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