diff options
Diffstat (limited to 'bindings/lang_java_wrapper_top.c')
| -rw-r--r-- | bindings/lang_java_wrapper_top.c | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/bindings/lang_java_wrapper_top.c b/bindings/lang_java_wrapper_top.c new file mode 100644 index 00000000..123bb996 --- /dev/null +++ b/bindings/lang_java_wrapper_top.c @@ -0,0 +1,522 @@ +#include <lasso/lasso.h> +#include <lasso_config.h> +#include <jni.h> +#include "com_entrouvert_lasso_LassoJNI.h" +#include <string.h> + +static GQuark lasso_wrapper_key; +typedef jobject (*Converter)(JNIEnv *env, void *); +typedef void *(*OutConverter)(JNIEnv *env, jobject); + +/* String handling */ +static jstring string_to_jstring(JNIEnv *env, const char *str); +static jstring string_to_jstring_and_free(JNIEnv *env, char *str); +static const char* jstring_to_string(JNIEnv *env, jstring str); +static void release_utf_string(JNIEnv *env, jstring str, const char *utfstr); + +/* xmlNode handling */ +static jstring xml_node_to_jstring(JNIEnv *env, xmlNode *xmlnode); +static xmlNode* jstring_to_xml_node(JNIEnv *env, jstring string); + +/* Lasso object handling */ +/* Reference counting: + * + * new jobject make ++refcount + * + */ + +static GObject* jobject_to_gobject(JNIEnv *env, jobject *obj); +static GObject* jobject_to_gobject_and_ref(JNIEnv *env, jobject *obj); +static jobject gobject_to_jobject(JNIEnv *env, GObject *obj); +static jobject gobject_to_jobject_and_ref(JNIEnv *env, GObject *obj); + +/* List handling */ +static void free_glist(GList **list, GFunc free_function) ; +static jobjectArray get_list(JNIEnv *, char *,GList *, Converter); +#define get_list_of_strings(env,list) get_list(env,"java/lang/String",list,(Converter)string_to_jstring) +#define get_list_of_xml_nodes(env,list) get_list(env,"java/lang/String",list,(Converter)xml_node_to_jstring) +#define get_list_of_objects(env,list) get_list(env,"java/lang/Object",list,(Converter)gobject_to_jobject_and_ref) +static void set_list(JNIEnv*,GList **, jobjectArray jarr,GFunc free_function, OutConverter); +#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_and_ref) +static void remove_from_list(JNIEnv*,GList**,jobject,GFunc,GCompareFunc,OutConverter); +#define remove_from_list_of_strings(env,list,obj) remove_from_list(env,list,obj,(GFunc)g_free,(GCompareFunc)strcmp,(OutConverter)jstring_to_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)strcmp,(OutConverter)jobject_to_gobject_and_ref) +static void add_to_list(JNIEnv*,GList**,void *,OutConverter); +#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) +#define add_to_list_of_objects(env,list,obj) add_to_list(env,list,obj,(OutConverter)jobject_to_gobject_and_ref) + +/* hashtable handling */ +/* Use property array cell[i % 2 = 0] = keys and cell[i % 2 = 1] = values */ +static jobjectArray get_hash(JNIEnv *env, char *clsName, GHashTable *hashtable, Converter convert); +#define get_hash_of_strings(env,hash) get_hash(env,"java/lang/String",hash,(Converter)string_to_jstring) +#define get_hash_of_objects(env,hash) get_hash(env,"java/lang/String",hash,(Converter)gobject_to_jobject_and_ref) +static void set_hash(JNIEnv *env, GHashTable *hashtable, jobjectArray arr, OutConverter convert); +#define set_hash_of_strings(env,hash,arr) set_hash(env,hash,arr,(OutConverter)jstring_to_string) +#define set_hash_of_objects(env,hash,arr) set_hash(env,hash,arr,(OutConverter)jobject_to_gobject_and_ref) +static void remove_from_hash(JNIEnv *env, GHashTable *hashtable, jstring key); +#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) +static void add_to_hash(JNIEnv *env, GHashTable *hashtable, jstring key, jobject obj, OutConverter convert); +#define add_to_hash_of_strings(env,hash,key,obj) add_to_hash(env,hash,key,obj,(OutConverter)jstring_to_string) +#define add_to_hash_of_objects(env,hash,key,obj) add_to_hash(env,hash,key,obj,(OutConverter)jobject_to_gobject_and_ref) +static jobject get_hash_by_name(JNIEnv *env, GHashTable *hashtable, jstring key, Converter convert); +#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) + + + +/* utility functions */ +static jlong +get_jlong_field(JNIEnv *env, jobject *obj, char *field) +{ + jclass cls; + jfieldID fid; + + cls = (*env)->GetObjectClass(env, obj); + if (cls == NULL) + return 0; + fid = (*env)->GetFieldID(env, cls, field, "J"); + if (fid == NULL) + return 0; + return (*env)->GetLongField(env, obj, fid); +} + +static jclass +get_jclass_by_name(JNIEnv *env, char *name) { + return (*env)->FindClass(env,name); +} + +/* string handling impl */ +static jstring +string_to_jstring(JNIEnv *env, const char* str) +{ + if (str) + return (*env)->NewStringUTF(env, str); + else + return NULL; +} + +static jstring +string_to_jstring_and_free(JNIEnv *env, char* str) +{ + if (str) { + jstring ret = (*env)->NewStringUTF(env, str); + g_free(str); + return ret; + } else { + return NULL; + } +} + +static const char * +jstring_to_string(JNIEnv *env, jstring str) +{ + if (str) + return (*env)->GetStringUTFChars(env, str, NULL); + else + return NULL; +} + +static const char * +jstring_to_string_dup(JNIEnv *env, jstring jstr) +{ + const char *str = jstring_to_string(env, jstr); + char * ret = NULL; + + if (! str) + return NULL; + + ret = g_strdup(str); + release_utf_string(env, jstr, str); + return ret; +} + +static void +release_utf_string(JNIEnv *env, jstring str, const char *utf_str) { + if (utf_str && str) + (*env)->ReleaseStringUTFChars(env, str, utf_str); +} + + +/* xmlNode handling */ +static jstring +xml_node_to_jstring(JNIEnv *env, xmlNode *xmlnode) +{ + xmlOutputBufferPtr buf; + + if (! xmlnode || ! env) { + return NULL; + } + + buf = xmlAllocOutputBuffer(NULL); + if (buf) { + jstring ret = NULL; + xmlNodeDumpOutput(buf, NULL, xmlnode, 0, 1, NULL); + xmlOutputBufferFlush(buf); + if (buf->conv == NULL) { + ret = string_to_jstring(env, (char*)buf->buffer->content); + } else { + ret = string_to_jstring(env, (char*)buf->conv->content); + } + xmlOutputBufferClose(buf); + return ret; + } else { + return NULL; + } +} + +static xmlNode* +jstring_to_xml_node(JNIEnv *env, jstring string) { + xmlDoc *doc; + xmlNode *node; + const char *str; + + str = jstring_to_string(env, string); + if (str == NULL) + return NULL; + + doc = xmlReadDoc((unsigned char *)str, NULL, NULL, XML_PARSE_NONET); + node = xmlDocGetRootElement(doc); + if (node != NULL) { + node = xmlCopyNode(node, 1); + } + xmlFreeDoc(doc); + release_utf_string(env, string, str); + + return node; +} + +/* lasso objects handling impl */ +static jobject +gobject_to_jobject_aux(JNIEnv *env, GObject *obj, gboolean doRef) { + jobject *self; +#define LASSO_ROOT "com/entrouvert/lasso/" + if (obj == NULL) { + return NULL; + } + + self = (jobject)g_object_get_qdata(obj, lasso_wrapper_key); + if (self == NULL) { + jclass nodeCls; + jmethodID cid; + char clsName[sizeof(LASSO_ROOT)+50] = LASSO_ROOT; + const char *typename = G_OBJECT_TYPE_NAME(obj); + if (! typename) // Moche + return NULL; + typename = typename + 5; + strncpy(clsName+sizeof(LASSO_ROOT)-1, typename,50); + clsName[sizeof(LASSO_ROOT)+49] = 0; + nodeCls = (*env)->FindClass(env, clsName); + if (nodeCls == NULL) { + return NULL; + } + cid = (*env)->GetMethodID(env, nodeCls, "<init>", "(J)V"); + if (cid == NULL) { + return NULL; + } + self = (*env)->NewObject(env, nodeCls, cid, (jlong)(unsigned int)obj); + if (self == NULL) { + return NULL; + } + g_object_set_qdata_full(obj, lasso_wrapper_key, self, NULL); + if (doRef) { + g_object_ref(obj); + } + } + return self; +} +/** Get or create a new java object encapsulating this lasso GObject, do not increase ref count if created. */ +static jobject +gobject_to_jobject(JNIEnv *env, GObject *obj) { + return gobject_to_jobject_aux(env, obj, FALSE); +} +/** Get or create a new java object encapsulating this lasso GObject, increase ref count if created. */ +static jobject +gobject_to_jobject_and_ref(JNIEnv *env, GObject *obj) { + return gobject_to_jobject_aux(env, obj, TRUE); +} + +/** Get the gobject encapsulated by the java object obj */ +static GObject* +jobject_to_gobject(JNIEnv *env, jobject *obj) { + return (GObject*)(int)get_jlong_field(env, obj, "cptr"); +} + +/** 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 GObject* +jobject_to_gobject_and_ref(JNIEnv *env, jobject *obj) { + GObject *ret; + + ret = jobject_to_gobject(env, obj); + if (ret) { + g_object_ref(obj); + } + + return ret; +} +/* List handling */ +static void +free_glist(GList **list, GFunc free_function) { + if (!list) + return; + if (*list) { + if (free_function) { + g_list_foreach(*list, free_function, NULL); + } + g_list_free(*list); + } + if (list) + *list = NULL; +} + +static jobjectArray +get_list(JNIEnv *env, char *clsName, GList *list, Converter convert) { + jsize l = g_list_length(list),i; + jobjectArray jarr; + jclass cls; + + if (!env || !list || !clsName || !convert) { + return NULL; + } + cls = get_jclass_by_name(env, clsName); + if (!cls) { + return NULL; + } + + jarr = (*env)->NewObjectArray(env, l, get_jclass_by_name(env, clsName), NULL); + if (! jarr) { + return NULL; + } + + for (i=0;i<l;i++) { + jobject item; + + item = convert(env, list->data); + if ((*env)->ExceptionOccurred(env)) { + return NULL; + } + (*env)->SetObjectArrayElement(env, jarr, i, item); + if ((*env)->ExceptionOccurred(env)) { + return NULL; + } + list = g_list_next(list); + } + return jarr; +} + +static void +set_list(JNIEnv *env, GList **list, jobjectArray jarr, GFunc free_function, OutConverter convert) { + jobject element; + jsize size; + jsize i; + + if (!list || !free_function || !convert || !env) + return; + + free_glist(list, free_function); + if (!jarr) { + *list = NULL; + return; + } + size = (*env)->GetArrayLength(env, jarr); + for (i=0; i < size; i++) { + element = (*env)->GetObjectArrayElement(env, jarr, i); + if ((*env)->ExceptionOccurred(env)) { + free_glist(list, free_function); + return; + } + *list = g_list_append(*list, convert(env, element)); + } +} + +static void +remove_from_list(JNIEnv *env,GList **list,jobject obj,GFunc free_function,GCompareFunc compare,OutConverter convert) { + void *c; + GList *found; + + c = convert(env, obj); + if ((*env)->ExceptionOccurred(env)) { + return; + } + found = g_list_find_custom(*list, c, compare); + if (found) { + free_function(found->data, NULL); + *list = g_list_delete_link(*list, found); + } +} +static void +add_to_list(JNIEnv* env,GList** list,jobject obj, OutConverter convert) { + void *data; + + data = convert(env, obj); + if ((*env)->ExceptionOccurred(env)) { + return; + } + *list = g_list_append(*list, data); +} + +struct Aux { + JNIEnv *env; + Converter convert; + gboolean crashed; + int idx; + jobjectArray jarr; +}; +static void +get_hash_aux(gpointer key, gpointer data, gpointer udata) +{ + struct Aux *aux = (struct Aux*)udata; + JNIEnv *env = aux->env; + jobjectArray jarr = aux->jarr; + + if (! aux->crashed) { + jstring jkey; + jobject jvalue; + + jkey = string_to_jstring(env, key); + if (!jkey) { + aux->crashed = TRUE; + return; + } + jvalue = aux->convert(env, data); + if ((*env)->ExceptionOccurred(env)) { + aux->crashed = TRUE; + return; + } + (*env)->SetObjectArrayElement(env, jarr, aux->idx, jkey); + if ((*env)->ExceptionOccurred(env)) { + aux->crashed = TRUE; + return; + } + (*env)->SetObjectArrayElement(env, jarr, aux->idx+1, jvalue); + if ((*env)->ExceptionOccurred(env)) { + aux->crashed = TRUE; + return; + } + aux->idx += 2; + } +} + +/* Ghash table handling impl */ +/** Set a hash table from an array of size multiple of 2 */ +static jobjectArray +get_hash(JNIEnv *env, char *clsName, GHashTable *hashtable,Converter convert) +{ + jsize l; + jobjectArray jarr; + jclass cls; + struct Aux udata = {env, convert, FALSE, 0, NULL }; + + if (!env || !hashtable || !clsName || !convert) { + return NULL; + } + l = g_hash_table_size(hashtable); + cls = get_jclass_by_name(env, clsName); + if (!cls) { + return NULL; + } + + udata.jarr = (*env)->NewObjectArray(env, l, get_jclass_by_name(env, clsName), NULL); + if (! jarr) { + return NULL; + } + g_hash_table_foreach (hashtable, (GHFunc)get_hash_aux, &udata); + if (udata.crashed) + return NULL; + return udata.jarr; +} +static void set_hash(JNIEnv *env, GHashTable *hashtable, jobjectArray arr, OutConverter convert) { + jsize l,i; + + if (! env || ! hashtable || ! arr || ! convert) + return; + + l = (*env)->GetArrayLength(env, arr); + if ((*env)->ExceptionOccurred(env) || l % 2 != 0) { + return; + } + g_hash_table_remove_all(hashtable); + for (i = 0; i < l; i += 2) { + jobject key,item; + const char *skey; + void *value; + + key = (*env)->GetObjectArrayElement(env, arr, i); + if ((*env)->ExceptionOccurred(env)) { + return; + } + item = (*env)->GetObjectArrayElement(env, arr, i); + if ((*env)->ExceptionOccurred(env)) { + return; + } + value = convert(env, item); + if ((*env)->ExceptionOccurred(env)) { + return; + } + skey = jstring_to_string(env, (jstring)key); + if ((*env)->ExceptionOccurred(env)) { + return; + } + g_hash_table_insert(hashtable, g_strdup(skey), value); + release_utf_string(env, key, skey); + } +} + +static void remove_from_hash(JNIEnv *env, GHashTable *hashtable, jstring key) { + const char *str; + if (! env || !hashtable || !key) { + return; + } + str = jstring_to_string(env, key); + if (!str) { + return; + } + g_hash_table_remove(hashtable, str); + release_utf_string(env, key, str); +} +static void add_to_hash(JNIEnv *env, GHashTable *hashtable, jstring key, jobject obj, OutConverter convert) +{ + void *data; + const char *str; + + if (!env || !hashtable || !key || !obj || !convert) { + return; + } + data = convert(env, obj); + if ((*env)->ExceptionOccurred(env)) { + return; + } + str = jstring_to_string(env,key); + if (!str) { + return; + } + g_hash_table_insert(hashtable, g_strdup(str), data); + release_utf_string(env, key, str); +} +static jobject +get_hash_by_name(JNIEnv *env, GHashTable *hashtable, jstring key, Converter convert) +{ + void *data; + const char *str; + + if (! env || !hashtable || !key || !convert) { + return NULL; + } + str = jstring_to_string(env,key); + if (!str) { + return NULL; + } + data = g_hash_table_lookup(hashtable,str); + release_utf_string(env, key, str); + return convert(env, data); +} + +/* JNI Functions */ +JNIEXPORT void JNICALL Java_com_entrouvert_lasso_LassoJNI_init2(JNIEnv *env, jclass cls) { + lasso_wrapper_key = g_quark_from_static_string("JavaLasso::wrapper"); +} |
