summaryrefslogtreecommitdiffstats
path: root/bridges/source/jni_uno
diff options
context:
space:
mode:
Diffstat (limited to 'bridges/source/jni_uno')
-rw-r--r--bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java61
-rw-r--r--bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java225
-rw-r--r--bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest1
-rw-r--r--bridges/source/jni_uno/jni_base.h258
-rw-r--r--bridges/source/jni_uno/jni_bridge.cxx578
-rw-r--r--bridges/source/jni_uno/jni_bridge.h118
-rw-r--r--bridges/source/jni_uno/jni_data.cxx2476
-rw-r--r--bridges/source/jni_uno/jni_helper.h150
-rw-r--r--bridges/source/jni_uno/jni_info.cxx992
-rw-r--r--bridges/source/jni_uno/jni_info.h366
-rw-r--r--bridges/source/jni_uno/jni_java2uno.cxx624
-rw-r--r--bridges/source/jni_uno/jni_uno2java.cxx805
-rw-r--r--bridges/source/jni_uno/jniunoenvironmentdata.hxx54
-rw-r--r--bridges/source/jni_uno/nativethreadpool.cxx227
14 files changed, 6935 insertions, 0 deletions
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java
new file mode 100644
index 000000000..e129f1032
--- /dev/null
+++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java
@@ -0,0 +1,61 @@
+// -*- Mode: Java; 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package com.sun.star.bridges.jni_uno;
+
+import com.sun.star.lib.util.NativeLibraryLoader;
+
+public final class JNI_info_holder
+{
+ static {
+ if ("The Android Project".equals(System.getProperty("java.vendor"))) {
+ // See corresponding code in
+ // javaunohelper/com/sun/star/comp/helper/Bootstrap.java for more
+ // comments.
+
+ boolean disable_dynloading = false;
+ try {
+ System.loadLibrary("lo-bootstrap");
+ } catch (UnsatisfiedLinkError e) {
+ disable_dynloading = true;
+ }
+
+ if (!disable_dynloading)
+ NativeLibraryLoader.loadLibrary(JNI_info_holder.class.getClassLoader(),
+ "java_uno");
+ } else
+ NativeLibraryLoader.loadLibrary(JNI_info_holder.class.getClassLoader(),
+ "java_uno");
+ }
+
+ private static JNI_info_holder s_holder = new JNI_info_holder();
+
+ private static long s_jni_info_handle;
+
+ private native void finalize( long jni_info_handle );
+
+ @Override
+ protected void finalize() throws Throwable
+ {
+ finalize( s_jni_info_handle );
+ super.finalize();
+ }
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java
new file mode 100644
index 000000000..12817e57e
--- /dev/null
+++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java
@@ -0,0 +1,225 @@
+// -*- Mode: Java; 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package com.sun.star.bridges.jni_uno;
+
+import com.sun.star.lib.util.AsynchronousFinalizer;
+import com.sun.star.lib.util.NativeLibraryLoader;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.IEnvironment;
+import com.sun.star.uno.IQueryInterface;
+
+
+
+public final class JNI_proxy implements java.lang.reflect.InvocationHandler
+{
+ static {
+ if ("The Android Project".equals(System.getProperty("java.vendor"))) {
+ // See corresponding code in
+ // javaunohelper/com/sun/star/comp/helper/Bootstrap.java for more
+ // comments.
+
+ boolean disable_dynloading = false;
+ try {
+ System.loadLibrary("lo-bootstrap");
+ } catch (UnsatisfiedLinkError e) {
+ disable_dynloading = true;
+ }
+
+ if (!disable_dynloading)
+ NativeLibraryLoader.loadLibrary(JNI_info_holder.class.getClassLoader(),
+ "java_uno");
+ } else
+ NativeLibraryLoader.loadLibrary(JNI_proxy.class.getClassLoader(),
+ "java_uno");
+ }
+ private static ClassLoader s_classloader =
+ JNI_proxy.class.getClassLoader();
+ private static Class s_InvocationHandler [] =
+ new Class [] { java.lang.reflect.InvocationHandler.class };
+
+ private long m_bridge_handle;
+ private final IEnvironment m_java_env;
+ /** these 2 fields are accessed directly from C++ */
+ private long m_receiver_handle; // on the C++ side, this is a "UNO_Interface *"
+ private long m_td_handle; // on the C++ side, this is a "typelib_TypeDescription *"
+ private final Type m_type;
+ private final String m_oid;
+ private final Class m_class;
+ private final AsynchronousFinalizer m_finalizer;
+
+ public static String get_stack_trace( Throwable throwable )
+ throws Throwable
+ {
+ boolean current_trace = false;
+ if (null == throwable)
+ {
+ throwable = new Throwable();
+ current_trace = true;
+ }
+ java.io.StringWriter string_writer =
+ new java.io.StringWriter();
+ java.io.PrintWriter print_writer =
+ new java.io.PrintWriter( string_writer, true );
+ throwable.printStackTrace( print_writer );
+ print_writer.flush();
+ print_writer.close();
+ string_writer.flush();
+ String trace = string_writer.toString();
+ if (current_trace)
+ {
+ // cut out first two lines
+ int n = trace.indexOf( '\n' );
+ n = trace.indexOf( '\n', n +1 );
+ trace = trace.substring( n +1 );
+ }
+ return "\njava stack trace:\n" + trace;
+ }
+
+ private native void finalize( long bridge_handle );
+
+ @Override
+ protected void finalize()
+ {
+ if (m_finalizer != null) {
+ m_finalizer.add(new AsynchronousFinalizer.Job() {
+ public void run() throws Throwable {
+ JNI_proxy.this.finalize( m_bridge_handle );
+ }
+ });
+ }
+ }
+
+ private JNI_proxy(
+ long bridge_handle, IEnvironment java_env,
+ long receiver_handle, long td_handle, Type type, String oid,
+ AsynchronousFinalizer finalizer)
+ {
+ m_bridge_handle = bridge_handle;
+ m_java_env = java_env;
+ m_receiver_handle = receiver_handle;
+ m_td_handle = td_handle;
+ m_type = type;
+ m_oid = oid;
+ m_class = m_type.getZClass();
+ m_finalizer = finalizer;
+ }
+
+ public static Object create(
+ long bridge_handle, IEnvironment java_env,
+ long receiver_handle, long td_handle, Type type, String oid,
+ java.lang.reflect.Constructor proxy_ctor,
+ AsynchronousFinalizer finalizer)
+ throws Throwable
+ {
+ JNI_proxy handler = new JNI_proxy(
+ bridge_handle, java_env, receiver_handle, td_handle, type, oid,
+ finalizer);
+ Object proxy = proxy_ctor.newInstance( new Object [] { handler } );
+ return java_env.registerInterface( proxy, new String [] { oid }, type );
+ }
+
+ public static java.lang.reflect.Constructor get_proxy_ctor( Class clazz )
+ throws Throwable
+ {
+ Class proxy_class = java.lang.reflect.Proxy.getProxyClass(
+ s_classloader,
+ new Class [] { clazz, IQueryInterface.class,
+ com.sun.star.lib.uno.Proxy.class } );
+ return proxy_class.getConstructor( s_InvocationHandler );
+ }
+
+ private native Object dispatch_call(
+ long bridge_handle, String method, Object args [] )
+ throws Throwable;
+
+ // InvocationHandler impl
+
+ public Object invoke(
+ Object proxy, java.lang.reflect.Method method, Object args [] )
+ throws Throwable
+ {
+ Class<?> decl_class = method.getDeclaringClass();
+ String method_name = method.getName();
+
+ if (Object.class.equals( decl_class ))
+ {
+ if (method_name.equals( "hashCode" ))
+ {
+ // int hashCode()
+ return Integer.valueOf( m_oid.hashCode() );
+ }
+ else if (method_name.equals( "equals" ))
+ {
+ // boolean equals( Object obj )
+ return isSame(args[0]);
+ }
+ else if (method_name.equals( "toString" ))
+ {
+ // String toString()
+ return this.toString() + " [oid=" + m_oid +
+ ", type=" + m_type.getTypeName() + "]";
+ }
+ }
+ // UNO interface call
+ else if (decl_class.isAssignableFrom( m_class ))
+ {
+ // dispatch interface call
+ return dispatch_call( m_bridge_handle, method_name, args );
+ }
+ // IQueryInterface impl
+ else if (IQueryInterface.class.equals( decl_class ))
+ {
+ if (method_name.equals( "queryInterface" ))
+ {
+ Object registered_proxy =
+ m_java_env.getRegisteredInterface( m_oid, (Type)args[ 0 ] );
+ if (null == registered_proxy)
+ {
+ return dispatch_call( m_bridge_handle, method_name, args );
+ }
+ else
+ {
+ return registered_proxy;
+ }
+ }
+ else if (method_name.equals( "isSame" ))
+ {
+ // boolean isSame( Object object )
+ return isSame(args[0]);
+ }
+ else if (method_name.equals( "getOid" ))
+ {
+ return m_oid;
+ }
+ }
+
+ throw new com.sun.star.uno.RuntimeException(
+ "[jni_uno bridge error] unexpected call on proxy " +
+ proxy.toString() + ": " + method.toString() );
+ }
+
+ private Boolean isSame(Object obj) {
+ return Boolean.valueOf(obj != null
+ && m_oid.equals(UnoRuntime.generateOid(obj)));
+ }
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest
new file mode 100644
index 000000000..7ad02e156
--- /dev/null
+++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest
@@ -0,0 +1 @@
+Sealed: true
diff --git a/bridges/source/jni_uno/jni_base.h b/bridges/source/jni_uno/jni_base.h
new file mode 100644
index 000000000..0d02261ad
--- /dev/null
+++ b/bridges/source/jni_uno/jni_base.h
@@ -0,0 +1,258 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+
+#include <osl/diagnose.h>
+
+#include <rtl/alloc.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <utility>
+
+#include <uno/environment.h>
+#include <typelib/typedescription.h>
+
+
+namespace jni_uno
+{
+
+class JNI_info;
+
+struct BridgeRuntimeError
+{
+ OUString m_message;
+
+ explicit BridgeRuntimeError( OUString message )
+ : m_message(std::move( message ))
+ {}
+};
+
+
+class JNI_context
+{
+ JNI_info const * m_jni_info;
+ JNIEnv * m_env;
+ jobject m_class_loader;
+
+ JNI_context( JNI_context const & ) = delete;
+ JNI_context& operator = ( JNI_context const &) = delete;
+
+ void java_exc_occurred() const;
+public:
+ explicit JNI_context(
+ JNI_info const * jni_info, JNIEnv * env, jobject class_loader )
+ : m_jni_info( jni_info ),
+ m_env( env ),
+ m_class_loader( class_loader )
+ {}
+
+ JNI_info const * get_info() const
+ { return m_jni_info; }
+
+ JNIEnv * operator -> () const
+ { return m_env; }
+ JNIEnv * get_jni_env() const
+ { return m_env; }
+
+ // does not handle exceptions, *classClass will be null if exception
+ // occurred:
+ void getClassForName(jclass * classClass, jmethodID * methodForName) const;
+
+ // if inException, does not handle exceptions, in which case returned value
+ // will be null if exception occurred:
+ jclass findClass(
+ char const * name, jclass classClass, jmethodID methodForName,
+ bool inException) const;
+
+ inline void ensure_no_exception() const; // throws BridgeRuntimeError
+ inline bool assert_no_exception() const; // asserts and clears exception
+
+ OUString get_stack_trace( jobject jo_exc = nullptr ) const;
+};
+
+inline void JNI_context::ensure_no_exception() const
+{
+ if (m_env->ExceptionCheck())
+ {
+ java_exc_occurred();
+ }
+}
+
+inline bool JNI_context::assert_no_exception() const
+{
+ if (m_env->ExceptionCheck())
+ {
+ SAL_WARN("bridges", "unexpected java exception occurred");
+#if OSL_DEBUG_LEVEL > 0
+ m_env->ExceptionDescribe();
+#endif
+ m_env->ExceptionClear();
+ return false;
+ }
+ return true;
+}
+
+
+class JNI_guarded_context
+ : private ::jvmaccess::VirtualMachine::AttachGuard,
+ public JNI_context
+{
+ JNI_guarded_context( JNI_guarded_context const & ) = delete;
+ JNI_guarded_context& operator = ( JNI_guarded_context const &) = delete;
+
+public:
+ explicit JNI_guarded_context(
+ JNI_info const * jni_info,
+ rtl::Reference<jvmaccess::UnoVirtualMachine> const & vm_access)
+ : AttachGuard( vm_access->getVirtualMachine() ),
+ JNI_context(
+ jni_info, AttachGuard::getEnvironment(),
+ static_cast< jobject >(vm_access->getClassLoader()) )
+ {}
+};
+
+
+class JLocalAutoRef
+{
+ JNI_context const & m_jni;
+ jobject m_jo;
+
+public:
+ explicit JLocalAutoRef( JNI_context const & jni )
+ : m_jni( jni ),
+ m_jo( nullptr )
+ {}
+ explicit JLocalAutoRef( JNI_context const & jni, jobject jo )
+ : m_jni( jni ),
+ m_jo( jo )
+ {}
+ inline JLocalAutoRef( JLocalAutoRef & auto_ref );
+ inline ~JLocalAutoRef();
+
+ jobject get() const
+ { return m_jo; }
+ bool is() const
+ { return (nullptr != m_jo); }
+ inline jobject release();
+ inline void reset( jobject jo );
+ inline JLocalAutoRef & operator = ( JLocalAutoRef & auto_ref );
+};
+
+inline JLocalAutoRef::~JLocalAutoRef()
+{
+ if (nullptr != m_jo)
+ m_jni->DeleteLocalRef( m_jo );
+}
+
+inline JLocalAutoRef::JLocalAutoRef( JLocalAutoRef & auto_ref )
+ : m_jni( auto_ref.m_jni ),
+ m_jo( auto_ref.m_jo )
+{
+ auto_ref.m_jo = nullptr;
+}
+
+inline jobject JLocalAutoRef::release()
+{
+ jobject jo = m_jo;
+ m_jo = nullptr;
+ return jo;
+}
+
+inline void JLocalAutoRef::reset( jobject jo )
+{
+ if (jo != m_jo)
+ {
+ if (nullptr != m_jo)
+ m_jni->DeleteLocalRef( m_jo );
+ m_jo = jo;
+ }
+}
+
+inline JLocalAutoRef & JLocalAutoRef::operator = ( JLocalAutoRef & auto_ref )
+{
+ assert( m_jni.get_jni_env() == auto_ref.m_jni.get_jni_env() );
+ reset( auto_ref.m_jo );
+ auto_ref.m_jo = nullptr;
+ return *this;
+}
+
+
+
+struct rtl_mem
+{
+ static void * operator new ( size_t nSize )
+ { return std::malloc( nSize ); }
+ static void operator delete ( void * mem )
+ { std::free( mem ); }
+ static void * operator new ( size_t, void * mem )
+ { return mem; }
+ static void operator delete ( void *, void * )
+ {}
+
+ static inline rtl_mem * allocate( std::size_t bytes );
+};
+
+inline rtl_mem * rtl_mem::allocate( std::size_t bytes )
+{
+ void * p = std::malloc( bytes );
+ if (nullptr == p)
+ throw BridgeRuntimeError( "out of memory!" );
+ return static_cast<rtl_mem *>(p);
+}
+
+
+class TypeDescr
+{
+ typelib_TypeDescription * m_td;
+
+ TypeDescr( TypeDescr const & ) = delete;
+ TypeDescr& operator = ( TypeDescr const & ) = delete;
+
+public:
+ inline explicit TypeDescr( typelib_TypeDescriptionReference * td_ref );
+ ~TypeDescr()
+ { TYPELIB_DANGER_RELEASE( m_td ); }
+
+ typelib_TypeDescription * get() const
+ { return m_td; }
+};
+
+inline TypeDescr::TypeDescr( typelib_TypeDescriptionReference * td_ref )
+ : m_td( nullptr )
+{
+ TYPELIB_DANGER_GET( &m_td, td_ref );
+ if (nullptr == m_td)
+ {
+ throw BridgeRuntimeError(
+ "cannot get comprehensive type description for " +
+ OUString::unacquired( &td_ref->pTypeName ) );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_bridge.cxx b/bridges/source/jni_uno/jni_bridge.cxx
new file mode 100644
index 000000000..341c466aa
--- /dev/null
+++ b/bridges/source/jni_uno/jni_bridge.cxx
@@ -0,0 +1,578 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cassert>
+#include <memory>
+
+#include "jni_bridge.h"
+#include "jniunoenvironmentdata.hxx"
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.hxx>
+#include <uno/lbnames.h>
+
+using namespace ::osl;
+using namespace ::jni_uno;
+
+namespace
+{
+extern "C"
+{
+
+
+void Mapping_acquire( uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ Mapping const * that = static_cast< Mapping const * >( mapping );
+ that->m_bridge->acquire();
+}
+
+
+void Mapping_release( uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ Mapping const * that = static_cast< Mapping const * >( mapping );
+ that->m_bridge->release();
+}
+
+
+void Mapping_map_to_uno(
+ uno_Mapping * mapping, void ** ppOut,
+ void * pIn, typelib_InterfaceTypeDescription * td )
+ SAL_THROW_EXTERN_C()
+{
+ uno_Interface ** ppUnoI = reinterpret_cast<uno_Interface **>(ppOut);
+ jobject javaI = static_cast<jobject>(pIn);
+
+ static_assert(sizeof (void *) == sizeof (jobject), "must be the same size");
+ assert(ppUnoI != nullptr);
+ assert(td != nullptr);
+
+ if (javaI == nullptr)
+ {
+ if (*ppUnoI != nullptr)
+ {
+ uno_Interface * p = *ppUnoI;
+ (*p->release)( p );
+ *ppUnoI = nullptr;
+ }
+ }
+ else
+ {
+ try
+ {
+ Bridge const * bridge =
+ static_cast< Mapping const * >( mapping )->m_bridge;
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<jni_uno::JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ bridge->getJniInfo()->get_type_info(
+ jni, &td->aBase ) );
+ uno_Interface * pUnoI = bridge->map_to_uno( jni, javaI, info );
+ if (*ppUnoI != nullptr)
+ {
+ uno_Interface * p = *ppUnoI;
+ (*p->release)( p );
+ }
+ *ppUnoI = pUnoI;
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+ catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ }
+ }
+}
+
+
+void Mapping_map_to_java(
+ uno_Mapping * mapping, void ** ppOut,
+ void * pIn, typelib_InterfaceTypeDescription * td )
+ SAL_THROW_EXTERN_C()
+{
+ jobject * ppJavaI = reinterpret_cast<jobject *>(ppOut);
+ uno_Interface * pUnoI = static_cast<uno_Interface *>(pIn);
+
+ static_assert(sizeof (void *) == sizeof (jobject), "must be the same size");
+ assert(ppJavaI != nullptr);
+ assert(td != nullptr);
+
+ try
+ {
+ if (pUnoI == nullptr)
+ {
+ if (*ppJavaI != nullptr)
+ {
+ Bridge const * bridge =
+ static_cast< Mapping const * >( mapping )->m_bridge;
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<jni_uno::JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+ jni->DeleteGlobalRef( *ppJavaI );
+ *ppJavaI = nullptr;
+ }
+ }
+ else
+ {
+ Bridge const * bridge =
+ static_cast< Mapping const * >( mapping )->m_bridge;
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<jni_uno::JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ bridge->getJniInfo()->get_type_info(
+ jni, &td->aBase ) );
+ jobject jlocal = bridge->map_to_java( jni, pUnoI, info );
+ if (*ppJavaI != nullptr)
+ jni->DeleteGlobalRef( *ppJavaI );
+ *ppJavaI = jni->NewGlobalRef( jlocal );
+ jni->DeleteLocalRef( jlocal );
+ }
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+ catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ }
+}
+
+
+void Bridge_free( uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ Mapping * that = static_cast< Mapping * >( mapping );
+ delete that->m_bridge;
+}
+
+}
+
+}
+
+namespace jni_uno
+{
+
+
+void Bridge::acquire() const
+{
+ if (++m_ref != 1)
+ return;
+
+ if (m_registered_java2uno)
+ {
+ uno_Mapping * mapping = const_cast< Mapping * >( &m_java2uno );
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ m_java_env, &m_uno_env->aBase, nullptr );
+ }
+ else
+ {
+ uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2java );
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ &m_uno_env->aBase, m_java_env, nullptr );
+ }
+}
+
+
+void Bridge::release() const
+{
+ if (! --m_ref )
+ {
+ uno_revokeMapping(
+ m_registered_java2uno
+ ? const_cast< Mapping * >( &m_java2uno )
+ : const_cast< Mapping * >( &m_uno2java ) );
+ }
+}
+
+
+Bridge::Bridge(
+ uno_Environment * java_env, uno_ExtEnvironment * uno_env,
+ bool registered_java2uno )
+ : m_ref( 1 ),
+ m_uno_env( uno_env ),
+ m_java_env( java_env ),
+ m_registered_java2uno( registered_java2uno )
+{
+ assert(m_java_env != nullptr);
+ assert(m_uno_env != nullptr);
+
+ // uno_initEnvironment (below) cannot report errors directly, so it clears
+ // its pContext upon error to indirectly report errors from here:
+ if (static_cast<jni_uno::JniUnoEnvironmentData *>(m_java_env->pContext)
+ == nullptr)
+ {
+ throw BridgeRuntimeError("error during JNI-UNO's uno_initEnvironment");
+ }
+
+ (*m_uno_env->aBase.acquire)( &m_uno_env->aBase );
+ (*m_java_env->acquire)( m_java_env );
+
+ // java2uno
+ m_java2uno.acquire = Mapping_acquire;
+ m_java2uno.release = Mapping_release;
+ m_java2uno.mapInterface = Mapping_map_to_uno;
+ m_java2uno.m_bridge = this;
+ // uno2java
+ m_uno2java.acquire = Mapping_acquire;
+ m_uno2java.release = Mapping_release;
+ m_uno2java.mapInterface = Mapping_map_to_java;
+ m_uno2java.m_bridge = this;
+}
+
+
+Bridge::~Bridge()
+{
+ (*m_java_env->release)( m_java_env );
+ (*m_uno_env->aBase.release)( &m_uno_env->aBase );
+}
+
+JNI_info const * Bridge::getJniInfo() const {
+ return static_cast<jni_uno::JniUnoEnvironmentData *>(m_java_env->pContext)
+ ->info;
+}
+
+void JNI_context::java_exc_occurred() const
+{
+ // !don't rely on JNI_info!
+
+ JLocalAutoRef jo_exc( *this, m_env->ExceptionOccurred() );
+ m_env->ExceptionClear();
+ assert(jo_exc.is());
+ if (! jo_exc.is())
+ {
+ throw BridgeRuntimeError(
+ "java exception occurred, but not available!?" +
+ get_stack_trace() );
+ }
+
+ // call toString(); don't rely on m_jni_info
+ jclass jo_class = m_env->FindClass( "java/lang/Object" );
+ if (m_env->ExceptionCheck())
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "cannot get class java.lang.Object!" + get_stack_trace() );
+ }
+ JLocalAutoRef jo_Object( *this, jo_class );
+ // method Object.toString()
+ jmethodID method_Object_toString = m_env->GetMethodID(
+ static_cast<jclass>(jo_Object.get()), "toString", "()Ljava/lang/String;" );
+ if (m_env->ExceptionCheck())
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "cannot get method id of java.lang.Object.toString()!" +
+ get_stack_trace() );
+ }
+ assert(method_Object_toString != nullptr);
+
+ JLocalAutoRef jo_descr(
+ *this, m_env->CallObjectMethodA(
+ jo_exc.get(), method_Object_toString, nullptr ) );
+ if (m_env->ExceptionCheck()) // no chance at all
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "error examining java exception object!" +
+ get_stack_trace() );
+ }
+
+ jsize len = m_env->GetStringLength( static_cast<jstring>(jo_descr.get()) );
+ std::unique_ptr< rtl_mem > ustr_mem(
+ rtl_mem::allocate(
+ sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
+ rtl_uString * ustr = reinterpret_cast<rtl_uString *>(ustr_mem.get());
+ m_env->GetStringRegion( static_cast<jstring>(jo_descr.get()), 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
+ if (m_env->ExceptionCheck())
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "invalid java string object!" + get_stack_trace() );
+ }
+ ustr->refCount = 1;
+ ustr->length = len;
+ ustr->buffer[ len ] = '\0';
+ OUString message( reinterpret_cast<rtl_uString *>(ustr_mem.release()), SAL_NO_ACQUIRE );
+
+ throw BridgeRuntimeError( message + get_stack_trace( jo_exc.get() ) );
+}
+
+
+void JNI_context::getClassForName(
+ jclass * classClass, jmethodID * methodForName) const
+{
+ jclass c = m_env->FindClass("java/lang/Class");
+ if (c != nullptr) {
+ *methodForName = m_env->GetStaticMethodID(
+ c, "forName",
+ "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
+ }
+ *classClass = c;
+}
+
+
+jclass JNI_context::findClass(
+ char const * name, jclass classClass, jmethodID methodForName,
+ bool inException) const
+{
+ jclass c = nullptr;
+ JLocalAutoRef s(*this, m_env->NewStringUTF(name));
+ if (s.is()) {
+ jvalue a[3];
+ a[0].l = s.get();
+ a[1].z = JNI_FALSE;
+ a[2].l = m_class_loader;
+ c = static_cast< jclass >(
+ m_env->CallStaticObjectMethodA(classClass, methodForName, a));
+ }
+ if (!inException) {
+ ensure_no_exception();
+ }
+ return c;
+}
+
+
+OUString JNI_context::get_stack_trace( jobject jo_exc ) const
+{
+ JLocalAutoRef jo_JNI_proxy(
+ *this,
+ find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) );
+ if (assert_no_exception())
+ {
+ // static method JNI_proxy.get_stack_trace()
+ jmethodID method = m_env->GetStaticMethodID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "get_stack_trace",
+ "(Ljava/lang/Throwable;)Ljava/lang/String;" );
+ if (assert_no_exception() && (method != nullptr))
+ {
+ jvalue arg;
+ arg.l = jo_exc;
+ JLocalAutoRef jo_stack_trace(
+ *this, m_env->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_JNI_proxy.get()), method, &arg ) );
+ if (assert_no_exception())
+ {
+ jsize len =
+ m_env->GetStringLength( static_cast<jstring>(jo_stack_trace.get()) );
+ std::unique_ptr< rtl_mem > ustr_mem(
+ rtl_mem::allocate(
+ sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
+ rtl_uString * ustr = reinterpret_cast<rtl_uString *>(ustr_mem.get());
+ m_env->GetStringRegion(
+ static_cast<jstring>(jo_stack_trace.get()), 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
+ if (assert_no_exception())
+ {
+ ustr->refCount = 1;
+ ustr->length = len;
+ ustr->buffer[ len ] = '\0';
+ return OUString(
+ reinterpret_cast<rtl_uString *>(ustr_mem.release()), SAL_NO_ACQUIRE );
+ }
+ }
+ }
+ }
+ return OUString();
+}
+
+}
+
+using namespace ::jni_uno;
+
+extern "C" {
+
+static void java_env_dispose(uno_Environment * env) {
+ auto * envData
+ = static_cast<jni_uno::JniUnoEnvironmentData *>(env->pContext);
+ if (envData == nullptr) return;
+
+ jobject async;
+ {
+ osl::MutexGuard g(envData->mutex);
+ async = envData->asynchronousFinalizer;
+ envData->asynchronousFinalizer = nullptr;
+ }
+ if (async == nullptr) return;
+
+ try {
+ JNI_guarded_context jni(envData->info, envData->machine);
+ jni->CallObjectMethodA(
+ async, envData->info->m_method_AsynchronousFinalizer_drain,
+ nullptr);
+ jni.ensure_no_exception();
+ jni->DeleteGlobalRef(async);
+ } catch (const BridgeRuntimeError & e) {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << e.m_message << "\"");
+ } catch (
+ jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN(
+ "bridges",
+ ("ignoring jvmaccess::VirtualMachine::AttachGuard"
+ "::CreationException"));
+ }
+}
+
+static void java_env_disposing(uno_Environment * env) {
+ java_env_dispose(env);
+ delete static_cast<jni_uno::JniUnoEnvironmentData *>(env->pContext);
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_initEnvironment java_uno_initEnvironment
+#endif
+
+
+SAL_DLLPUBLIC_EXPORT void uno_initEnvironment( uno_Environment * java_env )
+ SAL_THROW_EXTERN_C()
+{
+ try {
+ // JavaComponentLoader::getJavaLoader (in
+ // stoc/source/javaloader/javaloader.cxx) stores a
+ // jvmaccess::UnoVirtualMachine pointer into java_env->pContext; replace
+ // it here with either a pointer to a full JniUnoEnvironmentData upon
+ // success, or with a null pointer upon failure (as this function cannot
+ // directly report back failure, so it uses that way to indirectly
+ // report failure later from within the Bridge ctor):
+ rtl::Reference<jvmaccess::UnoVirtualMachine> vm(
+ static_cast<jvmaccess::UnoVirtualMachine *>(java_env->pContext));
+ java_env->pContext = nullptr;
+ java_env->dispose = java_env_dispose;
+ java_env->environmentDisposing = java_env_disposing;
+ java_env->pExtEnv = nullptr; // no extended support
+ std::unique_ptr<jni_uno::JniUnoEnvironmentData> envData(
+ new jni_uno::JniUnoEnvironmentData(vm));
+ {
+ JNI_guarded_context jni(envData->info, envData->machine);
+ JLocalAutoRef ref(
+ jni,
+ jni->NewObject(
+ envData->info->m_class_AsynchronousFinalizer,
+ envData->info->m_ctor_AsynchronousFinalizer));
+ jni.ensure_no_exception();
+ envData->asynchronousFinalizer = jni->NewGlobalRef(ref.get());
+ jni.ensure_no_exception();
+ }
+ java_env->pContext = envData.release();
+ } catch (const BridgeRuntimeError & e) {
+ SAL_WARN("bridges", "BridgeRuntimeError \"" << e.m_message << "\"");
+ } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
+ SAL_WARN(
+ "bridges",
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException");
+ }
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_ext_getMapping java_uno_ext_getMapping
+#endif
+
+
+SAL_DLLPUBLIC_EXPORT void uno_ext_getMapping(
+ uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppMapping != nullptr);
+ assert(pFrom != nullptr);
+ assert(pTo != nullptr);
+ if (*ppMapping != nullptr)
+ {
+ (*(*ppMapping)->release)( *ppMapping );
+ *ppMapping = nullptr;
+ }
+
+ static_assert(int(JNI_FALSE) == int(false), "must be equal");
+ static_assert(int(JNI_TRUE) == int(true), "must be equal");
+ static_assert(sizeof (jboolean) == sizeof (sal_Bool), "must be the same size");
+ static_assert(sizeof (jchar) == sizeof (sal_Unicode), "must be the same size");
+ static_assert(sizeof (jdouble) == sizeof (double), "must be the same size");
+ static_assert(sizeof (jfloat) == sizeof (float), "must be the same size");
+ static_assert(sizeof (jbyte) == sizeof (sal_Int8), "must be the same size");
+ static_assert(sizeof (jshort) == sizeof (sal_Int16), "must be the same size");
+ static_assert(sizeof (jint) == sizeof (sal_Int32), "must be the same size");
+ static_assert(sizeof (jlong) == sizeof (sal_Int64), "must be the same size");
+
+ OUString const & from_env_typename =
+ OUString::unacquired( &pFrom->pTypeName );
+ OUString const & to_env_typename =
+ OUString::unacquired( &pTo->pTypeName );
+
+ uno_Mapping * mapping = nullptr;
+
+ try
+ {
+ if ( from_env_typename == UNO_LB_JAVA && to_env_typename == UNO_LB_UNO )
+ {
+ Bridge * bridge =
+ new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
+ mapping = &bridge->m_java2uno;
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ pFrom, &pTo->pExtEnv->aBase, nullptr );
+ // coverity[leaked_storage] - on purpose
+ }
+ else if ( from_env_typename == UNO_LB_UNO && to_env_typename == UNO_LB_JAVA )
+ {
+ Bridge * bridge =
+ new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
+ mapping = &bridge->m_uno2java;
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ &pFrom->pExtEnv->aBase, pTo, nullptr );
+ // coverity[leaked_storage] - on purpose
+ }
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN("bridges", "BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+
+ *ppMapping = mapping;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_bridge.h b/bridges/source/jni_uno/jni_bridge.h
new file mode 100644
index 000000000..ea55a1391
--- /dev/null
+++ b/bridges/source/jni_uno/jni_bridge.h
@@ -0,0 +1,118 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include "jni_base.h"
+#include "jni_helper.h"
+
+#include <osl/diagnose.h>
+
+#include <uno/mapping.h>
+#include <uno/dispatcher.h>
+
+#include <com/sun/star/uno/XInterface.hpp>
+
+
+namespace jni_uno
+{
+
+class JNI_info;
+struct Bridge;
+
+struct Mapping : public uno_Mapping
+{
+ Bridge * m_bridge;
+};
+
+// Holds environments and mappings:
+struct Bridge
+{
+ mutable std::atomic<std::size_t> m_ref;
+
+ uno_ExtEnvironment * m_uno_env;
+ uno_Environment * m_java_env;
+
+ Mapping m_java2uno;
+ Mapping m_uno2java;
+ bool m_registered_java2uno;
+
+ ~Bridge();
+ explicit Bridge(
+ uno_Environment * java_env, uno_ExtEnvironment * uno_env,
+ bool registered_java2uno );
+
+ void acquire() const;
+ void release() const;
+
+ // jni_data.cxx
+ void map_to_uno(
+ JNI_context const & jni,
+ void * uno_data, jvalue java_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool assign, bool out_param,
+ bool special_wrapped_integral_types = false ) const;
+ void map_to_java(
+ JNI_context const & jni,
+ jvalue * java_data, void const * uno_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool in_param, bool out_param,
+ bool special_wrapped_integral_types = false ) const;
+
+ // jni_uno2java.cxx
+ void handle_uno_exc(
+ JNI_context const & jni, uno_Any * uno_exc ) const;
+ void call_java(
+ jobject javaI,
+ typelib_InterfaceTypeDescription * iface_td,
+ sal_Int32 local_member_index, sal_Int32 function_pos_offset,
+ typelib_TypeDescriptionReference * return_type,
+ typelib_MethodParameter * params, sal_Int32 nParams,
+ void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const;
+ jobject map_to_java(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, JNI_interface_type_info const * info ) const;
+
+ // jni_java2uno.cxx
+ void handle_java_exc(
+ JNI_context const & jni,
+ JLocalAutoRef const & jo_exc, uno_Any * uno_exc ) const;
+ jobject call_uno(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, typelib_TypeDescription * member_td,
+ typelib_TypeDescriptionReference * return_tdref,
+ sal_Int32 nParams, typelib_MethodParameter const * pParams,
+ jobjectArray jo_args ) const;
+ uno_Interface * map_to_uno(
+ JNI_context const & jni,
+ jobject javaI, JNI_interface_type_info const * info ) const;
+
+ JNI_info const * getJniInfo() const;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_data.cxx b/bridges/source/jni_uno/jni_data.cxx
new file mode 100644
index 000000000..06e8467f7
--- /dev/null
+++ b/bridges/source/jni_uno/jni_data.cxx
@@ -0,0 +1,2476 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <memory>
+
+#include "jni_bridge.h"
+
+#include <rtl/strbuf.hxx>
+#include <uno/sequence2.h>
+
+namespace jni_uno
+{
+
+
+static std::unique_ptr<rtl_mem> seq_allocate(
+ sal_Int32 nElements, sal_Int32 nSize )
+{
+ std::unique_ptr< rtl_mem > seq(
+ rtl_mem::allocate( SAL_SEQUENCE_HEADER_SIZE + (nElements * nSize) ) );
+ uno_Sequence * p = reinterpret_cast<uno_Sequence *>(seq.get());
+ p->nRefCount = 1;
+ p->nElements = nElements;
+ return seq;
+}
+
+
+namespace {
+
+void createDefaultUnoValue(
+ JNI_context const & jni, void * uno_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */, bool assign)
+{
+ switch (type->eTypeClass) {
+ case typelib_TypeClass_BOOLEAN:
+ *static_cast< sal_Bool * >(uno_data) = false;
+ break;
+
+ case typelib_TypeClass_BYTE:
+ *static_cast< sal_Int8 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_SHORT:
+ *static_cast< sal_Int16 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast< sal_uInt16 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_LONG:
+ *static_cast< sal_Int32 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast< sal_uInt32 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_HYPER:
+ *static_cast< sal_Int64 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast< sal_uInt64 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_FLOAT:
+ *static_cast< float * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_DOUBLE:
+ *static_cast< double * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_CHAR:
+ *static_cast< sal_Unicode * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_STRING:
+ if (!assign) {
+ *static_cast< rtl_uString ** >(uno_data) = nullptr;
+ }
+ rtl_uString_new(static_cast< rtl_uString ** >(uno_data));
+ break;
+
+ case typelib_TypeClass_TYPE:
+ if (assign) {
+ typelib_typedescriptionreference_release(
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data));
+ }
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data)
+ = *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID);
+ assert(
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data) != nullptr);
+ typelib_typedescriptionreference_acquire(
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data));
+ break;
+
+ case typelib_TypeClass_ANY:
+ if (assign) {
+ uno_any_destruct(static_cast< uno_Any * >(uno_data), nullptr);
+ }
+ uno_any_construct(
+ static_cast< uno_Any * >(uno_data), nullptr,
+ jni.get_info()->m_XInterface_type_info->m_td.get(), nullptr);
+ break;
+
+ case typelib_TypeClass_SEQUENCE:
+ {
+ std::unique_ptr< rtl_mem > seq(seq_allocate(0, 0));
+ if (assign) {
+ uno_type_destructData(uno_data, type, nullptr);
+ }
+ *static_cast< uno_Sequence ** >(uno_data)
+ = reinterpret_cast< uno_Sequence * >(seq.release());
+ break;
+ }
+
+ case typelib_TypeClass_ENUM:
+ {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(&td, type);
+ *static_cast< sal_Int32 * >(uno_data)
+ = (reinterpret_cast< typelib_EnumTypeDescription * >(td)->
+ nDefaultEnumValue);
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+
+ case typelib_TypeClass_STRUCT:
+ {
+ if (info == nullptr) {
+ info = jni.get_info()->get_type_info(jni, type);
+ }
+ JNI_compound_type_info const * comp_info
+ = static_cast< JNI_compound_type_info const * >(info);
+ typelib_CompoundTypeDescription * comp_td
+ = reinterpret_cast< typelib_CompoundTypeDescription * >(
+ comp_info->m_td.get());
+ sal_Int32 nPos = 0;
+ sal_Int32 nMembers = comp_td->nMembers;
+ try {
+ if (comp_td->pBaseTypeDescription != nullptr) {
+ createDefaultUnoValue(
+ jni, uno_data,
+ comp_td->pBaseTypeDescription->aBase.pWeakRef,
+ comp_info->m_base, assign);
+ }
+ for (; nPos < nMembers; ++nPos) {
+ createDefaultUnoValue(
+ jni,
+ (static_cast< char * >(uno_data)
+ + comp_td->pMemberOffsets[nPos]),
+ comp_td->ppTypeRefs[nPos], nullptr, assign);
+ }
+ } catch (...) {
+ if (!assign) {
+ for (sal_Int32 i = 0; i < nPos; ++i) {
+ uno_type_destructData(
+ (static_cast< char * >(uno_data)
+ + comp_td->pMemberOffsets[i]),
+ comp_td->ppTypeRefs[i], nullptr);
+ }
+ if (comp_td->pBaseTypeDescription != nullptr) {
+ uno_destructData(
+ uno_data, &comp_td->pBaseTypeDescription->aBase, nullptr);
+ }
+ }
+ throw;
+ }
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE:
+ if (assign) {
+ uno_Interface * p = *static_cast< uno_Interface ** >(uno_data);
+ if (p != nullptr) {
+ (*p->release)(p);
+ }
+ }
+ *static_cast< uno_Interface ** >(uno_data) = nullptr;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+}
+
+void Bridge::map_to_uno(
+ JNI_context const & jni,
+ void * uno_data, jvalue java_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool assign, bool out_param,
+ bool special_wrapped_integral_types ) const
+{
+ assert(
+ !out_param ||
+ (jni->GetArrayLength( static_cast<jarray>(java_data.l) ) == 1) );
+
+ switch (type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (out_param)
+ {
+ jni->GetCharArrayRegion(
+ static_cast<jcharArray>(java_data.l), 0, 1, static_cast<jchar *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jchar *>(uno_data) = jni->CallCharMethodA(
+ java_data.l, getJniInfo()->m_method_Character_charValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jchar *>(uno_data) = java_data.c;
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (out_param)
+ {
+ jni->GetBooleanArrayRegion(
+ static_cast<jbooleanArray>(java_data.l), 0, 1, static_cast<jboolean *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jboolean *>(uno_data) = jni->CallBooleanMethodA(
+ java_data.l, getJniInfo()->m_method_Boolean_booleanValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jboolean *>(uno_data) = java_data.z;
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (out_param)
+ {
+ jni->GetByteArrayRegion(
+ static_cast<jbyteArray>(java_data.l), 0, 1, static_cast<jbyte *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jbyte *>(uno_data) = jni->CallByteMethodA(
+ java_data.l, getJniInfo()->m_method_Byte_byteValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jbyte *>(uno_data) = java_data.b;
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (out_param)
+ {
+ jni->GetShortArrayRegion(
+ static_cast<jshortArray>(java_data.l), 0, 1, static_cast<jshort *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jshort *>(uno_data) = jni->CallShortMethodA(
+ java_data.l, getJniInfo()->m_method_Short_shortValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jshort *>(uno_data) = java_data.s;
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (out_param)
+ {
+ jni->GetIntArrayRegion(
+ static_cast<jintArray>(java_data.l), 0, 1, static_cast<jint *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jint *>(uno_data) = jni->CallIntMethodA(
+ java_data.l, getJniInfo()->m_method_Integer_intValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jint *>(uno_data) = java_data.i;
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (out_param)
+ {
+ jni->GetLongArrayRegion(
+ static_cast<jlongArray>(java_data.l), 0, 1, static_cast<jlong *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jlong *>(uno_data) = jni->CallLongMethodA(
+ java_data.l, getJniInfo()->m_method_Long_longValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jlong *>(uno_data) = java_data.j;
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (out_param)
+ {
+ jni->GetFloatArrayRegion(
+ static_cast<jfloatArray>(java_data.l), 0, 1, static_cast<jfloat *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jfloat *>(uno_data) = jni->CallFloatMethodA(
+ java_data.l, getJniInfo()->m_method_Float_floatValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jfloat *>(uno_data) = java_data.f;
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (out_param)
+ {
+ jni->GetDoubleArrayRegion(
+ static_cast<jdoubleArray>(java_data.l), 0, 1, static_cast<jdouble *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jdouble *>(uno_data) = jni->CallDoubleMethodA(
+ java_data.l, getJniInfo()->m_method_Double_doubleValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jdouble *>(uno_data) = java_data.d;
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+ if (! assign)
+ *static_cast<rtl_uString **>(uno_data) = nullptr;
+ jstring_to_ustring(
+ jni, static_cast<rtl_uString **>(uno_data), static_cast<jstring>(java_data.l) );
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ // type name
+ JLocalAutoRef jo_type_name(
+ jni, jni->GetObjectField(
+ java_data.l, getJniInfo()->m_field_Type_typeName ) );
+ if (! jo_type_name.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] incomplete type object: no type name!"
+ + jni.get_stack_trace() );
+ }
+ OUString type_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
+ ::com::sun::star::uno::TypeDescription td( type_name );
+ if (! td.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] UNO type not found: " + type_name
+ + jni.get_stack_trace() );
+ }
+ typelib_typedescriptionreference_acquire( td.get()->pWeakRef );
+ if (assign)
+ {
+ typelib_typedescriptionreference_release(
+ *static_cast<typelib_TypeDescriptionReference **>(uno_data) );
+ }
+ *static_cast<typelib_TypeDescriptionReference **>(uno_data) = td.get()->pWeakRef;
+ break;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+
+ uno_Any * pAny = static_cast<uno_Any *>(uno_data);
+ if (java_data.l == nullptr) // null-ref maps to XInterface null-ref
+ {
+ if (assign)
+ uno_any_destruct( pAny, nullptr );
+ uno_any_construct(
+ pAny, nullptr, getJniInfo()->m_XInterface_type_info->m_td.get(), nullptr );
+ break;
+ }
+
+ JLocalAutoRef jo_type( jni );
+ JLocalAutoRef jo_wrapped_holder( jni );
+
+ if (jni->IsInstanceOf( java_data.l, getJniInfo()->m_class_Any ))
+ {
+ // boxed any
+ jo_type.reset( jni->GetObjectField(
+ java_data.l, getJniInfo()->m_field_Any_type ) );
+ if (! jo_type.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] no type set at com.sun.star.uno.Any!"
+ + jni.get_stack_trace() );
+ }
+ // wrapped value
+ jo_wrapped_holder.reset(
+ jni->GetObjectField(
+ java_data.l, getJniInfo()->m_field_Any_object ) );
+ java_data.l = jo_wrapped_holder.get();
+ }
+ else
+ {
+ // create type out of class
+ JLocalAutoRef jo_class( jni, jni->GetObjectClass( java_data.l ) );
+ jo_type.reset( create_type( jni, static_cast<jclass>(jo_class.get()) ) );
+ }
+
+ // get type name
+ JLocalAutoRef jo_type_name(
+ jni, jni->GetObjectField(
+ jo_type.get(), getJniInfo()->m_field_Type_typeName ) );
+ jni.ensure_no_exception();
+ OUString type_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
+
+ ::com::sun::star::uno::TypeDescription value_td( type_name );
+ if (! value_td.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] UNO type not found: " + type_name
+ + jni.get_stack_trace() );
+ }
+ typelib_TypeClass type_class = value_td.get()->eTypeClass;
+
+ if (assign)
+ {
+ uno_any_destruct( pAny, nullptr );
+ }
+ try
+ {
+ switch (type_class)
+ {
+ case typelib_TypeClass_VOID:
+ pAny->pData = &pAny->pReserved;
+ break;
+ case typelib_TypeClass_CHAR:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jchar *>(pAny->pData) = jni->CallCharMethodA(
+ java_data.l, getJniInfo()->m_method_Character_charValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jboolean *>(pAny->pData) = jni->CallBooleanMethodA(
+ java_data.l, getJniInfo()->m_method_Boolean_booleanValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BYTE:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jbyte *>(pAny->pData) = jni->CallByteMethodA(
+ java_data.l, getJniInfo()->m_method_Byte_byteValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jshort *>(pAny->pData) = jni->CallShortMethodA(
+ java_data.l, getJniInfo()->m_method_Short_shortValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jint *>(pAny->pData) = jni->CallIntMethodA(
+ java_data.l, getJniInfo()->m_method_Integer_intValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (sizeof (sal_Int64) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jlong *>(pAny->pData) = jni->CallLongMethodA(
+ java_data.l, getJniInfo()->m_method_Long_longValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( sizeof (sal_Int64) ) );
+ *reinterpret_cast<jlong *>(mem.get()) = jni->CallLongMethodA(
+ java_data.l, getJniInfo()->m_method_Long_longValue, nullptr );
+ jni.ensure_no_exception();
+ pAny->pData = mem.release();
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (sizeof (float) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jfloat *>(pAny->pData) = jni->CallFloatMethodA(
+ java_data.l, getJniInfo()->m_method_Float_floatValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( sizeof (float) ) );
+ *reinterpret_cast<jfloat *>(mem.get()) = jni->CallFloatMethodA(
+ java_data.l, getJniInfo()->m_method_Float_floatValue, nullptr );
+ jni.ensure_no_exception();
+ pAny->pData = mem.release();
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (sizeof (double) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jdouble *>(pAny->pData) =
+ jni->CallDoubleMethodA(
+ java_data.l,
+ getJniInfo()->m_method_Double_doubleValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( sizeof (double) ) );
+ *reinterpret_cast<jdouble *>(mem.get()) =
+ jni->CallDoubleMethodA(
+ java_data.l,
+ getJniInfo()->m_method_Double_doubleValue, nullptr );
+ jni.ensure_no_exception();
+ pAny->pData = mem.release();
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ // opt: anies often contain strings; copy string directly
+ pAny->pReserved = nullptr;
+ pAny->pData = &pAny->pReserved;
+ jstring_to_ustring(
+ jni, static_cast<rtl_uString **>(pAny->pData),
+ static_cast<jstring>(java_data.l) );
+ break;
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ pAny->pData = &pAny->pReserved;
+ map_to_uno(
+ jni, pAny->pData, java_data,
+ value_td.get()->pWeakRef, nullptr,
+ false /* no assign */, false /* no out param */ );
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( value_td.get()->nSize ) );
+ map_to_uno(
+ jni, mem.get(), java_data, value_td.get()->pWeakRef, nullptr,
+ false /* no assign */, false /* no out param */ );
+ pAny->pData = mem.release();
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + type_name
+ + "] unsupported value type of any!"
+ + jni.get_stack_trace() );
+ }
+ }
+ }
+ catch (...)
+ {
+ if (assign)
+ {
+ // restore to valid any
+ uno_any_construct( pAny, nullptr, nullptr, nullptr );
+ }
+ throw;
+ }
+ typelib_typedescriptionreference_acquire( value_td.get()->pWeakRef );
+ pAny->pType = value_td.get()->pWeakRef;
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ *static_cast<jint *>(uno_data) = jni->GetIntField(
+ java_data.l, getJniInfo()->m_field_Enum_m_value );
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_compound_type_info const * comp_info =
+ static_cast< JNI_compound_type_info const * >( info );
+
+ typelib_CompoundTypeDescription * comp_td =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(comp_info->m_td.get());
+ bool polymorphic
+ = comp_td->aBase.eTypeClass == typelib_TypeClass_STRUCT
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ comp_td)->pParameterizedTypes != nullptr;
+
+ sal_Int32 nPos = 0;
+ sal_Int32 nMembers = comp_td->nMembers;
+ try
+ {
+ if (comp_td->pBaseTypeDescription != nullptr)
+ {
+ map_to_uno(
+ jni, uno_data, java_data,
+ comp_td->pBaseTypeDescription->aBase.pWeakRef,
+ comp_info->m_base,
+ assign, false /* no out param */ );
+ }
+
+ for ( ; nPos < nMembers; ++nPos )
+ {
+ void * p = static_cast<char *>(uno_data) + comp_td->pMemberOffsets[ nPos ];
+ typelib_TypeDescriptionReference * member_type =
+ comp_td->ppTypeRefs[ nPos ];
+ jfieldID field_id = comp_info->m_fields[ nPos ];
+ bool parameterizedType = polymorphic
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ comp_td)->pParameterizedTypes[nPos];
+ switch (member_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jchar *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jchar *>(p) = jni->GetCharField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jboolean *>(p) = false;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jboolean *>(p) = jni->GetBooleanField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jbyte *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jbyte *>(p) = jni->GetByteField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jshort *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jshort *>(p) = jni->GetShortField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jint *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jint *>(p) = jni->GetIntField( java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jlong *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jlong *>(p) = jni->GetLongField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jfloat *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jfloat *>(p) = jni->GetFloatField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jdouble *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jdouble *>(p) = jni->GetDoubleField(
+ java_data.l, field_id );
+ }
+ break;
+ default:
+ {
+ JLocalAutoRef jo_field( jni );
+ bool checkNull;
+ if (field_id == nullptr)
+ {
+ // special for Message: call Throwable.getMessage()
+ assert(
+ type_equals(
+ type,
+ getJniInfo()->m_Exception_type.getTypeLibType() )
+ || type_equals(
+ type,
+ getJniInfo()->m_RuntimeException_type.
+ getTypeLibType() ) );
+ assert( nPos == 0 ); // first member
+ // call getMessage()
+ jo_field.reset(
+ jni->CallObjectMethodA(
+ java_data.l,
+ getJniInfo()->m_method_Throwable_getMessage, nullptr )
+ );
+ jni.ensure_no_exception();
+ checkNull = true;
+ }
+ else
+ {
+ jo_field.reset(
+ jni->GetObjectField( java_data.l, field_id ) );
+ checkNull = parameterizedType;
+ }
+ if (checkNull && !jo_field.is()) {
+ createDefaultUnoValue(jni, p, member_type, nullptr, assign);
+ } else {
+ jvalue val;
+ val.l = jo_field.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr,
+ assign, false /* no out param */ );
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (...)
+ {
+ if (! assign)
+ {
+ // cleanup
+ for ( sal_Int32 nCleanup = 0; nCleanup < nPos; ++nCleanup )
+ {
+ void * p =
+ static_cast<char *>(uno_data) + comp_td->pMemberOffsets[ nCleanup ];
+ uno_type_destructData(
+ p, comp_td->ppTypeRefs[ nCleanup ], nullptr );
+ }
+ if (comp_td->pBaseTypeDescription != nullptr)
+ {
+ uno_destructData(
+ uno_data, &comp_td->pBaseTypeDescription->aBase, nullptr );
+ }
+ }
+ throw;
+ }
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ TypeDescr td( type );
+ typelib_TypeDescriptionReference * element_type =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(td.get())->pType;
+
+ std::unique_ptr< rtl_mem > seq;
+ sal_Int32 nElements = jni->GetArrayLength( static_cast<jarray>(java_data.l) );
+
+ switch (element_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ seq = seq_allocate( nElements, sizeof (sal_Unicode) );
+ jni->GetCharArrayRegion(
+ static_cast<jcharArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jchar *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ seq = seq_allocate( nElements, sizeof (sal_Bool) );
+ jni->GetBooleanArrayRegion(
+ static_cast<jbooleanArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jboolean *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BYTE:
+ seq = seq_allocate( nElements, sizeof (sal_Int8) );
+ jni->GetByteArrayRegion(
+ static_cast<jbyteArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jbyte *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ seq = seq_allocate( nElements, sizeof (sal_Int16) );
+ jni->GetShortArrayRegion(
+ static_cast<jshortArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jshort *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ seq = seq_allocate( nElements, sizeof (sal_Int32) );
+ jni->GetIntArrayRegion(
+ static_cast<jintArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jint *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ seq = seq_allocate( nElements, sizeof (sal_Int64) );
+ jni->GetLongArrayRegion(
+ static_cast<jlongArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jlong *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_FLOAT:
+ seq = seq_allocate( nElements, sizeof (float) );
+ jni->GetFloatArrayRegion(
+ static_cast<jfloatArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jfloat *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_DOUBLE:
+ seq = seq_allocate( nElements, sizeof (double) );
+ jni->GetDoubleArrayRegion(
+ static_cast<jdoubleArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jdouble *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ {
+ TypeDescr element_td( element_type );
+ seq = seq_allocate( nElements, element_td.get()->nSize );
+
+ JNI_type_info const * element_info;
+ if (element_type->eTypeClass == typelib_TypeClass_STRUCT ||
+ element_type->eTypeClass == typelib_TypeClass_EXCEPTION ||
+ element_type->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ element_info =
+ getJniInfo()->get_type_info( jni, element_td.get() );
+ }
+ else
+ {
+ element_info = nullptr;
+ }
+
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ try
+ {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectArrayElement(
+ static_cast<jobjectArray>(java_data.l), nPos ) );
+ jni.ensure_no_exception();
+ jvalue val;
+ val.l = jo.get();
+ void * p =
+ reinterpret_cast<uno_Sequence *>(seq.get())->elements +
+ (nPos * element_td.get()->nSize);
+ map_to_uno(
+ jni, p, val, element_td.get()->pWeakRef, element_info,
+ false /* no assign */, false /* no out param */ );
+ }
+ catch (...)
+ {
+ // cleanup
+ for ( sal_Int32 nCleanPos = 0;
+ nCleanPos < nPos; ++nCleanPos )
+ {
+ void * p =
+ reinterpret_cast<uno_Sequence *>(seq.get())->elements +
+ (nCleanPos * element_td.get()->nSize);
+ uno_destructData( p, element_td.get(), nullptr );
+ }
+ throw;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported sequence element type: "
+ + OUString::unacquired( &element_type->pTypeName )
+ + jni.get_stack_trace() );
+ }
+ }
+
+ if (assign)
+ uno_destructData( uno_data, td.get(), nullptr );
+ *static_cast<uno_Sequence **>(uno_data) = reinterpret_cast<uno_Sequence *>(seq.release());
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+
+ if (java_data.l == nullptr) // null-ref
+ {
+ if (assign)
+ {
+ uno_Interface * p = *static_cast<uno_Interface **>(uno_data);
+ if (p != nullptr)
+ (*p->release)( p );
+ }
+ *static_cast<uno_Interface **>(uno_data) = nullptr;
+ }
+ else
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >( info );
+ uno_Interface * pUnoI = map_to_uno( jni, java_data.l, iface_info );
+ if (assign)
+ {
+ uno_Interface * p = *static_cast<uno_Interface **>(uno_data);
+ if (p != nullptr)
+ (*p->release)( p );
+ }
+ *static_cast<uno_Interface **>(uno_data) = pUnoI;
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported type!" + jni.get_stack_trace() );
+ }
+ }
+}
+
+
+void Bridge::map_to_java(
+ JNI_context const & jni,
+ jvalue * java_data, void const * uno_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool in_param, bool out_param,
+ bool special_wrapped_integral_types ) const
+{
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to pointer
+ // to const between <http://docs.oracle.com/javase/6/docs/technotes/guides/
+ // jni/spec/functions.html#wp22933> and <http://docs.oracle.com/javase/7/
+ // docs/technotes/guides/jni/spec/functions.html#wp22933>; work around that
+ // difference in a way that doesn't trigger loplugin:redundantcast:
+ void * data = const_cast<void *>(uno_data);
+
+ switch (type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewCharArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetCharArrayRegion(
+ static_cast<jcharArray>(jo_ar.get()), 0, 1, static_cast<jchar *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetCharArrayRegion(
+ static_cast<jcharArray>(java_data->l), 0, 1, static_cast<jchar *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.c = *static_cast<jchar const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Character,
+ getJniInfo()->m_ctor_Character_with_char, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->c = *static_cast<jchar const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewBooleanArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetBooleanArrayRegion(
+ static_cast<jbooleanArray>(jo_ar.get()),
+ 0, 1, static_cast<jboolean *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetBooleanArrayRegion(
+ static_cast<jbooleanArray>(java_data->l),
+ 0, 1, static_cast<jboolean *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.z = *static_cast<jboolean const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Boolean,
+ getJniInfo()->m_ctor_Boolean_with_boolean, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->z = *static_cast<jboolean const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewByteArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetByteArrayRegion(
+ static_cast<jbyteArray>(jo_ar.get()), 0, 1, static_cast<jbyte *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetByteArrayRegion(
+ static_cast<jbyteArray>(java_data->l), 0, 1, static_cast<jbyte *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.b = *static_cast<jbyte const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Byte,
+ getJniInfo()->m_ctor_Byte_with_byte, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->b = *static_cast<jbyte const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewShortArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetShortArrayRegion(
+ static_cast<jshortArray>(jo_ar.get()), 0, 1, static_cast<jshort *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetShortArrayRegion(
+ static_cast<jshortArray>(java_data->l), 0, 1, static_cast<jshort *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.s = *static_cast<jshort const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Short,
+ getJniInfo()->m_ctor_Short_with_short, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->s = *static_cast<jshort const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewIntArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetIntArrayRegion(
+ static_cast<jintArray>(jo_ar.get()), 0, 1, static_cast<jint *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetIntArrayRegion(
+ static_cast<jintArray>(java_data->l), 0, 1, static_cast<jint *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.i = *static_cast<jint const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Integer,
+ getJniInfo()->m_ctor_Integer_with_int, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->i = *static_cast<jint const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewLongArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetLongArrayRegion(
+ static_cast<jlongArray>(jo_ar.get()), 0, 1, static_cast<jlong *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetLongArrayRegion(
+ static_cast<jlongArray>(java_data->l), 0, 1, static_cast<jlong *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.j = *static_cast<jlong const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Long,
+ getJniInfo()->m_ctor_Long_with_long, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->j = *static_cast<jlong const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewFloatArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetFloatArrayRegion(
+ static_cast<jfloatArray>(jo_ar.get()), 0, 1, static_cast<jfloat *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetFloatArrayRegion(
+ static_cast<jfloatArray>(java_data->l), 0, 1, static_cast<jfloat *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.f = *static_cast<jfloat const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Float,
+ getJniInfo()->m_ctor_Float_with_float, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->f = *static_cast<jfloat const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewDoubleArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetDoubleArrayRegion(
+ static_cast<jdoubleArray>(jo_ar.get()),
+ 0, 1, static_cast<jdouble *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetDoubleArrayRegion(
+ static_cast<jdoubleArray>(java_data->l),
+ 0, 1, static_cast<jdouble *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.d = *static_cast<double const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Double,
+ getJniInfo()->m_ctor_Double_with_double, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->d = *static_cast<jdouble const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ {
+ if (out_param)
+ {
+ JLocalAutoRef jo_in( jni );
+ if (in_param)
+ {
+ jo_in.reset(
+ ustring_to_jstring(
+ jni, *static_cast<rtl_uString * const *>(uno_data) ) );
+ }
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, getJniInfo()->m_class_String, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ assert( in_param );
+ java_data->l =
+ ustring_to_jstring( jni, *static_cast<rtl_uString * const *>(uno_data) );
+ }
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ if (out_param)
+ {
+ JLocalAutoRef jo_in( jni );
+ if (in_param)
+ {
+ jo_in.reset(
+ create_type(
+ jni,
+ *static_cast<typelib_TypeDescriptionReference * const *>(uno_data) )
+ );
+ }
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, getJniInfo()->m_class_Type, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ assert( in_param );
+ java_data->l =
+ create_type(
+ jni,
+ *static_cast<typelib_TypeDescriptionReference * const *>(uno_data) );
+ }
+ break;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ JLocalAutoRef jo_any( jni );
+ if (in_param)
+ {
+ uno_Any const * pAny = static_cast<uno_Any const *>(uno_data);
+ switch (pAny->pType->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ jo_any.reset(
+ jni->NewLocalRef( getJniInfo()->m_object_Any_VOID ) );
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ {
+ jvalue args[ 2 ];
+ args[ 0 ].s = *static_cast<jshort const *>(pAny->pData);
+ JLocalAutoRef jo_val(
+ jni, jni->NewObjectA(
+ getJniInfo()->m_class_Short,
+ getJniInfo()->m_ctor_Short_with_short, args ) );
+ jni.ensure_no_exception();
+ // box up in com.sun.star.uno.Any
+ args[ 0 ].l = getJniInfo()->m_object_Type_UNSIGNED_SHORT;
+ args[ 1 ].l = jo_val.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_LONG:
+ {
+ jvalue args[ 2 ];
+ args[ 0 ].i = *static_cast<jint const *>(pAny->pData);
+ JLocalAutoRef jo_val(
+ jni, jni->NewObjectA(
+ getJniInfo()->m_class_Integer,
+ getJniInfo()->m_ctor_Integer_with_int, args ) );
+ jni.ensure_no_exception();
+ // box up in com.sun.star.uno.Any
+ args[ 0 ].l = getJniInfo()->m_object_Type_UNSIGNED_LONG;
+ args[ 1 ].l = jo_val.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ {
+ jvalue args[ 2 ];
+ args[ 0 ].j = *static_cast<jlong const *>(pAny->pData);
+ JLocalAutoRef jo_val(
+ jni, jni->NewObjectA(
+ getJniInfo()->m_class_Long,
+ getJniInfo()->m_ctor_Long_with_long, args ) );
+ jni.ensure_no_exception();
+ // box up in com.sun.star.uno.Any
+ args[ 0 ].l = getJniInfo()->m_object_Type_UNSIGNED_HYPER;
+ args[ 1 ].l = jo_val.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ case typelib_TypeClass_STRING: // opt strings
+ jo_any.reset( ustring_to_jstring(
+ jni, static_cast<rtl_uString *>(pAny->pReserved) ) );
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ {
+ jvalue java_data2;
+ // prefetch sequence td
+ TypeDescr seq_td( pAny->pType );
+ map_to_java(
+ jni, &java_data2, pAny->pData, seq_td.get()->pWeakRef, nullptr,
+ true /* in */, false /* no out */,
+ true /* create integral wrappers */ );
+ jo_any.reset( java_data2.l );
+
+ // determine inner element type
+ ::com::sun::star::uno::Type element_type(
+ reinterpret_cast<typelib_IndirectTypeDescription *>(seq_td.get())->pType );
+ while (element_type.getTypeLibType()->eTypeClass ==
+ typelib_TypeClass_SEQUENCE)
+ {
+ TypeDescr element_td( element_type.getTypeLibType() );
+ typelib_typedescriptionreference_assign(
+ reinterpret_cast< typelib_TypeDescriptionReference ** >(
+ &element_type ),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(element_td.get())
+ ->pType );
+ }
+ // box up only if unsigned element type
+ switch (element_type.getTypeLibType()->eTypeClass)
+ {
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ {
+ jvalue args[ 2 ];
+ JLocalAutoRef jo_type(
+ jni, create_type( jni, seq_td.get()->pWeakRef ) );
+ args[ 0 ].l = jo_type.get();
+ args[ 1 ].l = jo_any.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ uno_Interface * pUnoI = static_cast<uno_Interface *>(pAny->pReserved);
+ if (is_XInterface( pAny->pType ))
+ {
+ if (pUnoI != nullptr)
+ {
+ jo_any.reset(
+ map_to_java(
+ jni, pUnoI,
+ getJniInfo()->m_XInterface_type_info ) );
+ }
+ // else: empty XInterface ref maps to null-ref
+ }
+ else
+ {
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >(
+ getJniInfo()->get_type_info( jni, pAny->pType ) );
+ if (pUnoI != nullptr)
+ {
+ jo_any.reset( map_to_java( jni, pUnoI, iface_info ) );
+ }
+ // box up in com.sun.star.uno.Any
+ jvalue args[ 2 ];
+ args[ 0 ].l = iface_info->m_type;
+ args[ 1 ].l = jo_any.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ {
+ // Do not lose information about type arguments of instantiated
+ // polymorphic struct types:
+ OUString const & name = OUString::unacquired(
+ &pAny->pType->pTypeName);
+ assert(!name.isEmpty());
+ if (name[name.getLength() - 1] == '>')
+ {
+ // Box up in com.sun.star.uno.Any:
+ JLocalAutoRef jo_type(jni, create_type(jni, pAny->pType));
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, pAny->pData, pAny->pType, nullptr, true,
+ false);
+ jo_any.reset(java_data2.l);
+ jvalue args[2];
+ args[0].l = jo_type.get();
+ args[1].l = jo_any.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args));
+ jni.ensure_no_exception();
+ break;
+ }
+ [[fallthrough]];
+ }
+ default:
+ {
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, pAny->pData, pAny->pType, nullptr,
+ true /* in */, false /* no out */,
+ true /* create integral wrappers */ );
+ jo_any.reset( java_data2.l );
+ break;
+ }
+ }
+ }
+
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, getJniInfo()->m_class_Object, jo_any.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_any.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_any.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ {
+ OUString const & type_name = OUString::unacquired( &type->pTypeName );
+ OString class_name(
+ OUStringToOString( type_name, RTL_TEXTENCODING_JAVA_UTF8 ) );
+ JLocalAutoRef jo_enum_class(
+ jni, find_class( jni, class_name.getStr() ) );
+
+ JLocalAutoRef jo_enum( jni );
+ if (in_param)
+ {
+ // call static <enum_class>.fromInt( int )
+ OString sig = "(I)L" + class_name.replace( '.', '/' ) + ";";
+ jmethodID method_id = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_enum_class.get()), "fromInt", sig.getStr() );
+ jni.ensure_no_exception();
+ assert( method_id != nullptr );
+
+ jvalue arg;
+ arg.i = *static_cast<jint const *>(uno_data);
+ jo_enum.reset(
+ jni->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_enum_class.get()), method_id, &arg ) );
+ jni.ensure_no_exception();
+ }
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, static_cast<jclass>(jo_enum_class.get()), jo_enum.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_enum.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_enum.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_compound_type_info const * comp_info =
+ static_cast< JNI_compound_type_info const * >( info );
+
+ JLocalAutoRef jo_comp( jni );
+ if (in_param)
+ {
+ if (type->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ JLocalAutoRef jo_message(
+ jni, ustring_to_jstring( jni, *static_cast<rtl_uString * const *>(uno_data) ) );
+ jvalue arg;
+ arg.l = jo_message.get();
+ jo_comp.reset(
+ jni->NewObjectA(
+ comp_info->m_class, comp_info->m_exc_ctor, &arg ) );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jo_comp.reset( jni->AllocObject( comp_info->m_class ) );
+ jni.ensure_no_exception();
+ }
+
+ for ( JNI_compound_type_info const * linfo = comp_info;
+ linfo != nullptr;
+ linfo = static_cast< JNI_compound_type_info const * >(
+ linfo->m_base ) )
+ {
+ typelib_CompoundTypeDescription * comp_td =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(linfo->m_td.get());
+ typelib_TypeDescriptionReference ** ppMemberTypeRefs =
+ comp_td->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = comp_td->pMemberOffsets;
+ bool polymorphic
+ = comp_td->aBase.eTypeClass == typelib_TypeClass_STRUCT
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ comp_td)->pParameterizedTypes != nullptr;
+ for ( sal_Int32 nPos = comp_td->nMembers; nPos--; )
+ {
+ jfieldID field_id = linfo->m_fields[ nPos ];
+ if (field_id != nullptr)
+ {
+ void const * p =
+ static_cast<char const *>(uno_data) + pMemberOffsets[ nPos ];
+ typelib_TypeDescriptionReference * member_type =
+ ppMemberTypeRefs[ nPos ];
+ bool parameterizedType = polymorphic
+ && (reinterpret_cast<
+ typelib_StructTypeDescription * >(comp_td)->
+ pParameterizedTypes[nPos]);
+ switch (member_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.c = *static_cast<jchar const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Character,
+ getJniInfo()->m_ctor_Character_with_char,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetCharField(
+ jo_comp.get(),
+ field_id, *static_cast<jchar const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.z = *static_cast<jboolean const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Boolean,
+ getJniInfo()->m_ctor_Boolean_with_boolean,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetBooleanField(
+ jo_comp.get(),
+ field_id, *static_cast<jboolean const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.b = *static_cast<jbyte const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Byte,
+ getJniInfo()->m_ctor_Byte_with_byte,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetByteField(
+ jo_comp.get(),
+ field_id, *static_cast<jbyte const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.s = *static_cast<jshort const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Short,
+ getJniInfo()->m_ctor_Short_with_short,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetShortField(
+ jo_comp.get(),
+ field_id, *static_cast<jshort const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.i = *static_cast<jint const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Integer,
+ getJniInfo()->m_ctor_Integer_with_int,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetIntField(
+ jo_comp.get(),
+ field_id, *static_cast<jint const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.j = *static_cast<jlong const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Long,
+ getJniInfo()->m_ctor_Long_with_long,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetLongField(
+ jo_comp.get(),
+ field_id, *static_cast<jlong const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.f = *static_cast<jfloat const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Float,
+ getJniInfo()->m_ctor_Float_with_float,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetFloatField(
+ jo_comp.get(),
+ field_id, *static_cast<jfloat const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.d = *static_cast<jdouble const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Double,
+ getJniInfo()->m_ctor_Double_with_double,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetDoubleField(
+ jo_comp.get(),
+ field_id, *static_cast<jdouble const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_STRING: // string opt here
+ {
+ JLocalAutoRef jo_string(
+ jni, ustring_to_jstring(
+ jni, *static_cast<rtl_uString * const *>(p) ) );
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo_string.get() );
+ break;
+ }
+ default:
+ {
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, p, member_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_obj( jni, java_data2.l );
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo_obj.get() );
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ java_data->l =
+ jni->NewObjectArray( 1, comp_info->m_class, jo_comp.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_comp.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_comp.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ // xxx todo: possible opt for pure out sequences
+ JLocalAutoRef jo_ar( jni );
+
+ sal_Int32 nElements;
+ uno_Sequence * seq = nullptr;
+ if (in_param)
+ {
+ seq = *static_cast<uno_Sequence * const *>(uno_data);
+ nElements = seq->nElements;
+ }
+ else
+ {
+ nElements = 0;
+ }
+
+ TypeDescr td( type );
+ typelib_TypeDescriptionReference * element_type =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(td.get())->pType;
+
+ switch (element_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ jo_ar.reset( jni->NewCharArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetCharArrayRegion(
+ static_cast<jcharArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jchar *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ jo_ar.reset( jni->NewBooleanArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetBooleanArrayRegion(
+ static_cast<jbooleanArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jboolean *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ jo_ar.reset( jni->NewByteArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetByteArrayRegion(
+ static_cast<jbyteArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jbyte *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ jo_ar.reset( jni->NewShortArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetShortArrayRegion(
+ static_cast<jshortArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jshort *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ jo_ar.reset( jni->NewIntArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetIntArrayRegion(
+ static_cast<jintArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jint *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ jo_ar.reset( jni->NewLongArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetLongArrayRegion(
+ static_cast<jlongArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jlong *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ jo_ar.reset( jni->NewFloatArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetFloatArrayRegion(
+ static_cast<jfloatArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jfloat *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ jo_ar.reset( jni->NewDoubleArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetDoubleArrayRegion(
+ static_cast<jdoubleArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jdouble *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, getJniInfo()->m_class_String, nullptr ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ rtl_uString * const * pp =
+ reinterpret_cast<rtl_uString * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ JLocalAutoRef jo_string(
+ jni, ustring_to_jstring( jni, pp[ nPos ] ) );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_string.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ case typelib_TypeClass_TYPE:
+ jo_ar.reset(
+ jni->NewObjectArray( nElements, getJniInfo()->m_class_Type, nullptr ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ typelib_TypeDescriptionReference * const * pp =
+ reinterpret_cast<typelib_TypeDescriptionReference * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue val;
+ map_to_java(
+ jni, &val, &pp[ nPos ], element_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_element( jni, val.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ case typelib_TypeClass_ANY:
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, getJniInfo()->m_class_Object, nullptr ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ uno_Any const * p = reinterpret_cast<uno_Any const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue val;
+ map_to_java(
+ jni, &val, &p[ nPos ], element_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_element( jni, val.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ {
+ OUString const & element_type_name =
+ OUString::unacquired( &element_type->pTypeName );
+ OString class_name(
+ OUStringToOString(
+ element_type_name, RTL_TEXTENCODING_JAVA_UTF8 ) );
+ JLocalAutoRef jo_enum_class(
+ jni, find_class( jni, class_name.getStr() ) );
+
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, static_cast<jclass>(jo_enum_class.get()), nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ // call static <enum_class>.fromInt( int )
+ OString sig = "(I)L" + class_name.replace( '.', '/' ) + ";";
+ jmethodID method_id = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_enum_class.get()), "fromInt", sig.getStr() );
+ jni.ensure_no_exception();
+ assert( method_id != nullptr );
+
+ sal_Int32 const * p = reinterpret_cast<sal_Int32 const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue arg;
+ arg.i = p[ nPos ];
+ JLocalAutoRef jo_enum(
+ jni, jni->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_enum_class.get()), method_id, &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_enum.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ JNI_type_info const * element_info =
+ getJniInfo()->get_type_info( jni, element_type );
+
+ jo_ar.reset(
+ jni->NewObjectArray( nElements, element_info->m_class, nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ char * p = const_cast<char *>(seq->elements);
+ sal_Int32 nSize = element_info->m_td.get()->nSize;
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue val;
+ map_to_java(
+ jni, &val, p + (nSize * nPos),
+ element_type, element_info,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_element( jni, val.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ OStringBuffer buf( 64 );
+ JNI_info::append_sig(
+ &buf, element_type, false /* use class XInterface */,
+ false /* '.' instead of '/' */ );
+ OString class_name( buf.makeStringAndClear() );
+ JLocalAutoRef jo_seq_class(
+ jni, find_class( jni, class_name.getStr() ) );
+
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, static_cast<jclass>(jo_seq_class.get()), nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ uno_Sequence * const * elements = reinterpret_cast<uno_Sequence * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, elements + nPos, element_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_seq( jni, java_data2.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_seq.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >(
+ getJniInfo()->get_type_info( jni, element_type ) );
+
+ jo_ar.reset(
+ jni->NewObjectArray( nElements, iface_info->m_class, nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ uno_Interface * const * pp = reinterpret_cast<uno_Interface * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ uno_Interface * pUnoI = pp[ nPos ];
+ if (pUnoI != nullptr)
+ {
+ JLocalAutoRef jo_element(
+ jni, map_to_java( jni, pUnoI, iface_info ) );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()),
+ nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_java():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported element type: "
+ + OUString::unacquired( &element_type->pTypeName )
+ + jni.get_stack_trace() );
+ }
+ }
+
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_element_class(
+ jni, jni->GetObjectClass( jo_ar.get() ) );
+ if (in_param)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, static_cast<jclass>(jo_element_class.get()), jo_ar.get() );
+ }
+ else
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, static_cast<jclass>(jo_element_class.get()), nullptr );
+ }
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_ar.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_ar.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ JLocalAutoRef jo_iface( jni );
+ if (in_param)
+ {
+ uno_Interface * pUnoI = *static_cast<uno_Interface * const *>(uno_data);
+ if (pUnoI != nullptr)
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >( info );
+ jo_iface.reset( map_to_java( jni, pUnoI, iface_info ) );
+ }
+ }
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ java_data->l =
+ jni->NewObjectArray( 1, info->m_class, jo_iface.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_iface.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_iface.release();
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_java():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported type!" + jni.get_stack_trace() );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_helper.h b/bridges/source/jni_uno/jni_helper.h
new file mode 100644
index 000000000..4cc145b26
--- /dev/null
+++ b/bridges/source/jni_uno/jni_helper.h
@@ -0,0 +1,150 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include "jni_base.h"
+#include "jni_info.h"
+
+
+namespace jni_uno
+{
+
+inline void jstring_to_ustring(
+ JNI_context const & jni, rtl_uString ** out_ustr, jstring jstr )
+{
+ if (nullptr == jstr)
+ {
+ rtl_uString_new( out_ustr );
+ }
+ else
+ {
+ jsize len = jni->GetStringLength( jstr );
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate(
+ sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
+ rtl_uString * ustr = reinterpret_cast<rtl_uString *>(mem.get());
+ jni->GetStringRegion( jstr, 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
+ jni.ensure_no_exception();
+ ustr->refCount = 1;
+ ustr->length = len;
+ ustr->buffer[ len ] = '\0';
+ mem.release();
+ if (nullptr != *out_ustr)
+ rtl_uString_release( *out_ustr );
+ *out_ustr = ustr;
+ }
+}
+
+inline OUString jstring_to_oustring(
+ JNI_context const & jni, jstring jstr )
+{
+ rtl_uString * ustr = nullptr;
+ jstring_to_ustring( jni, &ustr, jstr );
+ return OUString( ustr, SAL_NO_ACQUIRE );
+}
+
+inline jstring ustring_to_jstring(
+ JNI_context const & jni, rtl_uString const * ustr )
+{
+ jstring jstr = jni->NewString( reinterpret_cast<jchar const *>(ustr->buffer), ustr->length );
+ jni.ensure_no_exception();
+ return jstr;
+}
+
+
+// if inException, does not handle exceptions, in which case returned value will
+// be null if exception occurred:
+inline jclass find_class(
+ JNI_context const & jni, char const * class_name, bool inException = false )
+{
+ // find_class may be called before the JNI_info is set:
+ jclass c=nullptr;
+ jmethodID m;
+ JNI_info const * info = jni.get_info();
+ if (info == nullptr) {
+ jni.getClassForName(&c, &m);
+ if (c == nullptr) {
+ if (inException) {
+ return nullptr;
+ }
+ jni.ensure_no_exception();
+ }
+ } else {
+ c = info->m_class_Class;
+ m = info->m_method_Class_forName;
+ }
+ return jni.findClass(class_name, c, m, inException);
+}
+
+
+inline jobject create_type( JNI_context const & jni, jclass clazz )
+{
+ JNI_info const * jni_info = jni.get_info();
+ jvalue arg;
+ arg.l = clazz;
+ jobject jo_type = jni->NewObjectA(
+ jni_info->m_class_Type, jni_info->m_ctor_Type_with_Class, &arg );
+ jni.ensure_no_exception();
+ return jo_type;
+}
+
+inline jobject create_type(
+ JNI_context const & jni, typelib_TypeDescriptionReference * type )
+{
+ JNI_info const * jni_info = jni.get_info();
+ jvalue args[ 2 ];
+ // get type class
+ args[ 0 ].i = type->eTypeClass;
+ JLocalAutoRef jo_type_class(
+ jni, jni->CallStaticObjectMethodA(
+ jni_info->m_class_TypeClass,
+ jni_info->m_method_TypeClass_fromInt, args ) );
+ jni.ensure_no_exception();
+ // construct type
+ JLocalAutoRef jo_type_name(
+ jni, ustring_to_jstring( jni, type->pTypeName ) );
+ args[ 0 ].l = jo_type_name.get();
+ args[ 1 ].l = jo_type_class.get();
+ jobject jo_type = jni->NewObjectA(
+ jni_info->m_class_Type,
+ jni_info->m_ctor_Type_with_Name_TypeClass, args );
+ jni.ensure_no_exception();
+ return jo_type;
+}
+
+inline jobject compute_oid( JNI_context const & jni, jobject jo )
+{
+ JNI_info const * jni_info = jni.get_info();
+ jvalue arg;
+ arg.l= jo;
+ jobject jo_oid = jni->CallStaticObjectMethodA(
+ jni_info->m_class_UnoRuntime,
+ jni_info->m_method_UnoRuntime_generateOid, &arg );
+ jni.ensure_no_exception();
+ return jo_oid;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_info.cxx b/bridges/source/jni_uno/jni_info.cxx
new file mode 100644
index 000000000..81ad9323d
--- /dev/null
+++ b/bridges/source/jni_uno/jni_info.cxx
@@ -0,0 +1,992 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include "jni_bridge.h"
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <rtl/string.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <uno/lbnames.h>
+
+
+using namespace ::std;
+using namespace ::osl;
+
+namespace jni_uno
+{
+
+
+JNI_type_info::JNI_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td )
+ : m_td( td ),
+ m_class( nullptr )
+{
+ m_td.makeComplete();
+ if (! m_td.get()->bComplete)
+ {
+ throw BridgeRuntimeError(
+ "cannot make type complete: "
+ + OUString::unacquired( &m_td.get()->pTypeName )
+ + jni.get_stack_trace() );
+ }
+}
+
+
+void JNI_interface_type_info::destroy( JNIEnv * jni_env )
+{
+ JNI_type_info::destruct( jni_env );
+ jni_env->DeleteGlobalRef( m_proxy_ctor );
+ jni_env->DeleteGlobalRef( m_type );
+ m_methods.reset();
+ delete this;
+}
+
+
+JNI_interface_type_info::JNI_interface_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td_ )
+ : JNI_type_info( jni, td_ )
+{
+ assert( m_td.get()->eTypeClass == typelib_TypeClass_INTERFACE );
+
+ OUString const & uno_name = OUString::unacquired( &m_td.get()->pTypeName );
+ JNI_info const * jni_info = jni.get_info();
+
+ JLocalAutoRef jo_class(
+ jni,
+ find_class(
+ jni,
+ ( OUStringToOString( uno_name, RTL_TEXTENCODING_JAVA_UTF8 ).
+ getStr() ) ) );
+ JLocalAutoRef jo_type( jni, create_type( jni, static_cast<jclass>(jo_class.get()) ) );
+
+ // get proxy ctor
+ jvalue arg;
+ arg.l = jo_class.get();
+ JLocalAutoRef jo_proxy_ctor(
+ jni, jni->CallStaticObjectMethodA(
+ jni_info->m_class_JNI_proxy,
+ jni_info->m_method_JNI_proxy_get_proxy_ctor, &arg ) );
+
+ if (is_XInterface( m_td.get()->pWeakRef ))
+ {
+ m_methods = nullptr; // no methods
+ }
+ else
+ {
+ // retrieve method ids for all direct members
+ try
+ {
+ typelib_InterfaceTypeDescription * td =
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ m_td.get() );
+ // coverity[ctor_dtor_leak] - on purpose
+ m_methods.reset(new jmethodID[ td->nMapFunctionIndexToMemberIndex ]);
+ sal_Int32 nMethodIndex = 0;
+ typelib_TypeDescriptionReference ** ppMembers = td->ppMembers;
+ sal_Int32 nMembers = td->nMembers;
+
+ for ( sal_Int32 nPos = 0; nPos < nMembers; ++nPos )
+ {
+ TypeDescr member_td( ppMembers[ nPos ] );
+
+ OStringBuffer sig_buf( 64 );
+
+ if (member_td.get()->eTypeClass ==
+ typelib_TypeClass_INTERFACE_METHOD) // method
+ {
+ typelib_InterfaceMethodTypeDescription * method_td =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member_td.get() );
+
+ sig_buf.append( '(' );
+ for ( sal_Int32 i = 0; i < method_td->nParams; ++i )
+ {
+ typelib_MethodParameter const & param =
+ method_td->pParams[ i ];
+ if (param.bOut)
+ sig_buf.append( '[' );
+ JNI_info::append_sig( &sig_buf, param.pTypeRef );
+ }
+ sig_buf.append( ')' );
+ JNI_info::append_sig( &sig_buf, method_td->pReturnTypeRef );
+
+ OString method_signature( sig_buf.makeStringAndClear() );
+ OString method_name(
+ OUStringToOString( OUString::unacquired(
+ &method_td->aBase.pMemberName ),
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+
+ m_methods[ nMethodIndex ] = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), method_name.getStr(),
+ method_signature.getStr() );
+ jni.ensure_no_exception();
+ assert( m_methods[ nMethodIndex ] != nullptr );
+ ++nMethodIndex;
+ }
+ else // attribute
+ {
+ assert(
+ member_td.get()->eTypeClass ==
+ typelib_TypeClass_INTERFACE_ATTRIBUTE );
+ typelib_InterfaceAttributeTypeDescription * attribute_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member_td.get() );
+
+ // type sig
+ JNI_info::append_sig(
+ &sig_buf, attribute_td->pAttributeTypeRef );
+ OString type_sig( sig_buf.makeStringAndClear() );
+ sig_buf.ensureCapacity( 64 );
+ // member name
+ OUString const & member_name =
+ OUString::unacquired(
+ &attribute_td->aBase.pMemberName );
+
+ // getter
+ sig_buf.append( "()" );
+ sig_buf.append( type_sig );
+ OString method_signature( sig_buf.makeStringAndClear() );
+ OUStringBuffer name_buf( 3 + member_name.getLength() );
+ name_buf.append( "get" );
+ name_buf.append( member_name );
+ OString method_name(
+ OUStringToOString(
+ name_buf.makeStringAndClear(),
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ m_methods[ nMethodIndex ] = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), method_name.getStr(),
+ method_signature.getStr() );
+ jni.ensure_no_exception();
+ assert( m_methods[ nMethodIndex ] != nullptr );
+ ++nMethodIndex;
+ if (! attribute_td->bReadOnly)
+ {
+ // setter
+ sig_buf.ensureCapacity( 64 );
+ sig_buf.append( '(' );
+ sig_buf.append( type_sig );
+ sig_buf.append( ")V" );
+ method_signature = sig_buf.makeStringAndClear();
+ name_buf.ensureCapacity( 3 + member_name.getLength() );
+ name_buf.append( "set" );
+ name_buf.append( member_name );
+ method_name = OUStringToOString(
+ name_buf.makeStringAndClear(),
+ RTL_TEXTENCODING_JAVA_UTF8 );
+ m_methods[ nMethodIndex ] = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), method_name.getStr(),
+ method_signature.getStr() );
+ jni.ensure_no_exception();
+ assert( m_methods[ nMethodIndex ] != nullptr );
+ ++nMethodIndex;
+ }
+ }
+ }
+ }
+ catch (...)
+ {
+ m_methods.reset();
+ throw;
+ }
+ }
+ m_class = static_cast<jclass>(jni->NewGlobalRef( jo_class.get() ));
+ m_type = jni->NewGlobalRef( jo_type.get() );
+ m_proxy_ctor = jni->NewGlobalRef( jo_proxy_ctor.get() );
+}
+
+
+void JNI_compound_type_info::destroy( JNIEnv * jni_env )
+{
+ JNI_type_info::destruct( jni_env );
+ m_fields.reset();
+ delete this;
+}
+
+
+JNI_compound_type_info::JNI_compound_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td_ )
+ : JNI_type_info( jni, td_ ),
+ m_exc_ctor( nullptr )
+{
+ assert( m_td.get()->eTypeClass == typelib_TypeClass_STRUCT ||
+ m_td.get()->eTypeClass == typelib_TypeClass_EXCEPTION );
+ typelib_CompoundTypeDescription * td =
+ reinterpret_cast< typelib_CompoundTypeDescription * >( m_td.get() );
+
+ OUString const & uno_name =
+ OUString::unacquired( &td->aBase.pTypeName );
+
+ // Erase type arguments of instantiated polymorphic struct types:
+ std::u16string_view nucleus;
+ sal_Int32 i = uno_name.indexOf( '<' );
+ if ( i < 0 ) {
+ nucleus = uno_name;
+ } else {
+ nucleus = uno_name.subView( 0, i );
+ }
+ JLocalAutoRef jo_class(
+ jni,
+ find_class(
+ jni,
+ OUStringToOString(
+ nucleus, RTL_TEXTENCODING_JAVA_UTF8 ).getStr() ) );
+
+ JNI_info const * jni_info = jni.get_info();
+
+ if (m_td.get()->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ // retrieve exc ctor( msg )
+ m_exc_ctor = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), "<init>", "(Ljava/lang/String;)V" );
+ jni.ensure_no_exception();
+ assert( m_exc_ctor != nullptr );
+ }
+
+ // retrieve info for base type
+ typelib_TypeDescription * base_td =
+ type_equals(
+ td->aBase.pWeakRef,
+ jni_info->m_RuntimeException_type.getTypeLibType())
+ ? nullptr
+ : reinterpret_cast< typelib_TypeDescription * >(
+ td->pBaseTypeDescription );
+ m_base = (base_td == nullptr ? nullptr : jni_info->get_type_info( jni, base_td ));
+
+ try
+ {
+ if (type_equals(
+ td->aBase.pWeakRef,
+ jni_info->m_Exception_type.getTypeLibType() ) ||
+ type_equals(
+ td->aBase.pWeakRef,
+ jni_info->m_RuntimeException_type.getTypeLibType() ))
+ {
+ // coverity[ctor_dtor_leak] - on purpose
+ m_fields.reset(new jfieldID[ 2 ]);
+ m_fields[ 0 ] = nullptr; // special Throwable.getMessage()
+ // field Context
+ m_fields[ 1 ] = jni->GetFieldID(
+ static_cast<jclass>(jo_class.get()), "Context", "Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_fields[ 1 ] != nullptr );
+ }
+ else
+ {
+ // retrieve field ids for all direct members
+ sal_Int32 nMembers = td->nMembers;
+ m_fields.reset(new jfieldID[ nMembers ]);
+
+ for ( sal_Int32 nPos = 0; nPos < nMembers; ++nPos )
+ {
+ OString sig;
+ if (td->aBase.eTypeClass == typelib_TypeClass_STRUCT
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ td)->pParameterizedTypes != nullptr
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ td)->pParameterizedTypes[nPos])
+ {
+ sig = OString( "Ljava/lang/Object;" );
+ } else {
+ OStringBuffer sig_buf( 32 );
+ JNI_info::append_sig( &sig_buf, td->ppTypeRefs[ nPos ] );
+ sig = sig_buf.makeStringAndClear();
+ }
+
+ OString member_name(
+ OUStringToOString(
+ OUString::unacquired( &td->ppMemberNames[ nPos ] ),
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+
+ m_fields[ nPos ] = jni->GetFieldID(
+ static_cast<jclass>(jo_class.get()), member_name.getStr(),
+ sig.getStr() );
+ jni.ensure_no_exception();
+ assert( m_fields[ nPos ] != nullptr );
+ }
+ }
+ }
+ catch (...)
+ {
+ m_fields.reset();
+ throw;
+ }
+
+ m_class = static_cast<jclass>(jni->NewGlobalRef( jo_class.get() ));
+}
+
+
+JNI_type_info const * JNI_info::create_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td ) const
+{
+ OUString const & uno_name = OUString::unacquired( &td->pTypeName );
+
+ JNI_type_info * new_info;
+ switch (td->eTypeClass)
+ {
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ new_info = new JNI_compound_type_info( jni, td );
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ new_info = new JNI_interface_type_info( jni, td );
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "type info not supported for " + uno_name + jni.get_stack_trace() );
+ }
+ }
+
+ // look up
+ JNI_type_info * info;
+ std::unique_lock guard( m_mutex );
+ JNI_type_info_holder & holder = m_type_map[ uno_name ];
+ if (holder.m_info == nullptr) // new insertion
+ {
+ holder.m_info = new_info;
+ guard.unlock();
+ info = new_info;
+ }
+ else // inserted in the meantime
+ {
+ info = holder.m_info;
+ guard.unlock();
+ new_info->destroy( jni.get_jni_env() );
+ }
+ return info;
+}
+
+
+JNI_type_info const * JNI_info::get_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td ) const
+{
+ if (is_XInterface( td->pWeakRef ))
+ {
+ return m_XInterface_type_info;
+ }
+
+ OUString const & uno_name = OUString::unacquired( &td->pTypeName );
+ JNI_type_info const * info;
+ std::unique_lock guard( m_mutex );
+
+ t_str2type::const_iterator iFind( m_type_map.find( uno_name ) );
+ if (iFind == m_type_map.end())
+ {
+ guard.unlock();
+ info = create_type_info( jni, td );
+ }
+ else
+ {
+ info = iFind->second.m_info;
+ }
+
+ return info;
+}
+
+
+JNI_type_info const * JNI_info::get_type_info(
+ JNI_context const & jni, typelib_TypeDescriptionReference * type ) const
+{
+ if (is_XInterface( type ))
+ {
+ return m_XInterface_type_info;
+ }
+
+ OUString const & uno_name = OUString::unacquired( &type->pTypeName );
+ JNI_type_info const * info;
+ std::unique_lock guard( m_mutex );
+ t_str2type::const_iterator iFind( m_type_map.find( uno_name ) );
+ if (iFind == m_type_map.end())
+ {
+ guard.unlock();
+ TypeDescr td( type );
+ info = create_type_info( jni, td.get() );
+ }
+ else
+ {
+ info = iFind->second.m_info;
+ }
+
+ return info;
+}
+
+
+JNI_type_info const * JNI_info::get_type_info(
+ JNI_context const & jni, OUString const & uno_name ) const
+{
+ if ( uno_name == "com.sun.star.uno.XInterface" )
+ {
+ return m_XInterface_type_info;
+ }
+
+ JNI_type_info const * info;
+ std::unique_lock guard( m_mutex );
+ t_str2type::const_iterator iFind( m_type_map.find( uno_name ) );
+ if (iFind == m_type_map.end())
+ {
+ guard.unlock();
+ css::uno::TypeDescription td( uno_name );
+ if (! td.is())
+ {
+ throw BridgeRuntimeError(
+ "UNO type not found: " + uno_name + jni.get_stack_trace() );
+ }
+ info = create_type_info( jni, td.get() );
+ }
+ else
+ {
+ info = iFind->second.m_info;
+ }
+
+ return info;
+}
+
+
+JNI_info::JNI_info(
+ JNIEnv * jni_env, jobject class_loader, jclass classClass,
+ jmethodID methodForName )
+ : m_class_Class( classClass ),
+ m_method_Class_forName( methodForName ),
+ m_class_JNI_proxy( nullptr ),
+ m_XInterface_queryInterface_td(
+ (reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ css::uno::TypeDescription(
+ cppu::UnoType<css::uno::XInterface>::get())
+ .get())->ppMembers[ 0 ] ) ),
+ m_Exception_type(cppu::UnoType<css::uno::Exception>::get()),
+ m_RuntimeException_type(cppu::UnoType<css::uno::RuntimeException>::get()),
+ m_void_type(cppu::UnoType<void>::get()),
+ m_XInterface_type_info( nullptr )
+{
+ JNI_context jni( this, jni_env, class_loader ); // !no proper jni_info!
+
+ // class lookup
+ JLocalAutoRef jo_Object(
+ jni, find_class( jni, "java.lang.Object" ) );
+ JLocalAutoRef jo_Class(
+ jni, find_class( jni, "java.lang.Class" ) );
+ JLocalAutoRef jo_Throwable(
+ jni, find_class( jni, "java.lang.Throwable" ) );
+ JLocalAutoRef jo_Character(
+ jni, find_class( jni, "java.lang.Character" ) );
+ JLocalAutoRef jo_Boolean(
+ jni, find_class( jni, "java.lang.Boolean" ) );
+ JLocalAutoRef jo_Byte(
+ jni, find_class( jni, "java.lang.Byte" ) );
+ JLocalAutoRef jo_Short(
+ jni, find_class( jni, "java.lang.Short" ) );
+ JLocalAutoRef jo_Integer(
+ jni, find_class( jni, "java.lang.Integer" ) );
+ JLocalAutoRef jo_Long(
+ jni, find_class( jni, "java.lang.Long" ) );
+ JLocalAutoRef jo_Float(
+ jni, find_class( jni, "java.lang.Float" ) );
+ JLocalAutoRef jo_Double(
+ jni, find_class( jni, "java.lang.Double" ) );
+ JLocalAutoRef jo_String(
+ jni, find_class( jni, "java.lang.String" ) );
+ JLocalAutoRef jo_RuntimeException(
+ jni, find_class( jni, "com.sun.star.uno.RuntimeException" ) );
+ JLocalAutoRef jo_UnoRuntime(
+ jni, find_class( jni, "com.sun.star.uno.UnoRuntime" ) );
+ JLocalAutoRef jo_Any(
+ jni, find_class( jni, "com.sun.star.uno.Any" ) );
+ JLocalAutoRef jo_Enum(
+ jni, find_class( jni, "com.sun.star.uno.Enum" ) );
+ JLocalAutoRef jo_Type(
+ jni, find_class( jni, "com.sun.star.uno.Type" ) );
+ JLocalAutoRef jo_TypeClass(
+ jni, find_class( jni, "com.sun.star.uno.TypeClass" ) );
+ JLocalAutoRef jo_IEnvironment(
+ jni, find_class( jni, "com.sun.star.uno.IEnvironment" ) );
+ JLocalAutoRef jo_JNI_proxy(
+ jni, find_class( jni, "com.sun.star.bridges.jni_uno.JNI_proxy" ) );
+ JLocalAutoRef jo_AsynchronousFinalizer(
+ jni, find_class( jni, "com.sun.star.lib.util.AsynchronousFinalizer" ) );
+
+ // method Object.toString()
+ m_method_Object_toString = jni->GetMethodID(
+ static_cast<jclass>(jo_Object.get()), "toString", "()Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_Object_toString != nullptr );
+ // method Class.getName()
+ m_method_Class_getName = jni->GetMethodID(
+ static_cast<jclass>(jo_Class.get()), "getName", "()Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_Class_getName != nullptr );
+
+ // method Throwable.getMessage()
+ m_method_Throwable_getMessage = jni->GetMethodID(
+ static_cast<jclass>(jo_Throwable.get()), "getMessage", "()Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_Throwable_getMessage != nullptr );
+
+ // method Character.charValue()
+ m_method_Character_charValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Character.get()), "charValue", "()C" );
+ jni.ensure_no_exception();
+ assert( m_method_Character_charValue != nullptr );
+ // method Boolean.booleanValue()
+ m_method_Boolean_booleanValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Boolean.get()), "booleanValue", "()Z" );
+ jni.ensure_no_exception();
+ assert( m_method_Boolean_booleanValue != nullptr );
+ // method Byte.byteValue()
+ m_method_Byte_byteValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Byte.get()), "byteValue", "()B" );
+ jni.ensure_no_exception();
+ assert( m_method_Byte_byteValue != nullptr );
+ // method Short.shortValue()
+ m_method_Short_shortValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Short.get()), "shortValue", "()S" );
+ jni.ensure_no_exception();
+ assert( m_method_Short_shortValue != nullptr );
+ // method Integer.intValue()
+ m_method_Integer_intValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Integer.get()), "intValue", "()I" );
+ jni.ensure_no_exception();
+ assert( m_method_Integer_intValue != nullptr );
+ // method Long.longValue()
+ m_method_Long_longValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Long.get()), "longValue", "()J" );
+ jni.ensure_no_exception();
+ assert( m_method_Long_longValue != nullptr );
+ // method Float.floatValue()
+ m_method_Float_floatValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Float.get()), "floatValue", "()F" );
+ jni.ensure_no_exception();
+ assert( m_method_Float_floatValue != nullptr );
+ // method Double.doubleValue()
+ m_method_Double_doubleValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Double.get()), "doubleValue", "()D" );
+ jni.ensure_no_exception();
+ assert( m_method_Double_doubleValue != nullptr );
+
+ // ctor Character( char )
+ m_ctor_Character_with_char = jni->GetMethodID(
+ static_cast<jclass>(jo_Character.get()), "<init>", "(C)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Character_with_char != nullptr );
+ // ctor Boolean( boolean )
+ m_ctor_Boolean_with_boolean = jni->GetMethodID(
+ static_cast<jclass>(jo_Boolean.get()), "<init>", "(Z)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Boolean_with_boolean != nullptr );
+ // ctor Byte( byte )
+ m_ctor_Byte_with_byte = jni->GetMethodID(
+ static_cast<jclass>(jo_Byte.get()), "<init>", "(B)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Byte_with_byte != nullptr );
+ // ctor Short( short )
+ m_ctor_Short_with_short = jni->GetMethodID(
+ static_cast<jclass>(jo_Short.get()), "<init>", "(S)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Short_with_short != nullptr );
+ // ctor Integer( int )
+ m_ctor_Integer_with_int = jni->GetMethodID(
+ static_cast<jclass>(jo_Integer.get()), "<init>", "(I)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Integer_with_int != nullptr );
+ // ctor Long( long )
+ m_ctor_Long_with_long = jni->GetMethodID(
+ static_cast<jclass>(jo_Long.get()), "<init>", "(J)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Long_with_long != nullptr );
+ // ctor Float( float )
+ m_ctor_Float_with_float = jni->GetMethodID(
+ static_cast<jclass>(jo_Float.get()), "<init>", "(F)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Float_with_float != nullptr );
+ // ctor Double( double )
+ m_ctor_Double_with_double = jni->GetMethodID(
+ static_cast<jclass>(jo_Double.get()), "<init>", "(D)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Double_with_double != nullptr );
+
+ // static method UnoRuntime.generateOid()
+ m_method_UnoRuntime_generateOid = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_UnoRuntime.get()),
+ "generateOid", "(Ljava/lang/Object;)Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_UnoRuntime_generateOid != nullptr );
+ // static method UnoRuntime.queryInterface()
+ m_method_UnoRuntime_queryInterface = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_UnoRuntime.get()),
+ "queryInterface",
+ "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_UnoRuntime_queryInterface != nullptr );
+
+ // field Enum.m_value
+ m_field_Enum_m_value = jni->GetFieldID(
+ static_cast<jclass>(jo_Enum.get()), "m_value", "I" );
+ jni.ensure_no_exception();
+ assert( m_field_Enum_m_value != nullptr );
+
+ // static method TypeClass.fromInt()
+ m_method_TypeClass_fromInt = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_TypeClass.get()),
+ "fromInt", "(I)Lcom/sun/star/uno/TypeClass;" );
+ jni.ensure_no_exception();
+ assert( m_method_TypeClass_fromInt != nullptr );
+
+ // ctor Type( Class )
+ m_ctor_Type_with_Class = jni->GetMethodID(
+ static_cast<jclass>(jo_Type.get()), "<init>", "(Ljava/lang/Class;)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Type_with_Class != nullptr );
+ // ctor Type( String, TypeClass )
+ m_ctor_Type_with_Name_TypeClass = jni->GetMethodID(
+ static_cast<jclass>(jo_Type.get()),
+ "<init>", "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Type_with_Name_TypeClass != nullptr );
+ // field Type._typeName
+ m_field_Type_typeName = jni->GetFieldID(
+ static_cast<jclass>(jo_Type.get()), "_typeName", "Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_field_Type_typeName != nullptr );
+
+ // ctor Any( Type, Object )
+ m_ctor_Any_with_Type_Object = jni->GetMethodID(
+ static_cast<jclass>(jo_Any.get()),
+ "<init>", "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Any_with_Type_Object != nullptr );
+
+ // field Any._type
+ m_field_Any_type = jni->GetFieldID(
+ static_cast<jclass>(jo_Any.get()), "_type", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( m_field_Any_type != nullptr );
+ // field Any._object
+ m_field_Any_object = jni->GetFieldID(
+ static_cast<jclass>(jo_Any.get()), "_object", "Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_field_Any_object != nullptr );
+
+ // method IEnvironment.getRegisteredInterface()
+ m_method_IEnvironment_getRegisteredInterface = jni->GetMethodID(
+ static_cast<jclass>(jo_IEnvironment.get()),
+ "getRegisteredInterface",
+ "(Ljava/lang/String;Lcom/sun/star/uno/Type;)Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_IEnvironment_getRegisteredInterface != nullptr );
+ // method IEnvironment.registerInterface()
+ m_method_IEnvironment_registerInterface = jni->GetMethodID(
+ static_cast<jclass>(jo_IEnvironment.get()), "registerInterface",
+ "(Ljava/lang/Object;[Ljava/lang/String;Lcom/sun/star/uno/Type;)"
+ "Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_IEnvironment_registerInterface != nullptr );
+
+ // static method JNI_proxy.get_proxy_ctor()
+ m_method_JNI_proxy_get_proxy_ctor = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "get_proxy_ctor",
+ "(Ljava/lang/Class;)Ljava/lang/reflect/Constructor;" );
+ jni.ensure_no_exception();
+ assert( m_method_JNI_proxy_get_proxy_ctor != nullptr );
+ // static method JNI_proxy.create()
+ m_method_JNI_proxy_create = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "create",
+ "(JLcom/sun/star/uno/IEnvironment;JJLcom/sun/star/uno/Type;Ljava/lang"
+ "/String;Ljava/lang/reflect/Constructor;"
+ "Lcom/sun/star/lib/util/AsynchronousFinalizer;)Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_JNI_proxy_create != nullptr );
+ // field JNI_proxy.m_receiver_handle
+ m_field_JNI_proxy_m_receiver_handle = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_receiver_handle", "J" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_receiver_handle != nullptr );
+ // field JNI_proxy.m_td_handle
+ m_field_JNI_proxy_m_td_handle = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_td_handle", "J" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_td_handle != nullptr );
+ // field JNI_proxy.m_type
+ m_field_JNI_proxy_m_type = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_type", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_type != nullptr );
+ // field JNI_proxy.m_oid
+ m_field_JNI_proxy_m_oid = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_oid", "Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_oid != nullptr );
+
+ // ctor AsynchronousFinalizer
+ m_ctor_AsynchronousFinalizer = jni->GetMethodID(
+ static_cast<jclass>(jo_AsynchronousFinalizer.get()), "<init>", "()V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_AsynchronousFinalizer != nullptr );
+ // method AsynchronousFinalizer.drain()
+ m_method_AsynchronousFinalizer_drain = jni->GetMethodID(
+ static_cast<jclass>(jo_AsynchronousFinalizer.get()), "drain", "()V" );
+ jni.ensure_no_exception();
+ assert( m_method_AsynchronousFinalizer_drain != nullptr );
+
+ // get java env
+ OUString java_env_type_name( UNO_LB_JAVA );
+ JLocalAutoRef jo_java(
+ jni, ustring_to_jstring( jni, java_env_type_name.pData ) );
+ jvalue args[ 2 ];
+ args[ 0 ].l = jo_java.get();
+ args[ 1 ].l = nullptr;
+ jmethodID method_getEnvironment = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_UnoRuntime.get()), "getEnvironment",
+ "(Ljava/lang/String;Ljava/lang/Object;)"
+ "Lcom/sun/star/uno/IEnvironment;" );
+ jni.ensure_no_exception();
+ assert( method_getEnvironment != nullptr );
+ JLocalAutoRef jo_java_env(
+ jni, jni->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_UnoRuntime.get()), method_getEnvironment, args ) );
+
+ // get com.sun.star.uno.Any.VOID
+ jfieldID field_Any_VOID = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Any.get()), "VOID", "Lcom/sun/star/uno/Any;" );
+ jni.ensure_no_exception();
+ assert( field_Any_VOID != nullptr );
+ JLocalAutoRef jo_Any_VOID(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Any.get()), field_Any_VOID ) );
+ // get com.sun.star.uno.Type.UNSIGNED_SHORT
+ jfieldID field_Type_UNSIGNED_SHORT = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Type.get()), "UNSIGNED_SHORT", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( field_Type_UNSIGNED_SHORT != nullptr );
+ JLocalAutoRef jo_Type_UNSIGNED_SHORT(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Type.get()), field_Type_UNSIGNED_SHORT ) );
+ // get com.sun.star.uno.Type.UNSIGNED_LONG
+ jfieldID field_Type_UNSIGNED_LONG = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Type.get()), "UNSIGNED_LONG", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( field_Type_UNSIGNED_LONG != nullptr );
+ JLocalAutoRef jo_Type_UNSIGNED_LONG(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Type.get()), field_Type_UNSIGNED_LONG ) );
+ // get com.sun.star.uno.Type.UNSIGNED_HYPER
+ jfieldID field_Type_UNSIGNED_HYPER = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Type.get()), "UNSIGNED_HYPER", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( field_Type_UNSIGNED_HYPER != nullptr );
+ JLocalAutoRef jo_Type_UNSIGNED_HYPER(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Type.get()), field_Type_UNSIGNED_HYPER ) );
+
+ // make global refs
+ m_class_UnoRuntime =
+ static_cast<jclass>(jni->NewGlobalRef( jo_UnoRuntime.get() ));
+ m_class_RuntimeException =
+ static_cast<jclass>(jni->NewGlobalRef( jo_RuntimeException.get() ));
+ m_class_Any =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Any.get() ));
+ m_class_Type =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Type.get() ));
+ m_class_TypeClass =
+ static_cast<jclass>(jni->NewGlobalRef( jo_TypeClass.get() ));
+ m_class_JNI_proxy =
+ static_cast<jclass>(jni->NewGlobalRef( jo_JNI_proxy.get() ));
+ m_class_AsynchronousFinalizer =
+ static_cast<jclass>(jni->NewGlobalRef( jo_AsynchronousFinalizer.get() ));
+
+ m_class_Character =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Character.get() ));
+ m_class_Boolean =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Boolean.get() ));
+ m_class_Byte =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Byte.get() ));
+ m_class_Short =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Short.get() ));
+ m_class_Integer =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Integer.get() ));
+ m_class_Long =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Long.get() ));
+ m_class_Float =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Float.get() ));
+ m_class_Double =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Double.get() ));
+ m_class_String =
+ static_cast<jclass>(jni->NewGlobalRef( jo_String.get() ));
+ m_class_Object =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Object.get() ));
+ m_class_Class =
+ static_cast<jclass>(jni->NewGlobalRef( m_class_Class ));
+
+ m_object_Any_VOID =
+ jni->NewGlobalRef( jo_Any_VOID.get() );
+ m_object_Type_UNSIGNED_SHORT =
+ jni->NewGlobalRef( jo_Type_UNSIGNED_SHORT.get() );
+ m_object_Type_UNSIGNED_LONG =
+ jni->NewGlobalRef( jo_Type_UNSIGNED_LONG.get() );
+ m_object_Type_UNSIGNED_HYPER =
+ jni->NewGlobalRef( jo_Type_UNSIGNED_HYPER.get() );
+ m_object_java_env = jni->NewGlobalRef( jo_java_env.get() );
+
+ try
+ {
+ css::uno::TypeDescription XInterface_td(
+ cppu::UnoType<css::uno::XInterface>::get());
+ // coverity[ctor_dtor_leak] - on purpose
+ m_XInterface_type_info =
+ new JNI_interface_type_info( jni, XInterface_td.get() );
+ }
+ catch (...)
+ {
+ destruct( jni_env );
+ throw;
+ }
+}
+
+
+void JNI_info::destruct( JNIEnv * jni_env )
+{
+ for (auto & i: m_type_map)
+ {
+ i.second.m_info->destroy( jni_env );
+ }
+ if (m_XInterface_type_info != nullptr)
+ {
+ const_cast< JNI_interface_type_info * >(
+ m_XInterface_type_info )->destroy( jni_env );
+ }
+
+ // free global refs
+ jni_env->DeleteGlobalRef( m_object_java_env );
+ jni_env->DeleteGlobalRef( m_object_Any_VOID );
+ jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_SHORT );
+ jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_LONG );
+ jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_HYPER );
+
+ jni_env->DeleteGlobalRef( m_class_Class );
+ jni_env->DeleteGlobalRef( m_class_Object );
+ jni_env->DeleteGlobalRef( m_class_String );
+ jni_env->DeleteGlobalRef( m_class_Double );
+ jni_env->DeleteGlobalRef( m_class_Float );
+ jni_env->DeleteGlobalRef( m_class_Long );
+ jni_env->DeleteGlobalRef( m_class_Integer );
+ jni_env->DeleteGlobalRef( m_class_Short );
+ jni_env->DeleteGlobalRef( m_class_Byte );
+ jni_env->DeleteGlobalRef( m_class_Boolean );
+ jni_env->DeleteGlobalRef( m_class_Character );
+
+ jni_env->DeleteGlobalRef( m_class_AsynchronousFinalizer );
+ jni_env->DeleteGlobalRef( m_class_JNI_proxy );
+ jni_env->DeleteGlobalRef( m_class_RuntimeException );
+ jni_env->DeleteGlobalRef( m_class_UnoRuntime );
+ jni_env->DeleteGlobalRef( m_class_TypeClass );
+ jni_env->DeleteGlobalRef( m_class_Type );
+ jni_env->DeleteGlobalRef( m_class_Any );
+}
+
+
+JNI_info const * JNI_info::get_jni_info(
+ rtl::Reference< jvmaccess::UnoVirtualMachine > const & uno_vm )
+{
+ // !!!no JNI_info available at JNI_context!!!
+ ::jvmaccess::VirtualMachine::AttachGuard guard(
+ uno_vm->getVirtualMachine() );
+ JNIEnv * jni_env = guard.getEnvironment();
+ JNI_context jni(
+ nullptr, jni_env, static_cast< jobject >(uno_vm->getClassLoader()) );
+
+ jclass jo_class;
+ jmethodID jo_forName;
+ jni.getClassForName( &jo_class, &jo_forName );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_JNI_info_holder(
+ jni,
+ jni.findClass(
+ "com.sun.star.bridges.jni_uno.JNI_info_holder", jo_class,
+ jo_forName, false ) );
+ // field JNI_info_holder.m_jni_info_handle
+ jfieldID field_s_jni_info_handle =
+ jni->GetStaticFieldID(
+ static_cast<jclass>(jo_JNI_info_holder.get()), "s_jni_info_handle", "J" );
+ jni.ensure_no_exception();
+ assert( field_s_jni_info_handle != nullptr );
+
+ JNI_info const * jni_info =
+ reinterpret_cast< JNI_info const * >(
+ jni->GetStaticLongField(
+ static_cast<jclass>(jo_JNI_info_holder.get()), field_s_jni_info_handle ) );
+ if (jni_info == nullptr) // un-initialized?
+ {
+ JNI_info * new_info = new JNI_info(
+ jni_env, static_cast< jobject >(uno_vm->getClassLoader()), jo_class,
+ jo_forName );
+
+ ClearableMutexGuard g( Mutex::getGlobalMutex() );
+ jni_info =
+ reinterpret_cast< JNI_info const * >(
+ jni->GetStaticLongField(
+ static_cast<jclass>(jo_JNI_info_holder.get()),
+ field_s_jni_info_handle ) );
+ if (jni_info == nullptr) // still un-initialized?
+ {
+ jni->SetStaticLongField(
+ static_cast<jclass>(jo_JNI_info_holder.get()), field_s_jni_info_handle,
+ reinterpret_cast< jlong >( new_info ) );
+ jni_info = new_info;
+ }
+ else
+ {
+ g.clear();
+ new_info->destroy( jni_env );
+ }
+ }
+
+ return jni_info;
+}
+
+}
+
+extern "C"
+{
+
+
+SAL_JNI_EXPORT void
+JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1info_1holder_finalize__J(
+ JNIEnv * jni_env, SAL_UNUSED_PARAMETER jobject, jlong jni_info_handle )
+ SAL_THROW_EXTERN_C()
+{
+ ::jni_uno::JNI_info * jni_info =
+ reinterpret_cast< ::jni_uno::JNI_info * >( jni_info_handle );
+ jni_info->destroy( jni_env );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_info.h b/bridges/source/jni_uno/jni_info.h
new file mode 100644
index 000000000..7a18e553e
--- /dev/null
+++ b/bridges/source/jni_uno/jni_info.h
@@ -0,0 +1,366 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <unordered_map>
+
+#include "jni_base.h"
+
+#include <mutex>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/strbuf.hxx>
+
+#include <uno/environment.h>
+#include <typelib/typedescription.hxx>
+
+#include <com/sun/star/uno/Type.hxx>
+
+namespace jvmaccess { class UnoVirtualMachine; }
+
+namespace jni_uno
+{
+
+inline bool type_equals(
+ typelib_TypeDescriptionReference * type1,
+ typelib_TypeDescriptionReference * type2 )
+{
+ if (type1 == type2)
+ return true;
+ OUString const & name1 =
+ OUString::unacquired( &type1->pTypeName );
+ OUString const & name2 =
+ OUString::unacquired( &type2->pTypeName );
+ return ((type1->eTypeClass == type2->eTypeClass) && name1 == name2);
+}
+
+inline bool is_XInterface( typelib_TypeDescriptionReference * type )
+{
+ return ((typelib_TypeClass_INTERFACE == type->eTypeClass) &&
+ OUString::unacquired( &type->pTypeName ) == "com.sun.star.uno.XInterface");
+}
+
+struct JNI_type_info
+{
+ JNI_type_info(const JNI_type_info&) = delete;
+ const JNI_type_info& operator=(const JNI_type_info&) = delete;
+
+ ::com::sun::star::uno::TypeDescription m_td;
+ jclass m_class;
+
+ virtual void destroy( JNIEnv * jni_env ) = 0;
+protected:
+ void destruct( JNIEnv * jni_env )
+ { jni_env->DeleteGlobalRef( m_class ); }
+ virtual ~JNI_type_info() {}
+ explicit JNI_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td );
+};
+
+struct JNI_interface_type_info : public JNI_type_info
+{
+ jobject m_proxy_ctor; // proxy ctor
+ jobject m_type;
+ // sorted via typelib function index
+ std::unique_ptr<jmethodID[]> m_methods;
+
+ virtual void destroy( JNIEnv * jni_env ) override;
+ explicit JNI_interface_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td );
+
+private:
+ virtual ~JNI_interface_type_info() override {}
+};
+
+struct JNI_compound_type_info : public JNI_type_info
+{
+ JNI_type_info const * m_base;
+ // ctor( msg ) for exceptions
+ jmethodID m_exc_ctor;
+ // sorted via typelib member index
+ std::unique_ptr<jfieldID[]> m_fields;
+
+ virtual void destroy( JNIEnv * jni_env ) override;
+ explicit JNI_compound_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td );
+
+private:
+ virtual ~JNI_compound_type_info() override {}
+};
+
+struct JNI_type_info_holder
+{
+ JNI_type_info * m_info;
+
+ JNI_type_info_holder(const JNI_type_info_holder&) = delete;
+ const JNI_type_info_holder& operator=(const JNI_type_info_holder&) = delete;
+
+ JNI_type_info_holder() : m_info( nullptr ) {}
+};
+
+typedef std::unordered_map<
+ OUString, JNI_type_info_holder > t_str2type;
+
+class JNI_info
+{
+ mutable std::mutex m_mutex;
+ mutable t_str2type m_type_map;
+
+public:
+ // These two are needed very early by find_class from within the ctor:
+ jclass m_class_Class;
+ jmethodID m_method_Class_forName;
+
+ jobject m_object_java_env;
+ jobject m_object_Any_VOID;
+ jobject m_object_Type_UNSIGNED_SHORT;
+ jobject m_object_Type_UNSIGNED_LONG;
+ jobject m_object_Type_UNSIGNED_HYPER;
+
+ jclass m_class_Object;
+ jclass m_class_Character;
+ jclass m_class_Boolean;
+ jclass m_class_Byte;
+ jclass m_class_Short;
+ jclass m_class_Integer;
+ jclass m_class_Long;
+ jclass m_class_Float;
+ jclass m_class_Double;
+ jclass m_class_String;
+
+ jclass m_class_UnoRuntime;
+ jclass m_class_RuntimeException;
+ jclass m_class_Any;
+ jclass m_class_Type;
+ jclass m_class_TypeClass;
+ jclass m_class_JNI_proxy;
+ jclass m_class_AsynchronousFinalizer;
+
+ jmethodID m_method_Object_toString;
+ jmethodID m_method_Class_getName;
+ jmethodID m_method_Throwable_getMessage;
+ jmethodID m_ctor_Character_with_char;
+ jmethodID m_ctor_Boolean_with_boolean;
+ jmethodID m_ctor_Byte_with_byte;
+ jmethodID m_ctor_Short_with_short;
+ jmethodID m_ctor_Integer_with_int;
+ jmethodID m_ctor_Long_with_long;
+ jmethodID m_ctor_Float_with_float;
+ jmethodID m_ctor_Double_with_double;
+ jmethodID m_method_Boolean_booleanValue;
+ jmethodID m_method_Byte_byteValue;
+ jmethodID m_method_Character_charValue;
+ jmethodID m_method_Double_doubleValue;
+ jmethodID m_method_Float_floatValue;
+ jmethodID m_method_Integer_intValue;
+ jmethodID m_method_Long_longValue;
+ jmethodID m_method_Short_shortValue;
+
+ jmethodID m_method_IEnvironment_getRegisteredInterface;
+ jmethodID m_method_IEnvironment_registerInterface;
+ jmethodID m_method_UnoRuntime_generateOid;
+ jmethodID m_method_UnoRuntime_queryInterface;
+ jmethodID m_ctor_Any_with_Type_Object;
+ jfieldID m_field_Any_type;
+ jfieldID m_field_Any_object;
+ jmethodID m_ctor_Type_with_Class;
+ jmethodID m_ctor_Type_with_Name_TypeClass;
+ jfieldID m_field_Type_typeName;
+ jmethodID m_method_TypeClass_fromInt;
+ jfieldID m_field_Enum_m_value;
+
+ jmethodID m_method_JNI_proxy_get_proxy_ctor;
+ jmethodID m_method_JNI_proxy_create;
+ jfieldID m_field_JNI_proxy_m_receiver_handle;
+ jfieldID m_field_JNI_proxy_m_td_handle;
+ jfieldID m_field_JNI_proxy_m_type;
+ jfieldID m_field_JNI_proxy_m_oid;
+
+ jmethodID m_ctor_AsynchronousFinalizer;
+ jmethodID m_method_AsynchronousFinalizer_drain;
+
+ ::com::sun::star::uno::TypeDescription m_XInterface_queryInterface_td;
+ ::com::sun::star::uno::Type const & m_Exception_type;
+ ::com::sun::star::uno::Type const & m_RuntimeException_type;
+ ::com::sun::star::uno::Type const & m_void_type;
+ JNI_interface_type_info const * m_XInterface_type_info;
+
+ // noncopyable
+ JNI_info(const JNI_info&) = delete;
+ const JNI_info& operator=(const JNI_info&) = delete;
+
+ JNI_type_info const * get_type_info(
+ JNI_context const & jni,
+ typelib_TypeDescription * type ) const;
+ JNI_type_info const * get_type_info(
+ JNI_context const & jni,
+ typelib_TypeDescriptionReference * type ) const;
+ JNI_type_info const * get_type_info(
+ JNI_context const & jni,
+ OUString const & uno_name ) const;
+ inline static void append_sig(
+ OStringBuffer * buf, typelib_TypeDescriptionReference * type,
+ bool use_Object_for_type_XInterface = true, bool use_slashes = true );
+
+ // get this
+ static JNI_info const * get_jni_info(
+ rtl::Reference< jvmaccess::UnoVirtualMachine > const & uno_vm );
+ inline void destroy( JNIEnv * jni_env );
+
+private:
+ JNI_type_info const * create_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td ) const;
+
+ void destruct( JNIEnv * jni_env );
+
+ JNI_info( JNIEnv * jni_env, jobject class_loader,
+ jclass classClass, jmethodID methodForName );
+ ~JNI_info() {}
+};
+
+inline void JNI_info::destroy( JNIEnv * jni_env )
+{
+ destruct( jni_env );
+ delete this;
+}
+
+inline void JNI_info::append_sig(
+ OStringBuffer * buf, typelib_TypeDescriptionReference * type,
+ bool use_Object_for_type_XInterface, bool use_slashes )
+{
+ switch (type->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ buf->append( 'V' );
+ break;
+ case typelib_TypeClass_CHAR:
+ buf->append( 'C' );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ buf->append( 'Z' );
+ break;
+ case typelib_TypeClass_BYTE:
+ buf->append( 'B' );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ buf->append( 'S' );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ buf->append( 'I' );
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ buf->append( 'J' );
+ break;
+ case typelib_TypeClass_FLOAT:
+ buf->append( 'F' );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ buf->append( 'D' );
+ break;
+ case typelib_TypeClass_STRING:
+ if ( use_slashes ) {
+ buf->append( "Ljava/lang/String;" );
+ } else {
+ buf->append( "Ljava.lang.String;" );
+ }
+ break;
+ case typelib_TypeClass_TYPE:
+ if ( use_slashes ) {
+ buf->append( "Lcom/sun/star/uno/Type;" );
+ } else {
+ buf->append( "Lcom.sun.star.uno.Type;" );
+ }
+ break;
+ case typelib_TypeClass_ANY:
+ if ( use_slashes ) {
+ buf->append( "Ljava/lang/Object;" );
+ } else {
+ buf->append( "Ljava.lang.Object;" );
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ OUString const & uno_name =
+ OUString::unacquired( &type->pTypeName );
+ buf->append( 'L' );
+ // Erase type arguments of instantiated polymorphic struct types:
+ sal_Int32 i = uno_name.indexOf( '<' );
+ if ( i < 0 ) {
+ buf->append(
+ OUStringToOString(
+ use_slashes ? uno_name.replace( '.', '/' ) : uno_name,
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ } else {
+ OUString s( uno_name.copy( 0, i ) );
+ buf->append(
+ OUStringToOString(
+ use_slashes ? s.replace( '.', '/' ) : s,
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ }
+ buf->append( ';' );
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ buf->append( '[' );
+ TypeDescr td( type );
+ append_sig(
+ buf, reinterpret_cast<typelib_IndirectTypeDescription *>(td.get())->pType,
+ use_Object_for_type_XInterface, use_slashes );
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ if (use_Object_for_type_XInterface && is_XInterface( type ))
+ {
+ if ( use_slashes ) {
+ buf->append( "Ljava/lang/Object;" );
+ } else {
+ buf->append( "Ljava.lang.Object;" );
+ }
+ }
+ else
+ {
+ OUString const & uno_name =
+ OUString::unacquired( &type->pTypeName );
+ buf->append( 'L' );
+ buf->append(
+ OUStringToOString(
+ use_slashes ? uno_name.replace( '.', '/' ) : uno_name,
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ buf->append( ';' );
+ }
+ break;
+ default:
+ throw BridgeRuntimeError(
+ "unsupported type: " +
+ OUString::unacquired( &type->pTypeName ) );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_java2uno.cxx b/bridges/source/jni_uno/jni_java2uno.cxx
new file mode 100644
index 000000000..b6c4c6ea9
--- /dev/null
+++ b/bridges/source/jni_uno/jni_java2uno.cxx
@@ -0,0 +1,624 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <cassert>
+
+#include <sal/alloca.h>
+
+#include "jni_bridge.h"
+#include "jniunoenvironmentdata.hxx"
+
+namespace jni_uno
+{
+
+
+jobject Bridge::map_to_java(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, JNI_interface_type_info const * info ) const
+{
+ // get oid
+ rtl_uString * pOid = nullptr;
+ (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
+ assert( pOid != nullptr );
+ OUString oid( pOid, SAL_NO_ACQUIRE );
+
+ // opt getRegisteredInterface()
+ JLocalAutoRef jo_oid( jni, ustring_to_jstring( jni, oid.pData ) );
+ jvalue args[ 2 ];
+ args[ 0 ].l = jo_oid.get();
+ args[ 1 ].l = info->m_type;
+ jobject jo_iface = jni->CallObjectMethodA(
+ getJniInfo()->m_object_java_env,
+ getJniInfo()->m_method_IEnvironment_getRegisteredInterface, args );
+ jni.ensure_no_exception();
+
+ if (jo_iface == nullptr) // no registered iface
+ {
+ // register uno interface
+ (*m_uno_env->registerInterface)(
+ m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
+ oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
+
+ // create java and register java proxy
+ jvalue args2[ 8 ];
+ acquire();
+ args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
+ (*pUnoI->acquire)( pUnoI );
+ args2[ 1 ].l = getJniInfo()->m_object_java_env;
+ args2[ 2 ].j = reinterpret_cast< sal_Int64 >( pUnoI );
+ typelib_typedescription_acquire( info->m_td.get() );
+ args2[ 3 ].j = reinterpret_cast< sal_Int64 >( info->m_td.get() );
+ args2[ 4 ].l = info->m_type;
+ args2[ 5 ].l = jo_oid.get();
+ args2[ 6 ].l = info->m_proxy_ctor;
+ auto * envData = static_cast<jni_uno::JniUnoEnvironmentData *>(
+ m_java_env->pContext);
+ {
+ osl::MutexGuard g(envData->mutex);
+ args2[ 7 ].l = envData->asynchronousFinalizer;
+ }
+ jo_iface = jni->CallStaticObjectMethodA(
+ getJniInfo()->m_class_JNI_proxy,
+ getJniInfo()->m_method_JNI_proxy_create, args2 );
+ jni.ensure_no_exception();
+ }
+
+ assert( jo_iface != nullptr );
+ return jo_iface;
+}
+
+
+void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
+{
+ if (uno_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // append java stack trace to Message member
+ static_cast< ::com::sun::star::uno::Exception * >(
+ uno_exc->pData )->Message += jni.get_stack_trace();
+#endif
+ SAL_INFO(
+ "bridges",
+ "exception occurred java->uno: ["
+ << OUString::unacquired(&uno_exc->pType->pTypeName) << "] "
+ << static_cast<css::uno::Exception const *>(
+ uno_exc->pData)->Message);
+ // signal exception
+ jvalue java_exc;
+ try
+ {
+ map_to_java(
+ jni, &java_exc, uno_exc->pData, uno_exc->pType, nullptr,
+ true /* in */, false /* no out */ );
+ }
+ catch (...)
+ {
+ uno_any_destruct( uno_exc, nullptr );
+ throw;
+ }
+ uno_any_destruct( uno_exc, nullptr );
+
+ JLocalAutoRef jo_exc( jni, java_exc.l );
+ jint res = jni->Throw( static_cast<jthrowable>(jo_exc.get()) );
+ if (res != 0)
+ {
+ // call toString()
+ JLocalAutoRef jo_descr(
+ jni, jni->CallObjectMethodA(
+ jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ throw BridgeRuntimeError(
+ "throwing java exception failed: "
+ + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
+ + jni.get_stack_trace() );
+ }
+ }
+ else
+ {
+ OUString message(
+ "thrown exception is no uno exception: " +
+ OUString::unacquired( &uno_exc->pType->pTypeName ) +
+ jni.get_stack_trace() );
+ uno_any_destruct( uno_exc, nullptr );
+ throw BridgeRuntimeError( message );
+ }
+}
+
+namespace {
+
+union largest
+{
+ sal_Int64 n;
+ double d;
+ void * p;
+ uno_Any a;
+};
+
+}
+
+jobject Bridge::call_uno(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, typelib_TypeDescription * member_td,
+ typelib_TypeDescriptionReference * return_type,
+ sal_Int32 nParams, typelib_MethodParameter const * pParams,
+ jobjectArray jo_args /* may be 0 */ ) const
+{
+ // return mem
+ sal_Int32 return_size;
+ switch (return_type->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ return_size = 0;
+ break;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ return_size = std::max(
+ TypeDescr(return_type).get()->nSize,
+ static_cast< sal_Int32 >(sizeof (largest)));
+ break;
+
+ default:
+ return_size = sizeof (largest);
+ break;
+ }
+
+ char * mem = static_cast<char *>(alloca(
+ (nParams * sizeof (void *)) +
+ return_size + (nParams * sizeof (largest)) ));
+ void ** uno_args = reinterpret_cast<void **>(mem);
+ void * uno_ret = return_size == 0 ? nullptr : (mem + (nParams * sizeof (void *)));
+ largest * uno_args_mem = reinterpret_cast<largest *>
+ (mem + (nParams * sizeof (void *)) + return_size);
+
+ assert( (nParams == 0) || (nParams == jni->GetArrayLength( jo_args )) );
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = pParams[ nPos ];
+ typelib_TypeDescriptionReference * type = param.pTypeRef;
+
+ uno_args[ nPos ] = &uno_args_mem[ nPos ];
+ if (type->eTypeClass == typelib_TypeClass_STRUCT ||
+ type->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ TypeDescr td( type );
+ if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
+ > sizeof (largest))
+ uno_args[ nPos ] = alloca( td.get()->nSize );
+ }
+
+ if (param.bIn)
+ {
+ try
+ {
+ JLocalAutoRef jo_arg(
+ jni, jni->GetObjectArrayElement( jo_args, nPos ) );
+ jni.ensure_no_exception();
+ jvalue java_arg;
+ java_arg.l = jo_arg.get();
+ map_to_uno(
+ jni, uno_args[ nPos ], java_arg, type, nullptr,
+ false /* no assign */, param.bOut,
+ true /* special wrapped integral types */ );
+ }
+ catch (...)
+ {
+ // cleanup uno in args
+ for ( sal_Int32 n = 0; n < nPos; ++n )
+ {
+ typelib_MethodParameter const & p = pParams[ n ];
+ if (p.bIn)
+ {
+ uno_type_destructData(
+ uno_args[ n ], p.pTypeRef, nullptr );
+ }
+ }
+ throw;
+ }
+ }
+ }
+
+ uno_Any uno_exc_holder;
+ uno_Any * uno_exc = &uno_exc_holder;
+ // call binary uno
+ (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
+
+ if (uno_exc == nullptr)
+ {
+ // convert out args; destruct uno args
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = pParams[ nPos ];
+ typelib_TypeDescriptionReference * type = param.pTypeRef;
+ if (param.bOut)
+ {
+ try
+ {
+ // get out holder array[ 1 ]
+ JLocalAutoRef jo_out_holder(
+ jni, jni->GetObjectArrayElement( jo_args, nPos ) );
+ jni.ensure_no_exception();
+ jvalue java_arg;
+ java_arg.l = jo_out_holder.get();
+ map_to_java(
+ jni, &java_arg, uno_args[ nPos ], type, nullptr,
+ true /* in */, true /* out holder */ );
+ }
+ catch (...)
+ {
+ // cleanup further uno args
+ for ( sal_Int32 n = nPos; n < nParams; ++n )
+ {
+ uno_type_destructData(
+ uno_args[ n ], pParams[ n ].pTypeRef, nullptr );
+ }
+ // cleanup uno return value
+ uno_type_destructData( uno_ret, return_type, nullptr );
+ throw;
+ }
+ }
+ if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
+ type->eTypeClass != typelib_TypeClass_ENUM) // opt
+ {
+ uno_type_destructData( uno_args[ nPos ], type, nullptr );
+ }
+ }
+
+ if (return_type->eTypeClass != typelib_TypeClass_VOID)
+ {
+ // convert uno return value
+ jvalue java_ret;
+ try
+ {
+ map_to_java(
+ jni, &java_ret, uno_ret, return_type, nullptr,
+ true /* in */, false /* no out */,
+ true /* special_wrapped_integral_types */ );
+ }
+ catch (...)
+ {
+ uno_type_destructData( uno_ret, return_type, nullptr );
+ throw;
+ }
+ if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
+ return_type->eTypeClass != typelib_TypeClass_ENUM) // opt
+ {
+ uno_type_destructData( uno_ret, return_type, nullptr );
+ }
+ return java_ret.l;
+ }
+ return nullptr; // void return
+ }
+ else // exception occurred
+ {
+ // destruct uno in args
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = pParams[ nPos ];
+ if (param.bIn)
+ uno_type_destructData( uno_args[ nPos ], param.pTypeRef, nullptr );
+ }
+
+ handle_uno_exc( jni, uno_exc );
+ return nullptr;
+ }
+}
+
+}
+
+using namespace ::jni_uno;
+
+extern "C"
+{
+
+
+SAL_JNI_EXPORT jobject
+JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
+ JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
+ jobjectArray jo_args /* may be 0 */ )
+{
+ Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JNI_context jni(
+ jni_info, jni_env,
+ static_cast< jobject >(
+ static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
+ ->machine->getClassLoader()));
+
+ OUString method_name;
+
+ try
+ {
+ method_name = jstring_to_oustring( jni, jo_method );
+ SAL_INFO(
+ "bridges",
+ "java->uno call: " << method_name << " on oid "
+ << jstring_to_oustring(
+ jni,
+ static_cast<jstring>(
+ JLocalAutoRef(
+ jni,
+ jni->GetObjectField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
+ .get())));
+ // special IQueryInterface.queryInterface()
+ if ( method_name == "queryInterface" )
+ {
+ // oid
+ JLocalAutoRef jo_oid(
+ jni, jni->GetObjectField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
+ // type
+ JLocalAutoRef jo_type(
+ jni, jni->GetObjectArrayElement( jo_args, 0 ) );
+ jni.ensure_no_exception();
+
+ JLocalAutoRef jo_type_name(
+ jni, jni->GetObjectField(
+ jo_type.get(), jni_info->m_field_Type_typeName ) );
+ if (! jo_type_name.is())
+ {
+ throw BridgeRuntimeError(
+ "incomplete type object: no type name!" +
+ jni.get_stack_trace() );
+ }
+ OUString type_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
+ JNI_type_info const * info =
+ jni_info->get_type_info( jni, type_name );
+ if (info->m_td.get()->eTypeClass != typelib_TypeClass_INTERFACE)
+ {
+ throw BridgeRuntimeError(
+ "queryInterface() call demands an INTERFACE type!" );
+ }
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >( info );
+
+ // getRegisteredInterface() already tested in JNI_proxy:
+ // perform queryInterface call on binary uno interface
+ uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
+
+ uno_Any uno_ret;
+ void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
+ uno_Any uno_exc_holder;
+ uno_Any * uno_exc = &uno_exc_holder;
+ // call binary uno
+ (*pUnoI->pDispatcher)(
+ pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
+ &uno_ret, uno_args, &uno_exc );
+ if (uno_exc == nullptr)
+ {
+ jobject jo_ret = nullptr;
+ if (uno_ret.pType->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ uno_Interface * pUnoRet =
+ static_cast<uno_Interface *>(uno_ret.pReserved);
+ if (pUnoRet != nullptr)
+ {
+ try
+ {
+ jo_ret =
+ bridge->map_to_java( jni, pUnoRet, iface_info );
+ }
+ catch (...)
+ {
+ uno_any_destruct( &uno_ret, nullptr );
+ throw;
+ }
+ }
+ }
+ uno_any_destruct( &uno_ret, nullptr );
+ return jo_ret;
+ }
+ else
+ {
+ bridge->handle_uno_exc( jni, uno_exc );
+ return nullptr;
+ }
+ }
+
+ typelib_InterfaceTypeDescription * td =
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
+ uno_Interface * pUnoI =
+ reinterpret_cast< uno_Interface * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
+
+ typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
+ for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
+ {
+ // try to avoid getting typedescription as long as possible,
+ // because of a Mutex.acquire() in
+ // typelib_typedescriptionreference_getDescription()
+ typelib_TypeDescriptionReference * member_type =
+ ppAllMembers[ nPos ];
+
+ // check method_name against fully qualified type_name
+ // of member_type; type_name is of the form
+ // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
+ OUString const & type_name =
+ OUString::unacquired( &member_type->pTypeName );
+ sal_Int32 offset = type_name.indexOf( ':' ) + 2;
+ assert(offset >= 2);
+ assert(offset < type_name.getLength());
+ assert(type_name[offset - 1] == ':' );
+ sal_Int32 remainder = type_name.getLength() - offset;
+ if (member_type->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
+ {
+ if ((method_name.getLength() == remainder
+ || (method_name.getLength() < remainder
+ && type_name[offset + method_name.getLength()] == ':'))
+ && type_name.match(method_name, offset))
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceMethodTypeDescription * method_td =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member_td.get() );
+ return bridge->call_uno(
+ jni, pUnoI, member_td.get(),
+ method_td->pReturnTypeRef,
+ method_td->nParams, method_td->pParams,
+ jo_args );
+ }
+ }
+ else // attribute
+ {
+ assert(
+ member_type->eTypeClass ==
+ typelib_TypeClass_INTERFACE_ATTRIBUTE );
+
+ if (method_name.getLength() >= 3
+ && (method_name.getLength() - 3 == remainder
+ || (method_name.getLength() - 3 < remainder
+ && type_name[
+ offset + (method_name.getLength() - 3)] == ':'))
+ && method_name[1] == 'e' && method_name[2] == 't'
+ && rtl_ustr_compare_WithLength(
+ type_name.getStr() + offset,
+ method_name.getLength() - 3,
+ method_name.getStr() + 3,
+ method_name.getLength() - 3) == 0)
+ {
+ if (method_name[ 0 ] == 'g')
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceAttributeTypeDescription * attr_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member_td.get() );
+ return bridge->call_uno(
+ jni, pUnoI, member_td.get(),
+ attr_td->pAttributeTypeRef,
+ 0, nullptr,
+ jo_args );
+ }
+ else if (method_name[ 0 ] == 's')
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceAttributeTypeDescription * attr_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member_td.get() );
+ if (! attr_td->bReadOnly)
+ {
+ typelib_MethodParameter param;
+ param.pTypeRef = attr_td->pAttributeTypeRef;
+ param.bIn = true;
+ param.bOut = false;
+ return bridge->call_uno(
+ jni, pUnoI, member_td.get(),
+ jni_info->m_void_type.getTypeLibType(),
+ 1, &param,
+ jo_args );
+ }
+ }
+ }
+ }
+ }
+ // the thing that should not be... no method info found!
+ throw BridgeRuntimeError(
+ "calling undeclared function on interface "
+ + OUString::unacquired(&td->aBase.pTypeName)
+ + ": " + method_name + jni.get_stack_trace() );
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "Java calling UNO method " << method_name << ": " << err.m_message);
+ // notify RuntimeException
+ OString cstr_msg(
+ "[jni_uno bridge error] Java calling UNO method "
+ + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
+ + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
+ if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
+ != 0)
+ {
+ assert( false );
+ }
+ return nullptr;
+ }
+ catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ OString cstr_msg(
+ "[jni_uno bridge error] attaching current thread to java failed"
+ + OUStringToOString(
+ jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
+ if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
+ != 0)
+ {
+ assert( false );
+ }
+ return nullptr;
+ }
+}
+
+
+SAL_JNI_EXPORT void
+JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
+ JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
+{
+ Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JNI_context jni(
+ jni_info, jni_env,
+ static_cast< jobject >(
+ static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
+ ->machine->getClassLoader()));
+
+ uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
+ typelib_TypeDescription * td =
+ reinterpret_cast< typelib_TypeDescription * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
+ SAL_INFO(
+ "bridges",
+ "freeing java uno proxy: "
+ << jstring_to_oustring(
+ jni,
+ static_cast<jstring>(
+ JLocalAutoRef(
+ jni,
+ jni->GetObjectField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
+ .get())));
+ // revoke from uno env; has already been revoked from java env
+ (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
+ // release receiver
+ (*pUnoI->release)( pUnoI );
+ // release typedescription handle
+ typelib_typedescription_release( td );
+ // release bridge handle
+ bridge->release();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_uno2java.cxx b/bridges/source/jni_uno/jni_uno2java.cxx
new file mode 100644
index 000000000..8fd38ec31
--- /dev/null
+++ b/bridges/source/jni_uno/jni_uno2java.cxx
@@ -0,0 +1,805 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <atomic>
+#include <cassert>
+#include <cstddef>
+#include <memory>
+
+#include <sal/alloca.h>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <utility>
+
+#include "jni_bridge.h"
+#include "jniunoenvironmentdata.hxx"
+
+namespace
+{
+extern "C"
+{
+
+
+void UNO_proxy_free( uno_ExtEnvironment * env, void * proxy )
+ SAL_THROW_EXTERN_C();
+
+
+void UNO_proxy_acquire( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C();
+
+
+void UNO_proxy_release( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C();
+
+
+void UNO_proxy_dispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
+ void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
+ SAL_THROW_EXTERN_C();
+}
+}
+
+namespace jni_uno
+{
+
+
+void Bridge::handle_java_exc(
+ JNI_context const & jni,
+ JLocalAutoRef const & jo_exc, uno_Any * uno_exc ) const
+{
+ assert( jo_exc.is() );
+ if (! jo_exc.is())
+ {
+ throw BridgeRuntimeError(
+ "java exception occurred, but no java exception available!?" +
+ jni.get_stack_trace() );
+ }
+
+ JLocalAutoRef jo_class( jni, jni->GetObjectClass( jo_exc.get() ) );
+ JLocalAutoRef jo_class_name(
+ jni, jni->CallObjectMethodA(
+ jo_class.get(), getJniInfo()->m_method_Class_getName, nullptr ) );
+ jni.ensure_no_exception();
+ OUString exc_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_class_name.get()) ) );
+
+ ::com::sun::star::uno::TypeDescription td( exc_name.pData );
+ if (!td.is() || (td.get()->eTypeClass != typelib_TypeClass_EXCEPTION))
+ {
+ // call toString()
+ JLocalAutoRef jo_descr(
+ jni, jni->CallObjectMethodA(
+ jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ throw BridgeRuntimeError(
+ "non-UNO exception occurred: "
+ + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
+ + jni.get_stack_trace( jo_exc.get() ) );
+ }
+
+ std::unique_ptr< rtl_mem > uno_data( rtl_mem::allocate( td.get()->nSize ) );
+ jvalue val;
+ val.l = jo_exc.get();
+ map_to_uno(
+ jni, uno_data.get(), val, td.get()->pWeakRef, nullptr,
+ false /* no assign */, false /* no out param */ );
+
+#if OSL_DEBUG_LEVEL > 0
+ // patch Message, append stack trace
+ reinterpret_cast< ::com::sun::star::uno::Exception * >(
+ uno_data.get() )->Message += jni.get_stack_trace( jo_exc.get() );
+#endif
+
+ typelib_typedescriptionreference_acquire( td.get()->pWeakRef );
+ uno_exc->pType = td.get()->pWeakRef;
+ uno_exc->pData = uno_data.release();
+
+ SAL_INFO(
+ "bridges",
+ "exception occurred uno->java: [" << exc_name << "] "
+ << (static_cast<css::uno::Exception const *>(uno_exc->pData)
+ ->Message));
+}
+
+
+void Bridge::call_java(
+ jobject javaI, typelib_InterfaceTypeDescription * iface_td,
+ sal_Int32 local_member_index, sal_Int32 function_pos_offset,
+ typelib_TypeDescriptionReference * return_type,
+ typelib_MethodParameter * params, sal_Int32 nParams,
+ void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const
+{
+ assert( function_pos_offset == 0 || function_pos_offset == 1 );
+
+ JNI_guarded_context jni(
+ getJniInfo(),
+ static_cast<JniUnoEnvironmentData *>(m_java_env->pContext)->machine);
+
+ // assure fully initialized iface_td:
+ ::com::sun::star::uno::TypeDescription iface_holder;
+ if (! iface_td->aBase.bComplete) {
+ iface_holder = ::com::sun::star::uno::TypeDescription(
+ reinterpret_cast<typelib_TypeDescription *>(iface_td) );
+ iface_holder.makeComplete();
+ if (! iface_holder.get()->bComplete) {
+ throw BridgeRuntimeError(
+ "cannot make type complete: "
+ + OUString::unacquired(&iface_holder.get()->pTypeName)
+ + jni.get_stack_trace() );
+ }
+ iface_td = reinterpret_cast<typelib_InterfaceTypeDescription *>(
+ iface_holder.get() );
+ assert( iface_td->aBase.eTypeClass == typelib_TypeClass_INTERFACE );
+ }
+
+ // prepare java args, save param td
+ jvalue * java_args = static_cast<jvalue *>(alloca( sizeof (jvalue) * nParams ));
+
+ sal_Int32 nPos;
+ for ( nPos = 0; nPos < nParams; ++nPos )
+ {
+ try
+ {
+ typelib_MethodParameter const & param = params[ nPos ];
+ java_args[ nPos ].l = nullptr; // if out: build up array[ 1 ]
+ map_to_java(
+ jni, &java_args[ nPos ],
+ uno_args[ nPos ],
+ param.pTypeRef, nullptr,
+ param.bIn /* convert uno value */,
+ param.bOut /* build up array[ 1 ] */ );
+ }
+ catch (...)
+ {
+ // cleanup
+ for ( sal_Int32 n = 0; n < nPos; ++n )
+ {
+ typelib_MethodParameter const & param = params[ n ];
+ if (param.bOut ||
+ typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
+ {
+ jni->DeleteLocalRef( java_args[ n ].l );
+ }
+ }
+ throw;
+ }
+ }
+
+ sal_Int32 base_members = iface_td->nAllMembers - iface_td->nMembers;
+ assert( base_members < iface_td->nAllMembers );
+ sal_Int32 base_members_function_pos =
+ iface_td->pMapMemberIndexToFunctionIndex[ base_members ];
+ sal_Int32 member_pos = base_members + local_member_index;
+ SAL_WARN_IF(
+ member_pos >= iface_td->nAllMembers, "bridges",
+ "member pos out of range");
+ sal_Int32 function_pos =
+ iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]
+ + function_pos_offset;
+ SAL_WARN_IF(
+ (function_pos < base_members_function_pos
+ || function_pos >= iface_td->nMapFunctionIndexToMemberIndex),
+ "bridges", "illegal function index");
+ function_pos -= base_members_function_pos;
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ getJniInfo()->get_type_info( jni, &iface_td->aBase ) );
+ jmethodID method_id = info->m_methods[ function_pos ];
+
+#if OSL_DEBUG_LEVEL > 0
+ JLocalAutoRef jo_method(
+ jni, jni->ToReflectedMethod( info->m_class, method_id, JNI_FALSE ) );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_descr1(
+ jni, jni->CallObjectMethodA(
+ jo_method.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_descr2(
+ jni,
+ jni->CallObjectMethodA(
+ javaI, getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_class( jni, jni->GetObjectClass( javaI ) );
+ JLocalAutoRef jo_descr3(
+ jni,
+ jni->CallObjectMethodA(
+ jo_class.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ SAL_INFO(
+ "bridges",
+ "calling " << jstring_to_oustring( jni, static_cast<jstring>(jo_descr1.get()) ) << " on "
+ << jstring_to_oustring( jni, static_cast<jstring>(jo_descr2.get()) ) << " ("
+ << jstring_to_oustring( jni, static_cast<jstring>(jo_descr3.get()) ) << ")");
+#endif
+
+ // complex return value
+ JLocalAutoRef java_ret( jni );
+
+ switch (return_type->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ jni->CallVoidMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_CHAR:
+ *static_cast<sal_Unicode *>(uno_ret) =
+ jni->CallCharMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ *static_cast<sal_Bool *>(uno_ret) =
+ jni->CallBooleanMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int8 *>(uno_ret) =
+ jni->CallByteMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_Int16 *>(uno_ret) =
+ jni->CallShortMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_Int32 *>(uno_ret) =
+ jni->CallIntMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_Int64 *>(uno_ret) =
+ jni->CallLongMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_FLOAT:
+ *static_cast<float *>(uno_ret) =
+ jni->CallFloatMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *static_cast<double *>(uno_ret) =
+ jni->CallDoubleMethodA( javaI, method_id, java_args );
+ break;
+ default:
+ java_ret.reset(
+ jni->CallObjectMethodA( javaI, method_id, java_args ) );
+ break;
+ }
+
+ if (jni->ExceptionCheck())
+ {
+ JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() );
+ jni->ExceptionClear();
+
+ // release temp java local refs
+ for ( nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = params[ nPos ];
+ if (param.bOut ||
+ typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
+ {
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ }
+
+ handle_java_exc( jni, jo_exc, *uno_exc );
+ }
+ else // no exception
+ {
+ for ( nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = params[ nPos ];
+ if (param.bOut)
+ {
+ try
+ {
+ map_to_uno(
+ jni, uno_args[ nPos ],
+ java_args[ nPos ], param.pTypeRef, nullptr,
+ param.bIn /* assign if inout */,
+ true /* out param */ );
+ }
+ catch (...)
+ {
+ // cleanup uno pure out
+ for ( sal_Int32 n = 0; n < nPos; ++n )
+ {
+ typelib_MethodParameter const & p = params[ n ];
+ if (! p.bIn)
+ {
+ uno_type_destructData(
+ uno_args[ n ], p.pTypeRef, nullptr );
+ }
+ }
+ // cleanup java temp local refs
+ for ( ; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & p = params[ nPos ];
+ if (p.bOut ||
+ typelib_TypeClass_DOUBLE <
+ p.pTypeRef->eTypeClass)
+ {
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ }
+ throw;
+ }
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ else // pure temp in param
+ {
+ if (typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ }
+
+ // return value
+ if (typelib_TypeClass_DOUBLE < return_type->eTypeClass)
+ {
+ try
+ {
+ jvalue val;
+ val.l = java_ret.get();
+ map_to_uno(
+ jni, uno_ret, val, return_type, nullptr,
+ false /* no assign */, false /* no out param */ );
+ }
+ catch (...)
+ {
+ // cleanup uno pure out
+ for ( sal_Int32 i = 0; i < nParams; ++i )
+ {
+ typelib_MethodParameter const & param = params[ i ];
+ if (! param.bIn)
+ {
+ uno_type_destructData(
+ uno_args[ i ], param.pTypeRef, nullptr );
+ }
+ }
+ throw;
+ }
+ } // else: already set integral uno return value
+
+ // no exception occurred
+ *uno_exc = nullptr;
+ }
+}
+
+namespace {
+
+// a UNO proxy wrapping a Java interface
+struct UNO_proxy : public uno_Interface
+{
+ mutable std::atomic<std::size_t> m_ref;
+ Bridge const * m_bridge;
+
+ // mapping information
+ jobject m_javaI;
+ jstring m_jo_oid;
+ OUString m_oid;
+ JNI_interface_type_info const * m_type_info;
+
+ inline void acquire() const;
+ inline void release() const;
+
+ // ctor
+ inline UNO_proxy(
+ JNI_context const & jni, Bridge const * bridge,
+ jobject javaI, jstring jo_oid, OUString oid,
+ JNI_interface_type_info const * info );
+};
+
+}
+
+inline UNO_proxy::UNO_proxy(
+ JNI_context const & jni, Bridge const * bridge,
+ jobject javaI, jstring jo_oid, OUString oid,
+ JNI_interface_type_info const * info )
+ : m_ref( 1 ),
+ m_oid(std::move( oid )),
+ m_type_info( info )
+{
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JLocalAutoRef jo_string_array(
+ jni, jni->NewObjectArray( 1, jni_info->m_class_String, jo_oid ) );
+ jni.ensure_no_exception();
+ jvalue args[ 3 ];
+ args[ 0 ].l = javaI;
+ args[ 1 ].l = jo_string_array.get();
+ args[ 2 ].l = info->m_type;
+ jobject jo_iface = jni->CallObjectMethodA(
+ jni_info->m_object_java_env,
+ jni_info->m_method_IEnvironment_registerInterface, args );
+ jni.ensure_no_exception();
+
+ m_javaI = jni->NewGlobalRef( jo_iface );
+ m_jo_oid = static_cast<jstring>(jni->NewGlobalRef( jo_oid ));
+ bridge->acquire();
+ m_bridge = bridge;
+
+ // uno_Interface
+ uno_Interface::acquire = UNO_proxy_acquire;
+ uno_Interface::release = UNO_proxy_release;
+ uno_Interface::pDispatcher = UNO_proxy_dispatch;
+}
+
+
+inline void UNO_proxy::acquire() const
+{
+ if (++m_ref == 1)
+ {
+ // rebirth of proxy zombie
+ void * that = const_cast< UNO_proxy * >( this );
+ // register at uno env
+ (*m_bridge->m_uno_env->registerProxyInterface)(
+ m_bridge->m_uno_env, &that,
+ UNO_proxy_free, m_oid.pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(m_type_info->m_td.get()) );
+ assert( this == that );
+ }
+}
+
+
+inline void UNO_proxy::release() const
+{
+ if (--m_ref == 0)
+ {
+ // revoke from uno env on last release
+ (*m_bridge->m_uno_env->revokeInterface)(
+ m_bridge->m_uno_env, const_cast< UNO_proxy * >( this ) );
+ }
+}
+
+
+uno_Interface * Bridge::map_to_uno(
+ JNI_context const & jni,
+ jobject javaI, JNI_interface_type_info const * info ) const
+{
+ JLocalAutoRef jo_oid( jni, compute_oid( jni, javaI ) );
+ OUString oid( jstring_to_oustring( jni, static_cast<jstring>(jo_oid.get()) ) );
+
+ uno_Interface * pUnoI = nullptr;
+ (*m_uno_env->getRegisteredInterface)(
+ m_uno_env, reinterpret_cast<void **>(&pUnoI),
+ oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
+
+ if (pUnoI == nullptr) // no existing interface, register new proxy
+ {
+ // refcount initially 1
+ pUnoI = new UNO_proxy(
+ jni, this,
+ javaI, static_cast<jstring>(jo_oid.get()), oid, info );
+
+ (*m_uno_env->registerProxyInterface)(
+ m_uno_env, reinterpret_cast<void **>(&pUnoI),
+ UNO_proxy_free,
+ oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
+ }
+ return pUnoI;
+}
+
+}
+
+using namespace ::jni_uno;
+
+namespace
+{
+extern "C"
+{
+
+
+void UNO_proxy_free( uno_ExtEnvironment * env, void * proxy )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy * that = static_cast< UNO_proxy * >( proxy );
+ Bridge const * bridge = that->m_bridge;
+
+ assert(env == bridge->m_uno_env); (void) env;
+ SAL_INFO("bridges", "freeing binary uno proxy: " << that->m_oid);
+
+ try
+ {
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
+ ->machine));
+
+ jni->DeleteGlobalRef( that->m_javaI );
+ jni->DeleteGlobalRef( that->m_jo_oid );
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+ catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ }
+
+ bridge->release();
+#if OSL_DEBUG_LEVEL > 0
+ *reinterpret_cast<int *>(that) = 0xdeadcafe;
+#endif
+ delete that;
+}
+
+
+void UNO_proxy_acquire( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
+ that->acquire();
+}
+
+
+void UNO_proxy_release( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
+ that->release();
+}
+
+
+void UNO_proxy_dispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
+ void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
+ Bridge const * bridge = that->m_bridge;
+
+ SAL_INFO(
+ "bridges",
+ "uno->java call: " << OUString::unacquired(&member_td->pTypeName)
+ << " on oid " << that->m_oid);
+
+ try
+ {
+ switch (member_td->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription const * attrib_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ member_td );
+ com::sun::star::uno::TypeDescription attrib_holder;
+ while ( attrib_td->pBaseRef != nullptr ) {
+ attrib_holder = com::sun::star::uno::TypeDescription(
+ attrib_td->pBaseRef );
+ assert(
+ attrib_holder.get()->eTypeClass
+ == typelib_TypeClass_INTERFACE_ATTRIBUTE );
+ attrib_td = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ attrib_holder.get() );
+ }
+ typelib_InterfaceTypeDescription * iface_td = attrib_td->pInterface;
+
+ if (uno_ret == nullptr) // is setter method
+ {
+ typelib_MethodParameter param;
+ param.pTypeRef = attrib_td->pAttributeTypeRef;
+ param.bIn = true;
+ param.bOut = false;
+
+ bridge->call_java(
+ that->m_javaI, iface_td,
+ attrib_td->nIndex, 1, // get, then set method
+ bridge->getJniInfo()->m_void_type.getTypeLibType(),
+ &param, 1,
+ nullptr, uno_args, uno_exc );
+ }
+ else // is getter method
+ {
+ bridge->call_java(
+ that->m_javaI, iface_td, attrib_td->nIndex, 0,
+ attrib_td->pAttributeTypeRef,
+ nullptr, 0, // no params
+ uno_ret, nullptr, uno_exc );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_InterfaceMethodTypeDescription const * method_td =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ member_td );
+ com::sun::star::uno::TypeDescription method_holder;
+ while ( method_td->pBaseRef != nullptr ) {
+ method_holder = com::sun::star::uno::TypeDescription(
+ method_td->pBaseRef );
+ assert(
+ method_holder.get()->eTypeClass
+ == typelib_TypeClass_INTERFACE_METHOD );
+ method_td = reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ method_holder.get() );
+ }
+ typelib_InterfaceTypeDescription * iface_td = method_td->pInterface;
+
+ switch ( method_td->aBase.nPosition )
+ {
+ case 0: // queryInterface()
+ {
+ TypeDescr demanded_td(
+ *static_cast< typelib_TypeDescriptionReference ** >(
+ uno_args[ 0 ] ) );
+ if (demanded_td.get()->eTypeClass !=
+ typelib_TypeClass_INTERFACE)
+ {
+ throw BridgeRuntimeError(
+ "queryInterface() call demands an INTERFACE type!" );
+ }
+
+ uno_Interface * pInterface = nullptr;
+ (*bridge->m_uno_env->getRegisteredInterface)(
+ bridge->m_uno_env,
+ reinterpret_cast<void **>(&pInterface), that->m_oid.pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(demanded_td.get()) );
+
+ if (pInterface == nullptr)
+ {
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JNI_guarded_context jni(
+ jni_info,
+ (static_cast<JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ jni_info->get_type_info( jni, demanded_td.get() ) );
+
+ jvalue args[ 2 ];
+ args[ 0 ].l = info->m_type;
+ args[ 1 ].l = that->m_javaI;
+
+ JLocalAutoRef jo_ret(
+ jni, jni->CallStaticObjectMethodA(
+ jni_info->m_class_UnoRuntime,
+ jni_info->m_method_UnoRuntime_queryInterface,
+ args ) );
+
+ if (jni->ExceptionCheck())
+ {
+ JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() );
+ jni->ExceptionClear();
+ bridge->handle_java_exc( jni, jo_exc, *uno_exc );
+ }
+ else
+ {
+ if (jo_ret.is())
+ {
+ SAL_WARN_IF(
+ (jstring_to_oustring(
+ jni,
+ static_cast<jstring>(
+ JLocalAutoRef(
+ jni, compute_oid(jni, jo_ret.get()))
+ .get()))
+ != that->m_oid),
+ "bridges", "different oids");
+ // refcount initially 1
+ uno_Interface * pUnoI2 = new UNO_proxy(
+ jni, bridge, jo_ret.get(),
+ that->m_jo_oid, that->m_oid, info );
+
+ (*bridge->m_uno_env->registerProxyInterface)(
+ bridge->m_uno_env,
+ reinterpret_cast<void **>(&pUnoI2),
+ UNO_proxy_free, that->m_oid.pData,
+ reinterpret_cast<
+ typelib_InterfaceTypeDescription * >(
+ info->m_td.get() ) );
+
+ uno_any_construct(
+ static_cast<uno_Any *>(uno_ret), &pUnoI2,
+ demanded_td.get(), nullptr );
+ (*pUnoI2->release)( pUnoI2 );
+ }
+ else // object does not support demanded interface
+ {
+ uno_any_construct(
+ static_cast< uno_Any * >( uno_ret ),
+ nullptr, nullptr, nullptr );
+ }
+ // no exception occurred
+ *uno_exc = nullptr;
+ }
+ }
+ else
+ {
+ uno_any_construct(
+ static_cast< uno_Any * >( uno_ret ),
+ &pInterface, demanded_td.get(), nullptr );
+ (*pInterface->release)( pInterface );
+ *uno_exc = nullptr;
+ }
+ break;
+ }
+ case 1: // acquire this proxy
+ that->acquire();
+ *uno_exc = nullptr;
+ break;
+ case 2: // release this proxy
+ that->release();
+ *uno_exc = nullptr;
+ break;
+ default: // arbitrary method call
+ bridge->call_java(
+ that->m_javaI, iface_td, method_td->nIndex, 0,
+ method_td->pReturnTypeRef,
+ method_td->pParams, method_td->nParams,
+ uno_ret, uno_args, uno_exc );
+ break;
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "illegal member type description!" );
+ }
+ }
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ OUStringBuffer buf( 128 );
+ buf.append( "[jni_uno bridge error] UNO calling Java method " );
+ if (member_td->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ||
+ member_td->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE)
+ {
+ buf.append( OUString::unacquired(
+ &reinterpret_cast<
+ typelib_InterfaceMemberTypeDescription const * >(
+ member_td )->pMemberName ) );
+ }
+ buf.append( ": " );
+ buf.append( err.m_message );
+ // binary identical struct
+ ::com::sun::star::uno::RuntimeException exc(
+ buf.makeStringAndClear(),
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XInterface >() );
+ ::com::sun::star::uno::Type const & exc_type = cppu::UnoType<decltype(exc)>::get();
+ uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), nullptr );
+ SAL_INFO("bridges", exc.Message);
+ }
+ catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ // binary identical struct
+ ::com::sun::star::uno::RuntimeException exc(
+ "[jni_uno bridge error] attaching current thread to java failed!",
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XInterface >() );
+ ::com::sun::star::uno::Type const & exc_type = cppu::UnoType<decltype(exc)>::get();
+ uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), nullptr );
+ SAL_WARN("bridges", exc.Message);
+ }
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jniunoenvironmentdata.hxx b/bridges/source/jni_uno/jniunoenvironmentdata.hxx
new file mode 100644
index 000000000..39ffdeea6
--- /dev/null
+++ b/bridges/source/jni_uno/jniunoenvironmentdata.hxx
@@ -0,0 +1,54 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <jni.h>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/ref.hxx>
+
+#include "jni_info.h"
+
+namespace jni_uno {
+
+// The pContext payload of a JNI uno_Environment:
+struct JniUnoEnvironmentData {
+ JniUnoEnvironmentData(const JniUnoEnvironmentData&) = delete;
+ const JniUnoEnvironmentData& operator=(const JniUnoEnvironmentData&) = delete;
+
+ explicit JniUnoEnvironmentData(
+ rtl::Reference<jvmaccess::UnoVirtualMachine> const & theMachine):
+ machine(theMachine), info(JNI_info::get_jni_info(theMachine)),
+ asynchronousFinalizer(nullptr)
+ {}
+
+ rtl::Reference<jvmaccess::UnoVirtualMachine> const machine;
+ JNI_info const * const info;
+
+ osl::Mutex mutex;
+ jobject asynchronousFinalizer;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/nativethreadpool.cxx b/bridges/source/jni_uno/nativethreadpool.cxx
new file mode 100644
index 000000000..1d14c47bb
--- /dev/null
+++ b/bridges/source/jni_uno/nativethreadpool.cxx
@@ -0,0 +1,227 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <jvmaccess/virtualmachine.hxx>
+#include <rtl/byteseq.h>
+#include <rtl/byteseq.hxx>
+#include <rtl/ref.hxx>
+#include <sal/types.h>
+#include <uno/threadpool.h>
+
+#include <jni.h>
+
+#include <new>
+#include <utility>
+
+/* The native implementation part of
+ * jurt/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java.
+ */
+
+namespace {
+
+struct Pool {
+ Pool(rtl::Reference< jvmaccess::VirtualMachine > theVirtualMachine,
+ jmethodID theExecute, uno_ThreadPool thePool):
+ virtualMachine(std::move(theVirtualMachine)), execute(theExecute), pool(thePool) {}
+
+ rtl::Reference< jvmaccess::VirtualMachine > virtualMachine;
+ jmethodID execute;
+ uno_ThreadPool pool;
+};
+
+struct Job {
+ Job(Pool * thePool, jobject theJob): pool(thePool), job(theJob) {}
+
+ Pool * pool;
+ jobject job;
+};
+
+void throwOutOfMemory(JNIEnv * env) {
+ jclass c = env->FindClass("java/lang/OutOfMemoryError");
+ if (c != nullptr) {
+ env->ThrowNew(c, "");
+ }
+}
+
+}
+
+extern "C" {
+
+static void executeRequest(void * data) {
+ Job * job = static_cast< Job * >(data);
+ try {
+ jvmaccess::VirtualMachine::AttachGuard guard(job->pool->virtualMachine);
+ JNIEnv * env = guard.getEnvironment();
+ // Failure of the following Job.execute Java call is ignored; if that
+ // call fails, it should be due to a java.lang.Error, which is not
+ // handled well, anyway:
+ env->CallObjectMethod(job->job, job->pool->execute);
+ env->DeleteGlobalRef(job->job);
+ delete job;
+ } catch (const jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
+ //TODO: DeleteGlobalRef(job->job)
+ delete job;
+ }
+}
+
+}
+
+extern "C" SAL_JNI_EXPORT jbyteArray JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_threadId(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass) SAL_THROW_EXTERN_C()
+{
+ sal_Sequence * s = nullptr;
+ uno_getIdOfCurrentThread(&s); //TODO: out of memory
+ uno_releaseIdFromCurrentThread();
+ rtl::ByteSequence seq(s);
+ rtl_byte_sequence_release(s);
+ sal_Int32 n = seq.getLength();
+ jbyteArray a = env->NewByteArray(n);
+ // sal_Int32 and jsize are compatible here
+ if (a == nullptr) {
+ return nullptr;
+ }
+ void * p = env->GetPrimitiveArrayCritical(a, nullptr);
+ if (p == nullptr) {
+ return nullptr;
+ }
+ memcpy(p, seq.getConstArray(), n);
+ // sal_Int8 and jbyte ought to be compatible
+ env->ReleasePrimitiveArrayCritical(a, p, 0);
+ return a;
+}
+
+extern "C" SAL_JNI_EXPORT jlong JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_create(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass) SAL_THROW_EXTERN_C()
+{
+ JavaVM * vm;
+ if (env->GetJavaVM(&vm) != JNI_OK) { //TODO: no Java exception raised?
+ jclass c = env->FindClass("java/lang/RuntimeException");
+ if (c != nullptr) {
+ env->ThrowNew(c, "JNI GetJavaVM failed");
+ }
+ return 0;
+ }
+ jclass c = env->FindClass("com/sun/star/lib/uno/environments/remote/Job");
+ if (c == nullptr) {
+ return 0;
+ }
+ jmethodID execute = env->GetMethodID(c, "execute", "()Ljava/lang/Object;");
+ if (execute == nullptr) {
+ return 0;
+ }
+ try {
+ return reinterpret_cast< jlong >(new Pool(
+ new jvmaccess::VirtualMachine(vm, env->GetVersion(), false, env),
+ execute, uno_threadpool_create()));
+ } catch (const std::bad_alloc &) {
+ throwOutOfMemory(env);
+ return 0;
+ }
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_attach(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ uno_threadpool_attach(reinterpret_cast< Pool * >(pool)->pool);
+}
+
+extern "C" SAL_JNI_EXPORT jobject JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_enter(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass, jlong pool) SAL_THROW_EXTERN_C()
+{
+ jobject job;
+ uno_threadpool_enter(
+ reinterpret_cast< Pool * >(pool)->pool,
+ reinterpret_cast< void ** >(&job));
+ if (job == nullptr) {
+ return nullptr;
+ }
+ jobject ref = env->NewLocalRef(job);
+ env->DeleteGlobalRef(job);
+ return ref;
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_detach(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ uno_threadpool_detach(reinterpret_cast< Pool * >(pool)->pool);
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_putJob(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass, jlong pool, jbyteArray threadId,
+ jobject job, jboolean request, jboolean oneWay) SAL_THROW_EXTERN_C()
+{
+ void * s = env->GetPrimitiveArrayCritical(threadId, nullptr);
+ if (s == nullptr) {
+ return;
+ }
+ rtl::ByteSequence seq(
+ static_cast< sal_Int8 * >(s), env->GetArrayLength(threadId));
+ // sal_Int8 and jbyte ought to be compatible; sal_Int32 and jsize are
+ // compatible here
+ //TODO: out of memory
+ env->ReleasePrimitiveArrayCritical(threadId, s, JNI_ABORT);
+ Pool * p = reinterpret_cast< Pool * >(pool);
+ jobject ref = env->NewGlobalRef(job);
+ if (ref == nullptr) {
+ return;
+ }
+ Job * j = nullptr;
+ if (request) {
+ j = new(std::nothrow) Job(p, ref);
+ if (j == nullptr) {
+ env->DeleteGlobalRef(ref);
+ throwOutOfMemory(env);
+ return;
+ }
+ }
+ uno_threadpool_putJob(
+ p->pool, seq.getHandle(),
+ request ? static_cast< void * >(j) : static_cast< void * >(ref),
+ request ? executeRequest : nullptr, oneWay);
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_dispose(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ uno_threadpool_dispose(reinterpret_cast< Pool * >(pool)->pool);
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_destroy(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ Pool * p = reinterpret_cast< Pool * >(pool);
+ uno_threadpool_destroy(p->pool);
+ delete p;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */