This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
cryptic/bindings/java/wrapper_top.c

1032 lines
35 KiB
C

#include <glib.h>
#include <glib-object.h>
#include <cryptic/cryptic.h>
#include <config.h>
#include <jni.h>
#include "com_entrouvert_cryptic_CrypticJNI.h"
#include <string.h>
#include "../ghashtable.h"
#include "../../cryptic/utils.h"
#define CRYPTIC_ROOT "com/entrouvert/cryptic/"
#define check_exception (*env)->ExceptionCheck(env)
#define g_return_val_if_exception(value) if ((*env)->ExceptionCheck(env)) return (value);
#define g_return_if_exception() if ((*env)->ExceptionCheck(env)) return;
#define convert_jlong_to_gobject(value) ((GObject*)(ptrdiff_t)value)
#define g_error_if_fail(value) { if (!(value)) { g_on_error_query("CrypticJNI"); } }
#define PTR_TO_JLONG(x) (jlong)((ptrdiff_t)x)
static GQuark cryptic_wrapper_key = 0;
typedef int (*Converter)(JNIEnv *env, void *from, jobject *to);
typedef int *(*OutConverter)(JNIEnv *env, jobject from, gpointer *to);
/* Static declarations */
G_GNUC_UNUSED static int gpointer_equal(const gpointer p1, const gpointer p2);
G_GNUC_UNUSED static int new_object_with_gobject(JNIEnv *env, GObject *obj, const char *clsName, jobject *jobj);
G_GNUC_UNUSED static int jstring_to_local_string(JNIEnv *env, jstring jstr, const char **str);
G_GNUC_UNUSED static void release_local_string(JNIEnv *env, jstring str, const char *utf_str);
G_GNUC_UNUSED static int get_jlong_field(JNIEnv *env, jobject obj, const char *field, jlong *dest);
G_GNUC_UNUSED static jclass get_jclass_by_name(JNIEnv *env, const char *name);
G_GNUC_UNUSED static int get_array_element(JNIEnv *env, jobjectArray arr, jsize i, jobject *dest);
G_GNUC_UNUSED static int set_array_element(JNIEnv *env, jobjectArray arr, jsize i, jobject value);
G_GNUC_UNUSED static int get_array_size(JNIEnv *env, jobjectArray arr, jsize *dest);
G_GNUC_UNUSED static int create_object_array(JNIEnv *env, const char *clsName, jsize size, jobjectArray *jarr);
G_GNUC_UNUSED static jobject get_shadow_object(JNIEnv *env, GObject *obj);
G_GNUC_UNUSED static void set_shadow_object(JNIEnv *env, GObject *obj, jobject shadow_object);
G_GNUC_UNUSED static void exception(JNIEnv *env, const char *message);
G_GNUC_UNUSED static int string_to_jstring(JNIEnv *env, const char* str, jstring *jstr);
G_GNUC_UNUSED static int string_to_jstring_and_free(JNIEnv *env, char* str, jstring *jstr);
G_GNUC_UNUSED static int jstring_to_string(JNIEnv *env, jstring jstr, char **str);
////G_GNUC_UNUSED static int xml_node_to_jstring(JNIEnv *env, xmlNode *xmlnode, jstring *jstr);
////G_GNUC_UNUSED static int jstring_to_xml_node(JNIEnv *env, jstring jstr, xmlNode **xmlnode);
G_GNUC_UNUSED static int gobject_to_jobject_aux(JNIEnv *env, GObject *obj, gboolean doRef, jobject *job);
G_GNUC_UNUSED static int gobject_to_jobject(JNIEnv *env, GObject *obj, jobject *jobj);
G_GNUC_UNUSED static int gobject_to_jobject_and_ref(JNIEnv *env, GObject *obj, jobject *jobj);
G_GNUC_UNUSED static int jobject_to_gobject(JNIEnv *env, jobject obj, GObject **gobj);
G_GNUC_UNUSED static int jobject_to_gobject_noref(JNIEnv *env, jobject obj, GObject **gobj);
G_GNUC_UNUSED static void free_glist(GList **list, GFunc free_function);
G_GNUC_UNUSED static int get_list(JNIEnv *env, const char *clsName, const GList *list, Converter convert, jobjectArray *jarr);
G_GNUC_UNUSED static int set_list(JNIEnv *env, GList **list, jobjectArray jarr, GFunc free_function, OutConverter convert);
G_GNUC_UNUSED static int remove_from_list(JNIEnv *env,GList **list,jobject obj,GFunc free_function,GCompareFunc compare,OutConverter convert);
G_GNUC_UNUSED static int add_to_list(JNIEnv* env, GList** list, jobject obj, OutConverter convert);
G_GNUC_UNUSED static int get_hash(JNIEnv *env, char *clsName, GHashTable *hashtable, Converter convert, jobjectArray *jarr);
G_GNUC_UNUSED static int set_hash_of_objects(JNIEnv *env, GHashTable *hashtable, jobjectArray jarr);
G_GNUC_UNUSED static int set_hash_of_strings(JNIEnv *env, GHashTable *hashtable, jobjectArray jarr);
G_GNUC_UNUSED static int remove_from_hash(JNIEnv *env, GHashTable *hashtable, jstring jkey);
G_GNUC_UNUSED static int add_to_hash(JNIEnv *env, GHashTable *hashtable, jstring jkey, jobject jvalue, OutConverter convert, GFunc free_function);
G_GNUC_UNUSED static int get_hash_by_name(JNIEnv *env, GHashTable *hashtable, jstring jkey, Converter convert, jobject *jvalue);
#define get_list_of_strings(env,list,jarr) get_list(env,"java/lang/String",list,(Converter)string_to_jstring,jarr)
////#define get_list_of_xml_nodes(env,list,jarr) get_list(env,"java/lang/String",list,(Converter)xml_node_to_jstring,jarr)
#define get_list_of_objects(env,list,jarr) get_list(env,"java/lang/Object",list,(Converter)gobject_to_jobject_and_ref,jarr)
#define set_list_of_strings(env,list,jarr) set_list(env,list,jarr,(GFunc)g_free,(OutConverter)jstring_to_string)
////#define set_list_of_xml_nodes(env,list,jarr) set_list(env,list,jarr,(GFunc)xmlFreeNode,(OutConverter)jstring_to_xml_node)
#define set_list_of_objects(env,list,jarr) set_list(env,list,jarr,(GFunc)g_object_unref,(OutConverter)jobject_to_gobject)
// remove_from_list_of_strings is now implemented directly
//#define remove_from_list_of_strings(env,list,obj) remove_from_list(env,list,obj,(GFunc)g_free,(GCompareFunc)strcmp,(OutConverter)jstring_to_local_string)
//#define remove_from_list_of_xml_nodes(env,list,obj) remove_from_list(env,list,obj,(GFunc)xmlFreeNode,(GCompareFunc)strcmp,(OutConverter)jstring_to_xml_node)
#define remove_from_list_of_objects(env,list,obj) remove_from_list(env,list,obj,(GFunc)g_object_unref,(GCompareFunc)gpointer_equal,(OutConverter)jobject_to_gobject_noref)
#define add_to_list_of_strings(env,list,obj) add_to_list(env,list,obj,(OutConverter)jstring_to_string)
////#define add_to_list_of_xml_nodes(env,list,obj) add_to_list(env,list,obj,(OutConverter)jstring_to_xml_node)
// Use jobject_to_gobject_for_list because ref count must be augmented by one when inserted inside a list
#define add_to_list_of_objects(env,list,obj) add_to_list(env,list,obj,(OutConverter)jobject_to_gobject)
#define get_hash_of_strings(env,hash,jarr) get_hash(env,"java/lang/String",hash,(Converter)string_to_jstring, jarr)
#define get_hash_of_objects(env,hash,jarr) get_hash(env,"java/lang/Object",hash,(Converter)gobject_to_jobject_and_ref, jarr)
//#define remove_from_hash_of_strings(env,hash,key) remove_from_hash(env,hash,key)
//#define remove_from_hash_of_objects(env,hash,key) remove_from_hash(env,hash,key)
#define add_to_hash_of_strings(env,hash,key,obj) add_to_hash(env,hash,key,obj,(OutConverter)jstring_to_string,(GFunc)g_free)
#define add_to_hash_of_objects(env,hash,key,obj) add_to_hash(env,hash,key,obj,(OutConverter)jobject_to_gobject,(GFunc)g_object_unref)
//#define get_hash_of_strings_by_name(end,hash,key) get_hash_by_name(end,hash,key,(Converter)string_to_jstring)
//#define get_hash_of_objects_by_name(end,hash,key) get_hash_by_name(end,hash,key,(Converter)gobject_to_jobject_and_ref)
G_GNUC_UNUSED static void throw_by_name(JNIEnv *env, const char *name, const char *msg);
G_GNUC_UNUSED static int bignum_to_jstring(JNIEnv *env, BIGNUM *bn, jstring *jstr);
G_GNUC_UNUSED static int jstring_to_bignum(JNIEnv *env, jstring jstr, BIGNUM **bn);
//G_GNUC_UNUSED static int set_list_of_bn(JNIEnv *env, BIGNUM ***list, jobjectArray jarr);
G_GNUC_UNUSED static BIGNUM** set_list_of_bn(JNIEnv *env, jobjectArray jarr);
G_GNUC_UNUSED static int get_list_of_bn(JNIEnv *env, BIGNUM **list, jobjectArray *jarr);
#define get_list_of_bignum(env,list,jarr) get_list(env,"java/lang/String",list,(Converter)bignum_to_jstring,jarr)
#define set_list_of_bignum(env,list,jarr) set_list(env,list,jarr,(GFunc)g_free,(OutConverter)jstring_to_bignum)
#define add_to_list_of_bignum(env,list,obj) add_to_list(env,list,obj,(OutConverter)jstring_to_bignum)
#define get_hash_of_bignum(env,hash,jarr) get_hash(env,"java/lang/String",hash,(Converter)bignum_to_jstring, jarr)
static int int_to_jint(JNIEnv *env, int i, jint *ji);
//static int jint_to_int(JNIEnv *env, jint ji, int *i);
//G_GNUC_UNUSED static int set_list_of_int(JNIEnv *env, int **list, jobjectArray jarr);
G_GNUC_UNUSED static int* set_list_of_int(JNIEnv *env, jobjectArray jarr);
G_GNUC_UNUSED static int get_list_of_int(JNIEnv *env, int *list, jobjectArray *jarr);
static jint extractInt(JNIEnv *env, jobject arg);
#define add_to_list_of_int(env,list,obj) add_to_list(env,list,obj,(OutConverter)jint_to_int)
#define get_hash_of_int(env,hash,jarr) get_hash(env,"java/lang/Integer",hash,(Converter)int_to_jint, jarr)
static int
bignum_to_jstring(JNIEnv *env, BIGNUM *bn, jstring *jstr)
{
if (bn) {
char *hex = BN_bn2hex(bn);
*jstr = (*env)->NewStringUTF(env, hex);
OPENSSL_free(hex);
cryptic_return_val_if_fail(jstr, 0);
} else {
*jstr = NULL;
}
return 1;
}
static int
get_list_of_bn(JNIEnv *env, BIGNUM **list, jobjectArray *jarr) {
jsize i;
jclass cls;
g_error_if_fail (env);
int size = 0;
while(list[size] != NULL) size++;
cls = get_jclass_by_name(env, "java/lang/String");
cryptic_return_val_if_fail(cls, 0);
cryptic_return_val_if_fail(create_object_array(env, "java/lang/String", size, jarr), 0);
for (i=0; i<size; i++) {
jobject item;
bignum_to_jstring(env,list[i],&item);
cryptic_return_val_if_fail(set_array_element(env, *jarr, i, item), 0);
}
return 1;
}
static int
jstring_to_bignum(JNIEnv *env, jstring jstr, BIGNUM **bn) {
const char *local_str = NULL;
int r;
cryptic_return_val_if_fail(jstring_to_local_string(env, jstr, &local_str), 0);
if (local_str) {
if(local_str[0] == '-'){
r = BN_hex2bn(bn, local_str);
BN_set_negative(*bn,1);
}else{
r = BN_hex2bn(bn, local_str);
}
release_local_string(env, jstr, local_str);
if (r<0 || *bn == NULL) {
return 0;
}
} else {
*bn = NULL;
}
return 1;
}
/*static BIGNUM**
set_list_of_bn(JNIEnv *env, jobjectArray jarr) {
jobject element = NULL;
jsize size = 0;
jsize i = 0;
BIGNUM **list;
printf("set_list_of_bn\n");
g_error_if_fail (list && env);
if (jarr) {
if (! get_array_size(env, jarr, &size)){
return 0;
}
list = NULL;
list = (BIGNUM***) g_malloc0(sizeof(BIGNUM***));
list[0] = NULL;
list[0] = (BIGNUM**) g_malloc0(size*sizeof(BIGNUM**));
for (i=0; i<size; i++){
list[0][i] = NULL;
if (! get_array_element(env, jarr, i, &element)){
return 0;
}
jstring_to_bignum(env,element,&list[0][i]);
cryptic_print_bn("",list[0][i]);
}
}
return 1;
}*/
static BIGNUM**
set_list_of_bn(JNIEnv *env, jobjectArray jarr) {
jobject element = NULL;
jsize size = 0;
jsize i = 0;
BIGNUM **list;
g_error_if_fail (list && env);
if (jarr) {
if (! get_array_size(env, jarr, &size)){
return 0;
}
list = NULL;
list = (BIGNUM**) g_malloc0(size*sizeof(BIGNUM**));
for (i=0; i<size; i++){
list[i] = NULL;
if (! get_array_element(env, jarr, i, &element)){
return 0;
}
jstring_to_bignum(env,element,&list[i]);
}
}
return list;
}
static int
int_to_jint(JNIEnv *env, int i, jint *ji)
{
return 1;
}
static int
get_list_of_int(JNIEnv *env, int *list, jobjectArray *jarr) {
jsize i;
jclass cls;
g_error_if_fail (env);
int size = 0;
while(&list[size] != NULL) size++;
cls = get_jclass_by_name(env, "java/lang/Integer");
cryptic_return_val_if_fail(cls, 0);
cryptic_return_val_if_fail(create_object_array(env, "java/lang/Integer", size, jarr), 0);
for (i=0; i<size; i++) {
jint item;
int_to_jint(env,list[i],&item);
cryptic_return_val_if_fail(set_array_element(env, *jarr, i, &item), 0);
}
return 1;
}
/*static int
jint_to_int(JNIEnv *env, jint ji, int *i) {
return 1;
}*/
static int*
set_list_of_int(JNIEnv *env, jobjectArray jarr) {
jobject element = NULL;
jsize size = 0;
jsize i = 0;
int* list;
g_error_if_fail (list && env);
if (jarr) {
if (! get_array_size(env, jarr, &size)){
return 0;
}
list = NULL;
list = NULL;
list = (int*) g_malloc0(size*sizeof(int*));
for (i=0; i<size; i++){
if (! get_array_element(env, jarr, i, &element)){
return 0;
}
list[i] = (int) element;
}
}
return list;
}
static jint
extractInt(JNIEnv *env, jobject arg)
{
jclass argClass = (*env)->GetObjectClass(env, arg);
jmethodID ajf = (*env)->GetMethodID(env, argClass, "intValue", "()I");
return (*env)->CallIntMethod(env, arg, ajf);
}
static int
gpointer_equal(const gpointer p1, const gpointer p2) {
return p1 != p2;
}
static int
new_object_with_gobject(JNIEnv *env, GObject *obj, const char *clsName, jobject *jobj) {
jclass cls;
jmethodID mid;
g_error_if_fail(env && clsName && obj && G_IS_OBJECT(obj));
cryptic_return_val_if_fail((cls = (*env)->FindClass(env, clsName)), 0);
cryptic_return_val_if_fail((mid = (*env)->GetMethodID(env, cls, "<init>", "(J)V")), 0);
cryptic_return_val_if_fail((*jobj = (*env)->NewObject(env, cls, mid, PTR_TO_JLONG(obj))), 0);
return 1;
}
/** Convert a java string to a jstring */
static int
jstring_to_local_string(JNIEnv *env, jstring jstr, const char **str)
{
g_error_if_fail(env);
if (jstr) {
*str = (*env)->GetStringUTFChars(env, jstr, NULL);
cryptic_return_val_if_fail(*str, 0);
} else {
*str = NULL;
}
return 1;
}
/** Release a local string. IT'S MANDATORY TO CALL THIS !!! */
static void
release_local_string(JNIEnv *env, jstring str, const char *utf_str) {
g_error_if_fail(env);
if (utf_str && str) {
(*env)->ReleaseStringUTFChars(env, str, utf_str);
}
}
static int
get_jlong_field(JNIEnv *env, jobject obj, const char *field, jlong *dest)
{
jclass cls;
jfieldID fid;
cls = (*env)->GetObjectClass(env, obj);
cryptic_return_val_if_fail(cls, 0);
fid = (*env)->GetFieldID(env, cls, field, "J");
cryptic_return_val_if_fail(fid, 0);
*dest = (*env)->GetLongField(env, obj, fid);
g_return_val_if_exception(0);
return 1;
}
static jclass
get_jclass_by_name(JNIEnv *env, const char *name) {
return (*env)->FindClass(env,name);
}
static int
get_array_element(JNIEnv *env, jobjectArray arr, jsize i, jobject *dest) {
*dest = (*env)->GetObjectArrayElement(env, arr, i);
cryptic_return_val_if_fail(! (*env)->ExceptionCheck(env), 0);
return 1;
}
static int
set_array_element(JNIEnv *env, jobjectArray arr, jsize i, jobject value) {
(*env)->SetObjectArrayElement(env, arr, i, value);
g_return_val_if_exception(0);
return 1;
}
static int
get_array_size(JNIEnv *env, jobjectArray jarr, jsize *dest) {
*dest = (*env)->GetArrayLength(env, jarr);
g_return_val_if_exception(0);
return 1;
}
static int
create_object_array(JNIEnv *env, const char *clsName, jsize size, jobjectArray *jarr) {
jclass cls;
g_error_if_fail(env && clsName && jarr);
cls = get_jclass_by_name(env, clsName);
cryptic_return_val_if_fail(cls, 0);
*jarr = (*env)->NewObjectArray(env, size, get_jclass_by_name(env, clsName), NULL);
cryptic_return_val_if_fail(*jarr, 0);
return 1;
}
static int nullWeakRef(JNIEnv *env, jweak weakRef) {
return weakRef && (*env)->IsSameObject(env, weakRef, NULL);
}
/** Return the shadow object associated with the gobject.
* If the weak global reference is dead, frees it.
* If not shadow object is present, return NULL. */
static jobject
get_shadow_object(JNIEnv *env, GObject *obj) {
jweak weakRef;
g_error_if_fail (obj && env);
weakRef = (jweak)g_object_get_qdata(obj, cryptic_wrapper_key);
if (weakRef == NULL) {
return NULL;
} else if (nullWeakRef(env, weakRef)) {
/** Remove null weak ref. */
(*env)->DeleteWeakGlobalRef(env, weakRef);
g_object_set_qdata(obj, cryptic_wrapper_key, NULL);
return NULL;
} else {
return (*env)->NewLocalRef(env, weakRef);
}
}
/** Sets the java shadow object associated with the GObject obj.
* If a shadow object is already present, frees its weak global reference.
* Replacing a non NULL weak global reference by another one should not happend.
* It means that two java shadow object for the same GObject exist at the same time
*/
static void
set_shadow_object(JNIEnv *env, GObject *obj, jobject shadow_object) {
jweak weakRef;
jweak old_weakRef;
g_error_if_fail(obj && env);
old_weakRef = (jweak)g_object_get_qdata(obj, cryptic_wrapper_key);
if (old_weakRef) {
if (shadow_object != NULL && ! (*env)->IsSameObject(env, old_weakRef, NULL)) {
g_warning("remplacement d'un shadow object non nulle par un shadow object non nulle %p %p", shadow_object, old_weakRef);
}
(*env)->DeleteWeakGlobalRef(env, old_weakRef);
}
g_object_set_qdata(obj, cryptic_wrapper_key, NULL);
if (shadow_object) {
weakRef = (*env)->NewWeakGlobalRef(env, shadow_object);
g_object_set_qdata(obj, cryptic_wrapper_key, weakRef);
}
}
/** Throw a new RuntimeException containing this message. */
static void
exception(JNIEnv *env, const char *message) {
jclass cls = (*env)->FindClass(env, "java/lang/RuntimeException");
if (cls != NULL) {
throw_by_name(env, "java/lang/RuntimeException", message);
}
(*env)->DeleteLocalRef(env, cls);
}
/* Conversion fonctions */
/** Convert a C string to java string. NULL is a valid C string giving a null
* java object. */
static int
string_to_jstring(JNIEnv *env, const char* str, jstring *jstr) {
if (str) {
*jstr = (*env)->NewStringUTF(env, str);
cryptic_return_val_if_fail(jstr, 0);
} else {
*jstr = NULL;
}
return 1;
}
/** Convert a string to a java string then free it. Don't frees it
* if conversion failed. */
static int
string_to_jstring_and_free(JNIEnv *env, char* str, jstring *jstr) {
cryptic_return_val_if_fail(string_to_jstring(env, str, jstr), 0);
if (str)
g_free(str);
return 1;
}
/** Convert a jstring to a C string and copy it. Returned string is owner by the caller.*/
static int
jstring_to_string(JNIEnv *env, jstring jstr, char **str) {
const char *local_str = NULL;
cryptic_return_val_if_fail(jstring_to_local_string(env, jstr, &local_str), 0);
if (local_str) {
cryptic_assign_string(*str, local_str);
release_local_string(env, jstr, local_str);
if (!str) {
/* Maybe launch a OutOfMemoryException. */
exception(env, "could not alloc a copy of a jstring");
return 0;
}
} else {
*str = NULL;
}
return 1;
}
/* xmlNode handling */
/**
static int
xml_node_to_jstring(JNIEnv *env, xmlNode *xmlnode, jstring *jstr) {
xmlOutputBufferPtr buf = NULL;
g_error_if_fail(env);
if (! xmlnode) {
*jstr = NULL;
return 1;
}
buf = xmlAllocOutputBuffer(NULL);
if (buf) {
int ret = 1;
xmlNodeDumpOutput(buf, NULL, xmlnode, 0, 1, NULL);
xmlOutputBufferFlush(buf);
xmlChar *str = NULL;
if (buf->conv == NULL) {
str = buf->buffer->content;
} else {
str = buf->conv->content;
}
ret = string_to_jstring(env, (char*)str, jstr);
xmlOutputBufferClose(buf);
return ret;
} else {
exception(env, "could not alloc an xml output buffer");
return 0;
}
return 1;
}
**/
/** Convert a java string to an xml node. Return 0 if it failed with an exception
* throwed. */
/**
static int
jstring_to_xml_node(JNIEnv *env, jstring jstr, xmlNode **xmlnode) {
xmlDoc *doc = NULL;
xmlNode *node = NULL;
const char *local_str = NULL;
int ret = 1;
g_error_if_fail(env && xmlnode);
cryptic_return_val_if_fail(jstring_to_local_string(env, jstr, &local_str), 0);
if (local_str) {
doc = xmlReadDoc((unsigned char *)local_str, NULL, NULL, XML_PARSE_NONET);
if (!doc) {
exception(env, "could not read an xml document");
ret = 0;
goto out;
}
node = xmlDocGetRootElement(doc);
}
out:
cryptic_assign_xml_node(*xmlnode, node)
if (doc)
cryptic_release_doc(doc);
if (jstr && local_str)
release_local_string(env, jstr, local_str);
return ret;
}
**/
/* cryptic objects handling impl */
static void
create_class_name(char *dest, const char *typename) {
char *ret = NULL;
ret = strstr(typename, "Cryptic");
if (ret) {
typename = ret+7;
}
strncpy(dest+sizeof(CRYPTIC_ROOT)-1, typename,50);
dest[sizeof(CRYPTIC_ROOT)+49] = 0;
}
/** Convert the GObject obj to a java object encapsulating it.
* If obj is NULL, return NULL.
* Throws if obj is not a GObject or if anyhting fail. */
static int
gobject_to_jobject_aux(JNIEnv *env, GObject *obj, gboolean doRef, jobject *jobj) {
jobject self = NULL;
int ret = 1;
if (obj == NULL) {
goto out;
}
if (! G_IS_OBJECT(obj)) {
exception(env, "tried to convert something that is not a GObject to a Java object");
ret = 0;
goto out;
}
/* Try to get an already created java object. */
self = get_shadow_object(env, obj);
if (self) {
goto out;
} else {
/* Create the shadow object */
char clsName[sizeof(CRYPTIC_ROOT)+50] = CRYPTIC_ROOT;
const char *typename = NULL;
typename = G_OBJECT_TYPE_NAME(obj);
create_class_name(clsName, typename);
if (! new_object_with_gobject(env, obj, clsName, &self)) {
ret = 0;
goto out;
}
set_shadow_object(env, obj, self);
/** If all goes well increment reference count eventually. */
if (doRef) {
g_object_ref(obj);
}
}
out:
*jobj = self;
return ret;
}
/** Get or create static int
get_list(JNIEnv *env, const char *clsName, const GList *list, Converter convert, jobjectArray *jarr) {
jsize l,i;
jclass cls;
g_error_if_fail (env && clsName && convert);
l = g_list_length((GList*)list);
if (!l) {
*jarr = NULL;
goto out;
}
cls = get_jclass_by_name(env, clsName);
cryptic_return_val_if_fail(cls, 0);
cryptic_return_val_if_fail(create_object_array(env, clsName, l, jarr), 0);
for (i=0;i<l;i++) {
jobject item;
cryptic_return_val_if_fail(convert(env, list->data, &item), 0);
cryptic_return_val_if_fail(set_array_element(env, *jarr, i, item), 0);
list = g_list_next(list);
}
out:
return 1;
}
a new java object encapsulating this cryptic GObject, do not increase ref count if created. */
static int
gobject_to_jobject(JNIEnv *env, GObject *obj, jobject *jobj) {
return gobject_to_jobject_aux(env, obj, FALSE, jobj);
}
/** Get or create a new java object encapsulating this cryptic GObject, increase ref count if created. */
static int
gobject_to_jobject_and_ref(JNIEnv *env, GObject *obj, jobject *jobj) {
return gobject_to_jobject_aux(env, obj, TRUE, jobj);
}
/** Get the gobject encapsulated by the java object obj. If cptr is
* null return NULL.
* It throws and return 0 if anything fail unexpectedly. */
static int
jobject_to_gobject(JNIEnv *env, jobject obj, GObject **gobj) {
jlong value = 0;
GObject *gobject = NULL;
g_error_if_fail(env);
if (! obj) {
*gobj = NULL;
return 1;
}
cryptic_return_val_if_fail(get_jlong_field(env, obj, "cptr", &value), 0);
gobject = convert_jlong_to_gobject(value);
if (gobject && ! G_IS_OBJECT(gobject)) {
#define s "jobject->cptr is not a pointer on a gobject: XXXXXXXXXXXXXXXXXXXXXXX"
char str[] = s;
snprintf(str, sizeof(s)-1, "jobject->cptr is not a pointer on a gobject = %p", gobject);
exception(env, str);
#undef s
return 0;
} else {
cryptic_assign_gobject(*gobj, gobject);
return 1;
}
}
/** Get the gobject encapsulated by the java object obj and increase its ref count. The only
* use for this function is composed with set_list_of_objects or set_hash_of_object. */
static int
jobject_to_gobject_noref(JNIEnv *env, jobject obj, GObject **gobj) {
cryptic_return_val_if_fail(jobject_to_gobject(env, obj, gobj), 0);
if (*gobj) {
g_object_unref(*gobj);
}
return 1;
}
/* List handling */
static void
free_glist(GList **list, GFunc free_function) {
cryptic_return_if_fail(list);
if (*list) {
if (free_function) {
g_list_foreach(*list, free_function, NULL);
}
g_list_free(*list);
}
*list = NULL;
}
/** Get an object array from a GList*, convert C object to java object using
* the convert function.
*
* Can throw. If list is null or empty, return NULL.
*/
static int
get_list(JNIEnv *env, const char *clsName, const GList *list, Converter convert, jobjectArray *jarr) {
jsize l,i;
jclass cls;
g_error_if_fail (env && clsName && convert);
l = g_list_length((GList*)list);
if (!l) {
*jarr = NULL;
goto out;
}
cls = get_jclass_by_name(env, clsName);
cryptic_return_val_if_fail(cls, 0);
cryptic_return_val_if_fail(create_object_array(env, clsName, l, jarr), 0);
for (i=0;i<l;i++) {
jobject item;
cryptic_return_val_if_fail(convert(env, list->data, &item), 0);
cryptic_return_val_if_fail(set_array_element(env, *jarr, i, item), 0);
list = g_list_next(list);
}
out:
return 1;
}
/** Sets a GList* field using a java array of object. Use free_function if an old list exist.
* Use convert to convert the java objects to C values. */
static int
set_list(JNIEnv *env, GList **list, jobjectArray jarr, GFunc free_function, OutConverter convert) {
jobject element = NULL;
jsize size = 0;
jsize i = 0;
GList *new = NULL;
g_error_if_fail (list && free_function && convert && env);
if (jarr) {
if (! get_array_size(env, jarr, &size))
goto error;
for (i=0; i < size; i++) {
gpointer result = NULL;
if (! get_array_element(env, jarr, i, &element)
|| ! convert(env, element, &result)) {
goto error;
}
new = g_list_append(new, result);
}
}
free_glist(list, free_function);
*list = new;
return 1;
error:
free_glist(&new, free_function);
return 0;
}
/** Remove a value obtained via the convert function on obj from *list.
* It is searched inside *list using the compare function.
* If pointer is found, it is freed using the free_function.
* Return 0 if an exception was throwed.
**/
static int
remove_from_list(JNIEnv *env, GList **list, jobject obj, GFunc free_function, GCompareFunc compare, OutConverter convert) {
gpointer data = NULL;
GList *found = NULL;
g_error_if_fail(env && list && compare && convert && free_function);
cryptic_return_val_if_fail(obj, 1);
cryptic_return_val_if_fail(convert(env, obj, &data), 0);
found = g_list_find_custom(*list, data, compare);
if (found) {
free_function(found->data, NULL);
*list = g_list_delete_link(*list, found);
}
return 1;
}
static int
remove_from_list_of_strings(JNIEnv *env, GList **list, jstring jstr) {
const char *local_string = NULL;
GList *found = NULL;
g_error_if_fail(env && list);
cryptic_return_val_if_fail(jstr, 1);
cryptic_return_val_if_fail(jstring_to_local_string(env, jstr, &local_string), 0);
found = g_list_find_custom(*list, local_string, (GCompareFunc)strcmp);
if (found) {
g_free(found->data);
*list = g_list_delete_link(*list, found);
}
release_local_string(env, jstr, local_string);
return 1;
}
/** Add obj to GList *list.
* Returns 1.
* Returns 0 and throws if anything fail.
*/
static int
add_to_list(JNIEnv* env, GList** list, jobject obj, OutConverter convert) {
gpointer data = NULL;
g_error_if_fail(env && list && convert);
cryptic_return_val_if_fail(convert(env, obj, &data), 0);
if (data)
*list = g_list_append(*list, data);
return 1;
}
/* Ghash table handling impl */
/** Create a java array from a GHashTable, using the convert function. */
static int
get_hash(JNIEnv *env, char *clsName, GHashTable *hashtable, Converter convert, jobjectArray *jarr)
{
jsize l = 0, i = 0;
GList *keys = NULL, *values = NULL;
int ret = 1;
g_error_if_fail (env && hashtable && convert);
l = g_hash_table_size(hashtable);
cryptic_return_val_if_fail(create_object_array(env, clsName, 2*l, jarr), 0);
keys = g_hash_table_get_keys(hashtable);
values = g_hash_table_get_values(hashtable);
if (! (keys && values)) {
ret = 0;
exception(env, "cannot allocate for converting GHashTable to an array");
goto out;
}
for (i=0; i < 2*l && keys && values; i+=2) {
jstring key = NULL;
jobject value = NULL;
if (! (string_to_jstring(env, (char*)keys->data, &key)
&& convert(env, (gpointer)values->data, &value)
&& set_array_element(env, *jarr, i, key)
&& set_array_element(env, *jarr, i+1, value))) {
ret = 0;
goto out;
}
keys = g_list_next(keys);
values = g_list_next(values);
}
out:
if (keys)
g_list_free(keys);
if (values)
g_list_free(values);
return ret;
}
/** Fill a GHashTable with content of java array arr.
* Even indexed element coressponds to keys (jstring) and
* odd indexed one to value (GObject).
* Returns 1.
* Returns 0 and thows an exception if anything fail.
*/
static int
set_hash_of_objects(JNIEnv *env, GHashTable *hashtable, jobjectArray jarr)
{
jsize l = 0, i = 0;
g_error_if_fail (env && hashtable);
if (jarr) {
/** First increment ref count of object in jarr */
cryptic_return_val_if_fail(get_array_size(env, jarr, &l), 0);
if (l % 2 != 0) {
exception(env, "java array not of an even size");
return 0;
}
for (i = 1; i < l; i += 2) {
jobject jobj = NULL;
GObject *gobj = NULL;
cryptic_return_val_if_fail(get_array_element(env, jarr, i, &jobj), 0);
cryptic_return_val_if_fail(jobject_to_gobject_noref(env, jobj, &gobj), 0);
(*env)->DeleteLocalRef(env, jobj);
}
/* increment ref count of objects */
for (i = 1; i < l; i += 2) {
jobject jobj = NULL;
GObject *gobj = NULL;
get_array_element(env, jarr, i, &jobj);
jobject_to_gobject(env, jobj, &gobj);
(*env)->DeleteLocalRef(env, jobj);
}
}
/** Remove old values, if hashtable is well initialized
* it should unref objects automatically. */
g_hash_table_remove_all(hashtable);
/** Insert new values */
if (jarr) {
for (i = 0; i < l; i += 2) {
jstring jkey = NULL;
char *key = NULL;
jobject jvalue = NULL;
GObject *value = NULL;
cryptic_return_val_if_fail(get_array_element(env, jarr, i, &jkey), 0);
cryptic_return_val_if_fail(get_array_element(env, jarr, i+1, &jvalue), 0);
cryptic_return_val_if_fail(jstring_to_string(env, jkey, &key), 0);
if (! jobject_to_gobject_noref(env, jvalue, &value)) {
if (key)
g_free(key);
g_hash_table_remove_all(hashtable);
return 0;
}
g_hash_table_insert (hashtable, key, value);
(*env)->DeleteLocalRef(env, jkey);
(*env)->DeleteLocalRef(env, jvalue);
}
}
return 1;
}
/** Insert a java String array, containing
* keys at odd indexes, and values at even indexes into an existing
* GHashTable. Old entries are lost, but hopefully deallocated by
* the hashtable free functions --- setted at creation, see GLib
* documentation.
*
* @param env the JNI context given by the JVM
* @param hashtable an existing GHashTable
* @param a ref to a java object Array of size multiple of two
*
* @return 1 if successful, 0 if anything bad happen.
*/
static int
set_hash_of_strings(JNIEnv *env, GHashTable *hashtable, jobjectArray jarr) {
jsize l = 0, i = 0;
g_error_if_fail (env && hashtable);
g_hash_table_remove_all(hashtable);
if (jarr) {
cryptic_return_val_if_fail(get_array_size(env, jarr, &l), 0);
if (l % 2 != 0) {
exception(env, "java array not of an even size");
return 0;
}
for (i = 0; i < l; i += 2) {
jstring jkey = NULL;
char *key = NULL;
jstring jvalue = NULL;
char *value = NULL;
cryptic_return_val_if_fail(get_array_element(env, jarr, i, &jkey)
&& get_array_element(env, jarr, i+1, &jvalue)
&& jstring_to_string(env, jkey, &key), 0);
if (! key) {
exception(env, "key is null");
return 0;
}
if (! jstring_to_string(env, jvalue, &value)) {
if (key)
g_free(key);
g_hash_table_remove_all(hashtable);
return 0;
}
/* Can use insert because hash table is empty */
g_hash_table_insert(hashtable, key, value);
(*env)->DeleteLocalRef(env, jkey);
(*env)->DeleteLocalRef(env, jvalue);
}
}
return 1;
}
/** Remove the value for the given key from hashtable. */
static int
remove_from_hash(JNIEnv *env, GHashTable *hashtable, jstring jkey) {
const char *key = NULL;
g_error_if_fail (env && hashtable);
cryptic_return_val_if_fail(jstring_to_local_string(env, jkey, &key), 0);
g_hash_table_remove(hashtable, key);
release_local_string(env, jkey, key);
return 1;
}
/** Add a jobject to an hashtable */
static int
add_to_hash(JNIEnv *env, GHashTable *hashtable, jstring jkey, jobject jvalue, OutConverter convert, GFunc free_function)
{
void *value = NULL;
char *key = NULL;
g_error_if_fail (env && hashtable && key && convert);
if (! (convert(env, jvalue, &value)
&& jstring_to_string(env, jkey, &key)))
goto error;
g_hash_table_replace(hashtable, key, value);
return 1;
error:
if (key)
g_free(key);
if (value)
free_function(value, NULL);
return 0;
}
static int
get_hash_by_name(JNIEnv *env, GHashTable *hashtable, jstring jkey, Converter convert, jobject *jvalue)
{
const char *key = NULL;
gpointer value = NULL;
g_error_if_fail (env && hashtable && convert);
cryptic_return_val_if_fail(jstring_to_local_string(env, jkey, &key), 0);
value = g_hash_table_lookup(hashtable, key);
release_local_string(env, jkey, key);
return convert(env, value, jvalue);
}
static void
throw_by_name(JNIEnv *env, const char *name, const char *msg)
{
jclass cls = (*env)->FindClass(env, name);
/* if cls is NULL, an exception has already been thrown */
if (cls != NULL) {
(*env)->ThrowNew(env, cls, msg);
}
/* free the local ref */
(*env)->DeleteLocalRef(env, cls);
}
/* JNI Functions */
JNIEXPORT void JNICALL Java_com_entrouvert_cryptic_CrypticJNI_init2(JNIEnv *env, jclass cls) {
cryptic_wrapper_key = g_quark_from_static_string("JavaCryptic::wrapper");
}
JNIEXPORT void JNICALL Java_com_entrouvert_cryptic_CrypticJNI_destroy(JNIEnv *env, jclass cls, jlong cptr) {
GObject *obj = (GObject*)(ptrdiff_t)cptr;
set_shadow_object(env, obj, NULL);
g_object_unref(obj);
}
JNIEXPORT void JNICALL Java_com_entrouvert_cryptic_CrypticJNI_set_1shadow_1object(JNIEnv *env, jclass cls, jlong cptr, jobject shadow_object) {
GObject *gobj = NULL;
gobj = convert_jlong_to_gobject(cptr);
set_shadow_object(env, gobj, shadow_object);
}