forked from gmp/jni
		
	Initial commit.
This commit is contained in:
		
						commit
						d0d3f316ae
					
				
							
								
								
									
										27
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | Copyright (c) 2020 Tailscale & AUTHORS. All rights reserved. | ||||||
|  | 
 | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are | ||||||
|  | met: | ||||||
|  | 
 | ||||||
|  |    * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  |    * Redistributions in binary form must reproduce the above | ||||||
|  | copyright notice, this list of conditions and the following disclaimer | ||||||
|  | in the documentation and/or other materials provided with the | ||||||
|  | distribution. | ||||||
|  |    * Neither the name of Tailscale Inc. nor the names of its | ||||||
|  | contributors may be used to endorse or promote products derived from | ||||||
|  | this software without specific prior written permission. | ||||||
|  | 
 | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										3
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | # JNI | ||||||
|  | 
 | ||||||
|  | A JNI library cloned from github.com/tailscale/tailscale-android. | ||||||
							
								
								
									
										25
									
								
								gojni.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								gojni.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | __attribute__ ((visibility ("hidden"))) jint _jni_GetEnv(JavaVM *vm, JNIEnv **env, jint version); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jint _jni_AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jint _jni_DetachCurrentThread(JavaVM *vm); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jclass _jni_FindClass(JNIEnv *env, const char *name); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jthrowable _jni_ExceptionOccurred(JNIEnv *env); | ||||||
|  | __attribute__ ((visibility ("hidden"))) void _jni_ExceptionClear(JNIEnv *env); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jclass _jni_GetObjectClass(JNIEnv *env, jobject obj); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jmethodID _jni_GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jmethodID _jni_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jsize _jni_GetStringLength(JNIEnv *env, jstring str); | ||||||
|  | __attribute__ ((visibility ("hidden"))) const jchar *_jni_GetStringChars(JNIEnv *env, jstring str); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jstring _jni_NewString(JNIEnv *env, const jchar *unicodeChars, jsize len); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jboolean _jni_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jobject _jni_NewGlobalRef(JNIEnv *env, jobject obj); | ||||||
|  | __attribute__ ((visibility ("hidden"))) void _jni_DeleteGlobalRef(JNIEnv *env, jobject obj); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jint _jni_CallStaticIntMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jobject _jni_CallStaticObjectMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args); | ||||||
|  | __attribute__ ((visibility ("hidden"))) void _jni_CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jobject _jni_CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jint _jni_CallIntMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args); | ||||||
|  | __attribute__ ((visibility ("hidden"))) void _jni_CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jbyteArray _jni_NewByteArray(JNIEnv *env, jsize length); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jbyte *_jni_GetByteArrayElements(JNIEnv *env, jbyteArray arr); | ||||||
|  | __attribute__ ((visibility ("hidden"))) void _jni_ReleaseByteArrayElements(JNIEnv *env, jbyteArray arr, jbyte *elems, jint mode); | ||||||
|  | __attribute__ ((visibility ("hidden"))) jsize _jni_GetArrayLength(JNIEnv *env, jarray arr); | ||||||
							
								
								
									
										101
									
								
								jni.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								jni.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,101 @@ | ||||||
|  | #include <jni.h> | ||||||
|  | 
 | ||||||
|  | jint _jni_AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args) { | ||||||
|  | 	return (*vm)->AttachCurrentThread(vm, p_env, thr_args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jint _jni_DetachCurrentThread(JavaVM *vm) { | ||||||
|  | 	return (*vm)->DetachCurrentThread(vm); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jint _jni_GetEnv(JavaVM *vm, JNIEnv **env, jint version) { | ||||||
|  | 	return (*vm)->GetEnv(vm, (void **)env, version); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jclass _jni_FindClass(JNIEnv *env, const char *name) { | ||||||
|  | 	return (*env)->FindClass(env, name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jthrowable _jni_ExceptionOccurred(JNIEnv *env) { | ||||||
|  | 	return (*env)->ExceptionOccurred(env); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _jni_ExceptionClear(JNIEnv *env) { | ||||||
|  | 	(*env)->ExceptionClear(env); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jclass _jni_GetObjectClass(JNIEnv *env, jobject obj) { | ||||||
|  | 	return (*env)->GetObjectClass(env, obj); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jmethodID _jni_GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) { | ||||||
|  | 	return (*env)->GetMethodID(env, clazz, name, sig); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jmethodID _jni_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) { | ||||||
|  | 	return (*env)->GetStaticMethodID(env, clazz, name, sig); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jsize _jni_GetStringLength(JNIEnv *env, jstring str) { | ||||||
|  | 	return (*env)->GetStringLength(env, str); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const jchar *_jni_GetStringChars(JNIEnv *env, jstring str) { | ||||||
|  | 	return (*env)->GetStringChars(env, str, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jstring _jni_NewString(JNIEnv *env, const jchar *unicodeChars, jsize len) { | ||||||
|  | 	return (*env)->NewString(env, unicodeChars, len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jboolean _jni_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2) { | ||||||
|  | 	return (*env)->IsSameObject(env, ref1, ref2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jobject _jni_NewGlobalRef(JNIEnv *env, jobject obj) { | ||||||
|  | 	return (*env)->NewGlobalRef(env, obj); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _jni_DeleteGlobalRef(JNIEnv *env, jobject obj) { | ||||||
|  | 	(*env)->DeleteGlobalRef(env, obj); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _jni_CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args) { | ||||||
|  | 	(*env)->CallStaticVoidMethodA(env, cls, method, args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jint _jni_CallStaticIntMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args) { | ||||||
|  | 	return (*env)->CallStaticIntMethodA(env, cls, method, args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jobject _jni_CallStaticObjectMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args) { | ||||||
|  | 	return (*env)->CallStaticObjectMethodA(env, cls, method, args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jobject _jni_CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args) { | ||||||
|  | 	return (*env)->CallObjectMethodA(env, obj, method, args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jint _jni_CallIntMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args) { | ||||||
|  | 	return (*env)->CallIntMethodA(env, obj, method, args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _jni_CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args) { | ||||||
|  | 	(*env)->CallVoidMethodA(env, obj, method, args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jbyteArray _jni_NewByteArray(JNIEnv *env, jsize length) { | ||||||
|  | 	return (*env)->NewByteArray(env, length); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jbyte *_jni_GetByteArrayElements(JNIEnv *env, jbyteArray arr) { | ||||||
|  | 	return (*env)->GetByteArrayElements(env, arr, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _jni_ReleaseByteArrayElements(JNIEnv *env, jbyteArray arr, jbyte *elems, jint mode) { | ||||||
|  | 	(*env)->ReleaseByteArrayElements(env, arr, elems, mode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jsize _jni_GetArrayLength(JNIEnv *env, jarray arr) { | ||||||
|  | 	return (*env)->GetArrayLength(env, arr); | ||||||
|  | } | ||||||
							
								
								
									
										261
									
								
								jni.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								jni.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,261 @@ | ||||||
|  | // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
 | ||||||
|  | // Use of this source code is governed by a BSD-style
 | ||||||
|  | // license that can be found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package jni | ||||||
|  | 
 | ||||||
|  | // Package jni implements various helper functions for communicating with the Android JVM
 | ||||||
|  | // though JNI.
 | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"runtime" | ||||||
|  | 	"unicode/utf16" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | #cgo CFLAGS: -Wall | ||||||
|  | 
 | ||||||
|  | #include <jni.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | 
 | ||||||
|  | #include "gojni.h" | ||||||
|  | */ | ||||||
|  | import "C" | ||||||
|  | 
 | ||||||
|  | type JVM struct { | ||||||
|  | 	jvm *C.JavaVM | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Env struct { | ||||||
|  | 	env *C.JNIEnv | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type ( | ||||||
|  | 	Class     C.jclass | ||||||
|  | 	Object    C.jobject | ||||||
|  | 	MethodID  C.jmethodID | ||||||
|  | 	String    C.jstring | ||||||
|  | 	ByteArray C.jbyteArray | ||||||
|  | 	Value     uint64 // All JNI types fit into 64-bits.
 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func JVMFor(jvmPtr uintptr) JVM { | ||||||
|  | 	return JVM{ | ||||||
|  | 		jvm: (*C.JavaVM)(unsafe.Pointer(jvmPtr)), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func EnvFor(envPtr uintptr) Env { | ||||||
|  | 	return Env{ | ||||||
|  | 		env: (*C.JNIEnv)(unsafe.Pointer(envPtr)), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Do invokes a function with a temporary JVM environment. The
 | ||||||
|  | // environment is not valid after the function returns.
 | ||||||
|  | func Do(vm JVM, f func(env Env) error) error { | ||||||
|  | 	runtime.LockOSThread() | ||||||
|  | 	defer runtime.UnlockOSThread() | ||||||
|  | 	var env *C.JNIEnv | ||||||
|  | 	if res := C._jni_GetEnv(vm.jvm, &env, C.JNI_VERSION_1_6); res != C.JNI_OK { | ||||||
|  | 		if res != C.JNI_EDETACHED { | ||||||
|  | 			panic(fmt.Errorf("JNI GetEnv failed with error %d", res)) | ||||||
|  | 		} | ||||||
|  | 		if C._jni_AttachCurrentThread(vm.jvm, &env, nil) != C.JNI_OK { | ||||||
|  | 			panic(errors.New("runInJVM: AttachCurrentThread failed")) | ||||||
|  | 		} | ||||||
|  | 		defer C._jni_DetachCurrentThread(vm.jvm) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return f(Env{env}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func varArgs(args []Value) *C.jvalue { | ||||||
|  | 	if len(args) == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return (*C.jvalue)(unsafe.Pointer(&args[0])) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func IsSameObject(e Env, ref1, ref2 Object) bool { | ||||||
|  | 	same := C._jni_IsSameObject(e.env, C.jobject(ref1), C.jobject(ref2)) | ||||||
|  | 	return same == C.JNI_TRUE | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func CallStaticIntMethod(e Env, cls Class, method MethodID, args ...Value) (int, error) { | ||||||
|  | 	res := C._jni_CallStaticIntMethodA(e.env, C.jclass(cls), C.jmethodID(method), varArgs(args)) | ||||||
|  | 	return int(res), exception(e) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func CallStaticVoidMethod(e Env, cls Class, method MethodID, args ...Value) error { | ||||||
|  | 	C._jni_CallStaticVoidMethodA(e.env, C.jclass(cls), C.jmethodID(method), varArgs(args)) | ||||||
|  | 	return exception(e) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func CallVoidMethod(e Env, obj Object, method MethodID, args ...Value) error { | ||||||
|  | 	C._jni_CallVoidMethodA(e.env, C.jobject(obj), C.jmethodID(method), varArgs(args)) | ||||||
|  | 	return exception(e) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func CallStaticObjectMethod(e Env, cls Class, method MethodID, args ...Value) (Object, error) { | ||||||
|  | 	res := C._jni_CallStaticObjectMethodA(e.env, C.jclass(cls), C.jmethodID(method), varArgs(args)) | ||||||
|  | 	return Object(res), exception(e) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func CallObjectMethod(e Env, obj Object, method MethodID, args ...Value) (Object, error) { | ||||||
|  | 	res := C._jni_CallObjectMethodA(e.env, C.jobject(obj), C.jmethodID(method), varArgs(args)) | ||||||
|  | 	return Object(res), exception(e) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func CallIntMethod(e Env, obj Object, method MethodID, args ...Value) (int32, error) { | ||||||
|  | 	res := C._jni_CallIntMethodA(e.env, C.jobject(obj), C.jmethodID(method), varArgs(args)) | ||||||
|  | 	return int32(res), exception(e) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetByteArrayElements returns the contents of the array.
 | ||||||
|  | func GetByteArrayElements(e Env, jarr ByteArray) []byte { | ||||||
|  | 	size := C._jni_GetArrayLength(e.env, C.jarray(jarr)) | ||||||
|  | 	elems := C._jni_GetByteArrayElements(e.env, C.jbyteArray(jarr)) | ||||||
|  | 	defer C._jni_ReleaseByteArrayElements(e.env, C.jbyteArray(jarr), elems, 0) | ||||||
|  | 	backing := (*(*[1 << 30]byte)(unsafe.Pointer(elems)))[:size:size] | ||||||
|  | 	s := make([]byte, len(backing)) | ||||||
|  | 	copy(s, backing) | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewByteArray allocates a Java byte array with the content. It
 | ||||||
|  | // panics if the allocation fails.
 | ||||||
|  | func NewByteArray(e Env, content []byte) ByteArray { | ||||||
|  | 	jarr := C._jni_NewByteArray(e.env, C.jsize(len(content))) | ||||||
|  | 	if jarr == 0 { | ||||||
|  | 		panic(fmt.Errorf("jni: NewByteArray(%d) failed", len(content))) | ||||||
|  | 	} | ||||||
|  | 	elems := C._jni_GetByteArrayElements(e.env, jarr) | ||||||
|  | 	defer C._jni_ReleaseByteArrayElements(e.env, jarr, elems, 0) | ||||||
|  | 	backing := (*(*[1 << 30]byte)(unsafe.Pointer(elems)))[:len(content):len(content)] | ||||||
|  | 	copy(backing, content) | ||||||
|  | 	return ByteArray(jarr) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ClassLoader returns a reference to the Java ClassLoader associated
 | ||||||
|  | // with obj.
 | ||||||
|  | func ClassLoaderFor(e Env, obj Object) Object { | ||||||
|  | 	cls := GetObjectClass(e, obj) | ||||||
|  | 	getClassLoader := GetMethodID(e, cls, "getClassLoader", "()Ljava/lang/ClassLoader;") | ||||||
|  | 	clsLoader, err := CallObjectMethod(e, Object(obj), getClassLoader) | ||||||
|  | 	if err != nil { | ||||||
|  | 		// Class.getClassLoader should never fail.
 | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	return Object(clsLoader) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // LoadClass invokes the underlying ClassLoader's loadClass method and
 | ||||||
|  | // returns the class.
 | ||||||
|  | func LoadClass(e Env, loader Object, class string) (Class, error) { | ||||||
|  | 	cls := GetObjectClass(e, loader) | ||||||
|  | 	loadClass := GetMethodID(e, cls, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;") | ||||||
|  | 	name := JavaString(e, class) | ||||||
|  | 	loaded, err := CallObjectMethod(e, loader, loadClass, Value(name)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	return Class(loaded), exception(e) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // exception returns an error corresponding to the pending
 | ||||||
|  | // exception, and clears it. exceptionError returns nil if no
 | ||||||
|  | // exception is pending.
 | ||||||
|  | func exception(e Env) error { | ||||||
|  | 	thr := C._jni_ExceptionOccurred(e.env) | ||||||
|  | 	if thr == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	C._jni_ExceptionClear(e.env) | ||||||
|  | 	cls := GetObjectClass(e, Object(thr)) | ||||||
|  | 	toString := GetMethodID(e, cls, "toString", "()Ljava/lang/String;") | ||||||
|  | 	msg, err := CallObjectMethod(e, Object(thr), toString) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return errors.New(GoString(e, String(msg))) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetObjectClass returns the Java Class for an Object.
 | ||||||
|  | func GetObjectClass(e Env, obj Object) Class { | ||||||
|  | 	if obj == 0 { | ||||||
|  | 		panic("null object") | ||||||
|  | 	} | ||||||
|  | 	cls := C._jni_GetObjectClass(e.env, C.jobject(obj)) | ||||||
|  | 	if err := exception(e); err != nil { | ||||||
|  | 		// GetObjectClass should never fail.
 | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	return Class(cls) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetStaticMethodID returns the id for a static method. It panics if the method
 | ||||||
|  | // wasn't found.
 | ||||||
|  | func GetStaticMethodID(e Env, cls Class, name, signature string) MethodID { | ||||||
|  | 	mname := C.CString(name) | ||||||
|  | 	defer C.free(unsafe.Pointer(mname)) | ||||||
|  | 	msig := C.CString(signature) | ||||||
|  | 	defer C.free(unsafe.Pointer(msig)) | ||||||
|  | 	m := C._jni_GetStaticMethodID(e.env, C.jclass(cls), mname, msig) | ||||||
|  | 	if err := exception(e); err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	return MethodID(m) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetMethodID returns the id for a method. It panics if the method
 | ||||||
|  | // wasn't found.
 | ||||||
|  | func GetMethodID(e Env, cls Class, name, signature string) MethodID { | ||||||
|  | 	mname := C.CString(name) | ||||||
|  | 	defer C.free(unsafe.Pointer(mname)) | ||||||
|  | 	msig := C.CString(signature) | ||||||
|  | 	defer C.free(unsafe.Pointer(msig)) | ||||||
|  | 	m := C._jni_GetMethodID(e.env, C.jclass(cls), mname, msig) | ||||||
|  | 	if err := exception(e); err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	return MethodID(m) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewGlobalRef(e Env, obj Object) Object { | ||||||
|  | 	return Object(C._jni_NewGlobalRef(e.env, C.jobject(obj))) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func DeleteGlobalRef(e Env, obj Object) { | ||||||
|  | 	C._jni_DeleteGlobalRef(e.env, C.jobject(obj)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // JavaString converts the string to a JVM jstring.
 | ||||||
|  | func JavaString(e Env, str string) String { | ||||||
|  | 	if str == "" { | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  | 	utf16Chars := utf16.Encode([]rune(str)) | ||||||
|  | 	res := C._jni_NewString(e.env, (*C.jchar)(unsafe.Pointer(&utf16Chars[0])), C.int(len(utf16Chars))) | ||||||
|  | 	return String(res) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GoString converts the JVM jstring to a Go string.
 | ||||||
|  | func GoString(e Env, str String) string { | ||||||
|  | 	if str == 0 { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	strlen := C._jni_GetStringLength(e.env, C.jstring(str)) | ||||||
|  | 	chars := C._jni_GetStringChars(e.env, C.jstring(str)) | ||||||
|  | 	var utf16Chars []uint16 | ||||||
|  | 	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&utf16Chars)) | ||||||
|  | 	hdr.Data = uintptr(unsafe.Pointer(chars)) | ||||||
|  | 	hdr.Cap = int(strlen) | ||||||
|  | 	hdr.Len = int(strlen) | ||||||
|  | 	utf8 := utf16.Decode(utf16Chars) | ||||||
|  | 	return string(utf8) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user