From 1226b060bd441761cac5c9afe44dca92ec69e6e8 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 5 Aug 2008 14:53:03 +0000 Subject: Move all files related to java into the java subdirectory --- bindings/java/Makefile.am | 2 +- bindings/java/lang.py | 902 +++++++++++++++++++++++++++++++++++++++++ bindings/java/wrapper_bottom.c | 0 bindings/java/wrapper_top.c | 783 +++++++++++++++++++++++++++++++++++ 4 files changed, 1686 insertions(+), 1 deletion(-) create mode 100644 bindings/java/lang.py create mode 100644 bindings/java/wrapper_bottom.c create mode 100644 bindings/java/wrapper_top.c (limited to 'bindings/java') diff --git a/bindings/java/Makefile.am b/bindings/java/Makefile.am index d4403ed9..d13502ae 100644 --- a/bindings/java/Makefile.am +++ b/bindings/java/Makefile.am @@ -50,7 +50,7 @@ BUILT_SOURCES = com_entrouvert_lasso_LassoJNI.c com_entrouvert_lasso_LassoJNI.h BINDING_OPTION=#--enable-exception-docs -$(java_lasso_source_files) com_entrouvert_lasso_LassoJNI.c: ../lang_java_wrapper_top.c ../lang_java.py ../bindings.py +$(java_lasso_source_files) com_entrouvert_lasso_LassoJNI.c: wrapper_top.c wrapper_bottom.c lang.py ../bindings.py $(PYTHON) $(top_srcdir)/bindings/bindings.py $(BINDING_OPTION) -l java --src-dir=$(top_srcdir)/lasso/ $(EXTRA_ARGS) cp $(srcdir)/GObject.java com/entrouvert/lasso diff --git a/bindings/java/lang.py b/bindings/java/lang.py new file mode 100644 index 00000000..044e468e --- /dev/null +++ b/bindings/java/lang.py @@ -0,0 +1,902 @@ +# Lasso - A free implementation of the Liberty Alliance specifications. +# +# Copyright (C) 2004-2007 Entr'ouvert +# http://lasso.entrouvert.org +# +# Authors: See AUTHORS file in top-level directory. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import re +import textwrap + +import utils + +lasso_package_name = 'com.entrouvert.lasso' +lasso_java_path = 'com/entrouvert/lasso/' + +debug = 0 + +def with_return_owner(d): + c = d.copy() + c['return_owner'] = 1 + return c + +def generate_arg_list(self,args): + def arg_to_decl(arg): + type, name, option = arg + return self.JNI_arg_type(type) + ' ' + utils.format_as_camelcase(name) + return ', '.join([ arg_to_decl(x) for x in args ]) + +def generate_arg_list2(args): + def arg_to_decl(arg): + type, name, option = arg + return utils.format_as_camelcase(name) + return ', '.join([ arg_to_decl(x) for x in args ]) + +def convert_class_name(lasso_name): + return lasso_name[5:] + +def mangle_name(name): + s = name + s = s.replace('_', '_1') + s = s.replace(';', '_2') + s = s.replace('[', '_3') + return s + +def jni_elem_type(type): + if type in ('char*', 'gchar*', 'const char*', 'const gchar*'): + return 'jstring' + elif type == 'xmlNode*': + return 'jstring' + else: + return 'jobject' + +def JNI_elem_type(type): + if type in ('char*', 'gchar*', 'const char*', 'const gchar*'): + return 'String' + elif type == 'xmlNode*': + return 'String' + elif type != None and type.startswith('Lasso'): + return type[5:] + else: + return 'Object' + +def wrapper_name(name): + return 'Java_com_entrouvert_lasso_LassoJNI_' + mangle_name(name) + +def error_to_exception(error_name): + if 'LASSO_ERROR' in error_name: + name, = re.match('LASSO_ERROR(_.*)', error_name).groups() + super = 'Lasso' + else: + super, name = re.match('LASSO(_.*)_ERROR(_.*)', error_name).groups() + super = utils.format_as_camelcase(super.lower()) + name = utils.format_as_camelcase(name.lower()) + return (super+name+'Exception',super+'Exception') + +def wrapper_decl(name, jnitype, fd): + jniname = wrapper_name(name) + print >> fd, 'JNIEXPORT %s JNICALL %s(JNIEnv *env, jclass clss' % \ + (jnitype,jniname), + +def is_collection(type): + return type in ('const GList*','GList*','GHashTable*') + +def is_string_type(type): + return type in ['char*', 'const char*', 'gchar*', 'const gchar*'] + +def is_const_type(type): + return type in ['const char*', 'const gchar*'] + +class Binding: + def __init__(self, binding_data): + self.binding_data = binding_data + self.src_dir = os.path.dirname(__file__) + + def print_list_of_files(self): + l = ['GObject.java','LassoConstants.java','LassoJNI.java','LassoException.java', 'LassoUndefinedException.java', 'LassoUnimplementedException.java'] + for c in self.binding_data.structs: + class_name = convert_class_name(c.name) + l.append(class_name + '.java') + for c in self.binding_data.constants: + type, orig = c + if 'LASSO_ERROR_' in orig or '_ERROR_' not in orig: + continue + name, super = error_to_exception(orig) + l.append(name + '.java') + if not super + '.java' in l: + l.append(super + '.java') + l = [ lasso_java_path + p for p in l] + for p in l: + print p, + print + print + + def is_int_type(self, type): + return type in ['gboolean','int','gint'] + self.binding_data.enums + + + def is_gobject_type(self, t): + return t not in ['char*', 'const char*', 'gchar*', 'const gchar*', + 'const GList*','GList*', 'GHashTable*', + 'int', 'gint', 'gboolean', 'const gboolean'] + self.binding_data.enums + + def generate(self): + if not os.path.exists(lasso_java_path): + os.makedirs(lasso_java_path) + self.generate_Constants() + self.generate_JNI() + self.generate_wrapper() + self.generate_exception_classes() + self.generate_lasso_classes() + + +# LassoConstants + def generate_Constants(self): + fd = open(lasso_java_path + 'LassoConstants.java', 'w') + self.generate_Constants_header(fd) + self.generate_Constants_constants(fd) + self.generate_Constants_footer(fd) + fd.close() + + def generate_Constants_header(self, fd): + print >> fd, '''\ +/* this file has been generated automatically; do not edit */ + +package %s; + +public abstract interface LassoConstants { +''' % lasso_package_name + + def generate_Constants_constants(self, fd): + print >> fd, '/* Constants (both enums and defines) */' + # Declaration + for c in self.binding_data.constants: + print >> fd, 'static final ', + if c[0] == 'i': + print >> fd, 'int ', + elif c[0] == 's': + print >> fd, 'String ', + elif c[0] == 'b': + print >> fd, 'boolean ', + print >> fd, '%s = LassoJNI.%s_get();' % (c[1][6:], c[1]) + + def generate_Constants_footer(self, fd): + print >> fd, '}' + + +# LassoJNI + def generate_JNI(self): + fd = open(lasso_java_path + 'LassoJNI.java','w') + self.generate_JNI_header(fd) + self.generate_JNI_constants(fd) + for m in self.binding_data.functions: + self.generate_JNI_functions(m ,fd) + for c in self.binding_data.structs: + self.generate_JNI_member(c, fd) + for m in c.methods: + self.generate_JNI_functions(m, fd) + self.generate_JNI_footer(fd) + fd.close(); + + def generate_JNI_header(self, fd): + print >> fd, '''\ +/* this file has been generated automatically; do not edit */ + +package %s; + +public final class LassoJNI { +protected static native void init2(); +protected static native void destroy(long cptr); +''' % lasso_package_name + def generate_JNI_constants(self, fd): + print >>fd, '/* Constants getters */' + for c in self.binding_data.constants: + print >>fd, 'public static native ', + if c[0] == 'i': + print >>fd, 'int ', + elif c[0] == 's': + print >>fd, 'String ', + elif c[0] == 'b': + print >>fd, 'boolean ', + print >>fd, '%s_get();' % c[1] + + def JNI_arg_type(self, vtype): + if vtype == 'gboolean': + return 'boolean' + elif vtype in ['int','gint'] + self.binding_data.enums: + return 'int' + elif vtype in ('char*', 'gchar*', 'const char*', 'const gchar*'): + return 'String' + elif vtype in ('const GList*','GList*','GHashTable*'): + return 'Object[]' + elif vtype == 'xmlNode*': + return 'String' + elif isinstance(vtype,basestring) and vtype.startswith('Lasso'): + if vtype.endswith('*'): + vtype = vtype[:-1] + return convert_class_name(vtype) + else: + return 'GObject' + + def JNI_return_type(self, vtype): + if vtype: + m = re.match(r'(?:const\s*)?(.*)',vtype) + vtype = m.group(1) + if vtype == 'gboolean': + return 'boolean' + elif vtype in ['int','gint'] + self.binding_data.enums: + return 'int' + elif vtype in ('char*', 'gchar*'): + return 'String' + elif vtype in ('const GList*','GList*','GHashTable*'): + return 'Object[]' + elif vtype == 'xmlNode*': + return 'String' + elif isinstance(vtype,basestring) and vtype.startswith('Lasso'): + if vtype.endswith('*'): + vtype = vtype[:-1] + return convert_class_name(vtype) + else: + return 'void' + + def JNI_member_type(self,member): + type, name, options = member + if type in ('const GList*','GList*','GHashTable*'): + return self.JNI_arg_type(options.get('elem_type')) + else: + return self.JNI_arg_type(type) + + def JNI_function_name(self, m): + if m.rename: + return m.rename + else: + return m.name[6:] + + def generate_JNI_functions(self, m, fd): + if m.name.endswith('_new'): + jtype = 'long' + else: + jtype = self.JNI_return_type(m.return_type) + name = self.JNI_function_name(m) + print >> fd, ' public static native %s %s(%s);' % (jtype,name, generate_arg_list(self,m.args)) + + def JNI_member_function_prefix(self,c,m): + klassname = c.name[5:] + mname = utils.format_as_camelcase(m[1]) + return '%s_%s' % (klassname,mname) + + def generate_JNI_member(self, c, fd): + for m in c.members: + prefix = self.JNI_member_function_prefix(c,m) + mname = utils.format_as_camelcase(m[1]) + mtype = m[0] + + jtype = self.JNI_member_type(m) + if mtype == 'GList*'or mtype == 'const GList*': + name = '%s_get' % prefix + print >> fd, ' public static native %s[] %s(GObject obj);' % (jtype,name) + name = '%s_set' % prefix + print >> fd, ' public static native void %s(GObject obj, %s[] value);' % (name,jtype) + name = '%s_add' % prefix + print >> fd, ' public static native void %s(GObject obj, %s value);' % (name,jtype) + if not m[2].get('elem_type') in ('xmlNode*',): + name = '%s_remove' % prefix + print >> fd, ' public static native void %s(GObject obj, %s value);' % (name,jtype) + elif mtype == 'GHashTable*': + name = '%s_get' % prefix + print >> fd, ' public static native %s[] %s(GObject obj);' % (jtype,name) + name = '%s_set' % prefix + print >> fd, ' public static native void %s(GObject obj, %s[] value);' % (name,jtype) + name = '%s_add' % prefix + print >> fd, ' public static native void %s(GObject obj, String key, %s value);' % (name,jtype) +# name = '%s_remove' % prefix +# print >> fd, ' public static native void %s(GObject obj, String key);' % (name) +# name = '%s_get_by_name' % prefix +# print >> fd, ' public static native %s[] %s(GObject obj, String key);' % (jtype,name) + else: + name = '%s_get' % prefix + print >> fd, ' public static native %s %s(GObject obj);' % (jtype,name) + name = '%s_set' % prefix + print >> fd, ' public static native void %s(GObject obj, %s value);' % (name,jtype) + + def generate_JNI_footer(self, fd): + print >>fd, ''' + static { + System.loadLibrary("jnilasso"); + init(); + init2(); + } +''' + print >>fd, '}' + + +# Wrappers + def generate_wrapper(self): + fd = open('com_entrouvert_lasso_LassoJNI.c', 'w') + self.generate_wrapper_header(fd) + self.generate_wrapper_constants(fd) + + print >> fd, '/* Declaration of standalone functions */' + for m in self.binding_data.functions: + self.generate_wrapper_function(m, fd) + print >> fd, '/* End of declaration of standalone functions */' + print >> fd, '/* Declaration of getter/setter methods */' + for c in self.binding_data.structs: + self.generate_wrapper_getter_setter(c, fd) + print >> fd, '/* End of declaration of getter/setter methods */' + for c in self.binding_data.structs: + for m in c.methods: + self.generate_wrapper_function(m, fd) + print >> fd, open(os.path.join(self.src_dir,'wrapper_bottom.c')).read() + fd.close() + + def generate_wrapper_header(self, fd): + print >> fd, open(os.path.join(self.src_dir,'wrapper_top.c')).read() + print >> fd, '' + for h in self.binding_data.headers: + print >> fd, '#include <%s>' % h + + + def generate_wrapper_constants(self, fd): + print >> fd, '/* Declaration of constants */' + for c in self.binding_data.constants: + s = c[1]+'_get' + if c[0] == 'i': + wrapper_decl(s,'jint',fd) + print >>fd, ') {' + print >>fd, ' return %s;' % c[1] + print >>fd, '}' + elif c[0] == 's': + wrapper_decl(s,'jstring',fd) + print >>fd, ') {' + print >>fd, ' return (*env)->NewStringUTF(env, %s);' % c[1] + print >>fd, '}' + elif c[0] == 'b': + wrapper_decl(s,'jboolean',fd) + print >>fd, ') {' + print >>fd, '#ifdef %s' % c[1] + print >>fd, ' return 1;' + print >>fd, '#else' + print >>fd, ' return 0;' + print >>fd, '#endif' + print >>fd, '}' + print >> fd, '/* End of declaration of constants */' + + def jni_return_type(self, type): + if type == 'gboolean': + return 'jboolean' + elif type in ['int','gint'] + self.binding_data.enums: + return 'jint' + elif type in ('char*', 'gchar*', 'const char*', 'const gchar*'): + return 'jstring' + elif type in ('const GList*','GList*','GHashTable*'): + return 'jobjectArray' + elif type == 'xmlNode*': + return 'jstring' + elif not type: + return 'void' + else: + return 'jobject' + + def c_to_java_value(self, left, right, type, options): + if type == 'gboolean': + return '%s = (jboolean)%s' % (left,right) + elif type in ['int', 'gint'] + self.binding_data.enums: + return '%s = (jint)%s' % (left, right) + elif is_string_type(type): + return 'string_to_jstring(env, %s, &%s)' % (right, left) + elif type in ('const GList*','GList*',): + elem_type = options.get('elem_type') + if elem_type == 'char*': + return 'get_list_of_strings(env, %s, &%s)' % (right, left) + elif elem_type == 'xmlNode*': + return 'get_list_of_xml_nodes(env, %s, &%s)' % (right, left) + else: + return 'get_list_of_objects(env, %s, &%s)' % (right, left) + elif type in ('GHashTable*',): + elem_type = options.get('elem_type') + if elem_type == 'char*': + return 'get_hash_of_strings(env, %s, &%s)' % (right, left) + else: + return 'get_hash_of_objects(env, %s, &%s)' % (right, left) + elif type == 'xmlNode*': + return 'xml_node_to_jstring(env, %s, &%s)' % (right, left) + else: + if options.get('return_owner'): + return 'gobject_to_jobject(env, (GObject*)%s, &%s);' % (right, left) + else: + return 'gobject_to_jobject_and_ref(env, (GObject*)%s, &%s);' % (right, left) + + def java_to_c_value(self, left, right, type, options): + if type in ['gboolean','int', 'gint'] + self.binding_data.enums: + return '%s = (%s)%s;' % (left,type,right) + elif is_string_type(type): + return 'jstring_to_string(env, %s, (char**)&%s);' % (right,left) + elif type in ('const GList*','GList*',): + elem_type = options.get('elem_type') + if elem_type == 'char*': + return 'set_list_of_strings(env, &%s,%s);' % (left,right) + elif elem_type == 'xmlNode*': + return 'set_list_of_xml_nodes(env, &%s, %s);' % (left, right) + else: + return 'set_list_of_objects(env, &%s, %s);' % (left, right) + elif type in ('GHashTable*',): + elem_type = options.get('elem_type') + if elem_type == 'char*': + return 'set_hash_of_strings(env, %s, %s);' % (left,right) + else: + return 'set_hash_of_objects(env, %s, %s);' % (left,right) + elif type == 'xmlNode*': + return 'jstring_to_xml_node(env, %s, &%s);' % (right, left) + else: + return 'jobject_to_gobject(env, %s, (GObject**)&%s);' % (right, left) + + def generate_wrapper_function(self, m, fd): + print >> fd, '/* Wrapper function for ', + if m.return_type: + print >> fd, m.return_type, + else: + print >> fd, 'void', + print >> fd, '%s(' % m.name, + for arg in m.args: + print >> fd, '%s %s %s,' % (arg[0],arg[1],arg[2]), + print >> fd, ') */' + if m.rename: + name = m.rename + else: + name = m.name[6:] +# self.wrapper_list.append(name) +# print >> fd, '''static PyObject* +#%s(PyObject *self, PyObject *args) +#{''' % name + if m.name.endswith('_new'): + jtype = 'jlong' + else: + jtype = self.jni_return_type(m.return_type) + wrapper_decl(name, jtype, fd) + parse_tuple_format = [] + parse_tuple_args = [] + idx = 0 + # Declare java args + for arg in m.args: + idx = idx + 1 + arg_type, arg_name, arg_options = arg + print >> fd, ',%s jarg%s' % (self.jni_return_type(arg_type.replace('const ','')),idx), + print >> fd, ')' + print >> fd, ' {' + idx = 0 + if m.return_type: + print >> fd, ' %s ret;' % jtype + # Declare C args + for arg in m.args: + idx = idx + 1 + arg_type, arg_name, arg_options = arg + print >> fd, ' %s %s;' % (arg_type.replace('const ',''),arg_name) + # Declare return vars + if m.return_type: + print >> fd, ' %s return_value;' % m.return_type + idx = 0 + # Convert args + for arg in m.args: + idx = idx + 1 + arg_type, arg_name, arg_options = arg + print >> fd, ' %s' % self.java_to_c_value(arg_name, 'jarg%s' % idx, arg_type, arg_options) + if debug: + print >> fd, ' printf("%s' % name, + arglist = '' + for arg in m.args: + arg_type, arg_name, arg_options = arg + arglist = arglist + ', %s' % arg_name + if self.is_int_type(arg_type): + print >> fd, '%i', + elif is_string_type(arg_type): + print >> fd, '%s', + else: + print >> fd, '%p', + print >> fd, '\\n"%s);' % arglist + # Call function + print >> fd, ' ', + if m.return_type: + print >> fd, 'return_value = ', + if 'new' in m.name: + print >>fd, '(%s)' % m.return_type, + + print >> fd, '%s(%s);' % (m.name, ', '.join([x[1] for x in m.args])) + # Free const char * args + idx=0 + for arg in m.args: + idx=idx+1 + arg_type, arg_name, arg_options = arg + if is_string_type(arg_type): + print >> fd, ' if (%s)' % arg_name + print >> fd, ' g_free(%s);' % arg_name + elif arg_type == 'GList*' or arg_type == 'const GList*': + if arg_options.get('elem_type') == 'char*': + print >> fd, ' free_glist(&%s, (GFunc)free);' % arg_name + else: + raise Exception('Freeing args of type list of \'%s\' not supported.' % arg_options.get('elem_type')) + + # Return + if m.return_type: + if m.name.endswith('_new'): + print >> fd, ' ret = (jlong)(int) return_value;' + else: + options = {} + if m.return_owner: + options = with_return_owner({}) + print >> fd, ' %s;' % self.c_to_java_value('ret','return_value', m.return_type, options) + if m.return_owner: + if m.return_type == 'GList*' or m.return_type == 'const GList*': + print >> fd, ' free_glist(&return_value, NULL);' + elif is_string_type(m.return_type) and not is_const_type(m.return_type): + print >> fd, ' if (return_value)' + print >> fd, ' g_free(return_value);' + print >> fd, ' return ret;' + print >> fd, ' }' + + def generate_wrapper_getter_setter(self, c, fd): + klassname = c.name + for m in c.members: + mtype = m[0] + prefix = self.JNI_member_function_prefix(c,m) + # getter + jtype = self.jni_return_type(mtype) + print >> fd,'/* Getter for %s %s.%s */' % (mtype,klassname,m[1]) + wrapper_decl("%s_get" % prefix, jtype, fd) + print >> fd, ', jobject jobj)\n {' + print >> fd, ' %s *gobj;' % klassname + print >> fd, ' jobject_to_gobject(env, jobj, (GObject**)&gobj);' + if debug: + print >> fd, ' printf("%s_get %%p %%p\\n", gobj, gobj->%s);' % (prefix, m[1]) + print >> fd, ' %s ret = 0;' % jtype + print >> fd, ' if (gobj) {' + print >> fd, ' %s;' % self.c_to_java_value ('ret','gobj->%s' % m[1], mtype, m[2]) + print >> fd, ' } else {' + print >> fd, ' (*env)->ThrowNew(env, "java/lang/NullPointerException", "no gobject correspond to the given object");' + print >> fd, ' }' + print >> fd, ' return ret;' + print >> fd, '}' + print >> fd, '' + # setter + print >> fd,'/* Setter for %s %s.%s */' % (mtype,klassname,m[1]) + wrapper_decl("%s_set" % prefix, 'void', fd) + print >> fd, ', jobject jobj, %s value)\n {' % self.jni_return_type(mtype) + print >> fd, ' %s *gobj;' % klassname + if debug: + print >> fd, ' printf("%s_set %%p %%p\\n", gobj, value);' % prefix + print >> fd, ' jobject_to_gobject(env, jobj, (GObject**)&gobj);' + print >> fd, ' if (!gobj) {' + print >> fd, ' (*env)->ThrowNew(env, "java/lang/NullPointerException", "no gobject correspond to the given object");' + print >> fd, ' }' + if not self.is_int_type(mtype) and not is_collection(mtype): + print >> fd, ' if (gobj->%s) {' % m[1] + if is_string_type(mtype): + print >> fd, ' g_free(gobj->%s);' % m[1] + else: + print >> fd, ' g_object_unref(gobj->%s);' % m[1] + print >> fd, ' }' + print >> fd, ' %s' % self.java_to_c_value('gobj->%s' % m[1], 'value', mtype, m[2]) + if self.is_gobject_type(mtype): + print >> fd, ' if (gobj->%s) {' % m[1] + print >> fd, ' g_object_ref(gobj->%s);' % m[1] + print >> fd, ' }' + print >> fd, '}' + # add/remove + if mtype in ('const GList*','GList*', ): + # add + print >> fd,'/* Adder for %s %s.%s */' % (mtype,klassname,m[1]) + elem_type = m[2].get('elem_type') + wrapper_decl("%s_add" % prefix, 'void', fd) + print >> fd, ', jobject jobj, %s value)\n {' % jni_elem_type(elem_type) + print >> fd, ' %s *gobj;' % klassname + print >> fd, ' jobject_to_gobject(env, jobj, (GObject**)&gobj);' + if is_string_type(elem_type): + print >> fd, ' add_to_list_of_strings(env, &gobj->%s,value);' % m[1] + elif elem_type in ('xmlNode*',): + print >> fd, ' add_to_list_of_xml_nodes(env, &gobj->%s,value);' % m[1] + else: + print >> fd, ' add_to_list_of_objects(env, &gobj->%s,value);' % m[1] + print >> fd, '}' + # remove + if elem_type not in ('xmlNode*',): + print >> fd,'/* Remover for %s %s.%s */' % (mtype,klassname,m[1]) + wrapper_decl("%s_remove" % prefix, 'void', fd) + print >> fd, ', jobject jobj, %s value)\n {' % jni_elem_type(elem_type) + print >> fd, ' %s *gobj;' % klassname + print >> fd, ' jobject_to_gobject(env, jobj, (GObject**)&gobj);' + if elem_type in ('char*','gchar*'): + print >> fd, ' remove_from_list_of_strings(env, &gobj->%s,value);' % m[1] + else: + print >> fd, ' remove_from_list_of_objects(env, &gobj->%s,value);' % m[1] + print >> fd, '}' + # add/remove/get_by_name + if mtype in ('GHashTable*',): + # add + print >> fd,'/* Adder for %s %s.%s */' % (mtype,klassname,m[1]) + elem_type = m[2].get('elem_type') + wrapper_decl("%s_add" % prefix, 'void', fd) + print >> fd, ', jobject jobj, jstring key, %s value)\n {' % jni_elem_type(elem_type) + print >> fd, ' %s *gobj;' % klassname + print >> fd, ' jobject_to_gobject(env, jobj, (GObject**)&gobj);' + if elem_type in ('char*','gchar*'): + print >> fd, ' add_to_hash_of_strings(env, gobj->%s,value,key);' % m[1] + else: + print >> fd, ' add_to_hash_of_objects(env, gobj->%s,value,key);' % m[1] + print >> fd, '}' +# # remove +# print >> fd,'/* Remover for %s %s.%s */' % (mtype,klassname,m[1]) +# wrapper_decl("%s_remove" % prefix, 'void', fd) +# print >> fd, ', jobject jobj, jstring key)\n {' +# print >> fd, ' %s *gobj;' % klassname +# print >> fd, ' jobject_to_gobject(env, jobj, (GObject**)&gobj);' +# if elem_type in ('char*','gchar*'): +# print >> fd, ' remove_from_hash_of_strings(env, gobj->%s,key);' % m[1] +# else: +# print >> fd, ' remove_from_hash_of_objects(env, gobj->%s,key);' % m[1] +# print >> fd, '}' +# # get by name +# print >> fd,'/* Get by name for %s %s.%s */' % (mtype,klassname,m[1]) +# wrapper_decl("%s_get_by_name" % prefix, jni_elem_type(elem_type) , fd) +# print >> fd, ', jobject jobj, jstring key)\n {' +# print >> fd, ' %s *gobj;' % klassname +# print >> fd, ' jobject_to_gobject(env, jobj, (GObject**)&gobj);' +# if elem_type in ('char*','gchar*'): +# print >> fd, ' return get_hash_of_strings_by_name(env, gobj->%s,key);' % m[1] +# else: +# print >> fd, ' return get_hash_of_objects_by_name(env, gobj->%s,key);' % m[1] +# print >> fd, '}' + +# + def generate_exception_switch_case(self, fd, name, orig): + print >> fd, ' if (errorCode == LassoConstants.%s) {' % orig[6:] + print >> fd, ' throw new %s(errorCode);' % name + print >> fd, ' }' + + def generate_exception_classes(self): + efd = open(lasso_java_path + 'LassoException.java', 'w') + print >> efd, open(os.path.join(self.src_dir,'LassoException_top.java')).read() + # Generate the function to get class name by error code + supers = [] + for c in self.binding_data.constants: + type, orig = c + if 'LASSO_ERROR_' in orig or '_ERROR_' not in orig: + continue + name, super = error_to_exception(orig) + self.generate_exception_switch_case(efd, name, orig) + if super not in supers: + supers.append(super) + self.generate_exception_class(name,super,0,orig) + for s in supers: + self.generate_exception_class(s,'LassoException',1,'') + # Special errors, UNIMPLEMENTED and UNDEFINED + for c in self.binding_data.constants: + type, orig = c + if 'LASSO_ERROR_' not in orig: + continue + name, = re.match('LASSO_ERROR(.*)',orig).groups() + name = name.lower() + name = utils.format_underscore_as_camelcase(name) + name = 'Lasso%sException' % name + self.generate_exception_class(name, 'LassoException', 0, orig) + self.generate_exception_switch_case(efd, name, orig) + print >> efd, ' throw new LassoException(errorCode, "Uknown lasso error code, maybe a bug in the binding, report it!");' + print >> efd, ' }' + print >> efd, '}' + efd.close() + + + def generate_exception_class(self, name, super,abstract,orig): + fd = open(lasso_java_path + '%s.java' % name, 'w') + print >> fd, 'package %s;' % lasso_package_name + print >> fd, '' + if abstract: + print >> fd, 'abstract ', + print >> fd, 'public class %s extends %s {' % (name,super) + print >> fd, ' private static final long serialVersionUID = 6170037639785281128L;' + if not abstract: + print >> fd, ' public %s() {' % name + print >> fd, ' super(LassoConstants.%s);' % orig[6:] + print >> fd, ' }' + print >> fd, ' protected %s(int errorCode) {' % name + print >> fd, ' super(errorCode);' + print >> fd, ' }' + print >> fd, '}' + fd.close() + + # Generate classes for Lasso Objects + def generate_lasso_classes(self): + def method_name(m,class_name): + prefix = len(class_name) + if m.rename: + return m.rename + else: + name = utils.format_as_camelcase(m.name[6:]) + name = name[prefix:] + return name[0].lower() + name[1:] + for c in self.binding_data.structs: + class_name = convert_class_name(c.name) + parent_name = c.parent + if parent_name != 'GObject': + parent_name = convert_class_name(parent_name) + path = lasso_java_path + '%s.java' % class_name + fd = open(path,'w') + print >> fd, 'package %s;' % lasso_package_name + do_import_util = 0 + for m in c.members: + if m[0] in ('const GList*','GList*','GHashTable*'): + do_import_util = 1 + for m in c.methods: + if m.return_type in ('const GList*','GList*','GHashTable*'): + do_import_util = 1 + if do_import_util: + print >> fd, 'import java.util.*;' + print >> fd, '' + #print 'class %s extends %s {' % (class_name,parent_name) + print >> fd, 'public class %s extends %s {' % (class_name,parent_name) + # Constructeur private + print >> fd, ' /* Constructors */' + print >> fd, ' protected %s(long cptr) {' % class_name + print >> fd, ' super(cptr);' + print >> fd, ' }' + # Constructeur de base + def cprefix(name): + i = name.find('_new') + if i == -1: + return name + else: + return name[:i].replace('_','').lower() + cons = [ x for x in self.binding_data.functions if cprefix(x.name) == c.name.lower() and x.name.endswith('_new') ] + #print 'cons ', cons + for m in cons: + print >> fd, ' public %s(%s) {' % (class_name, generate_arg_list(self,m.args)) + print >> fd, ' super(LassoJNI.%s(%s));' % (self.JNI_function_name(m),generate_arg_list2(m.args)) + print >> fd, ' }' + # Constructeurs speciaux + cons = [ x for x in self.binding_data.functions if cprefix(x.name) == c.name.lower() and not x.name.endswith('_new') ] + #print 'cons ', cons + for m in cons: + name = method_name(m,class_name) + print >> fd, ' static public %s %s(%s) {' % (class_name, name, generate_arg_list(self,m.args)) + print >> fd, ' return LassoJNI.%s(%s);' % (self.JNI_function_name(m),generate_arg_list2(m.args)) + print >> fd, ' }' + print >> fd, ' /* Setters and getters */' + for m in c.members: + type, name, options = m + prefix = self.JNI_member_function_prefix(c,m) + jname = utils.format_as_camelcase('_'+name) + jtype = self.JNI_member_type(m) + if type == 'GList*' or type == 'const GList*': + print >> fd, ' public void set%s(List list) {' % jname + print >> fd, ' %s[] arr = null;' % jtype + print >> fd, ' if (list != null) {' + print >> fd, ' arr = new %s[list.size()];' % jtype + print >> fd, ' listToArray(list, arr);' + print >> fd, ' }' + print >> fd, ' LassoJNI.%s_set(this, arr);' % prefix + print >> fd, ' }' + print >> fd, ' public List get%s() {' % jname + print >> fd, ' %s[] arr = LassoJNI.%s_get(this);' % (jtype,prefix) + print >> fd, ' if (arr != null)' + print >> fd, ' return Arrays.asList(arr);' + print >> fd, ' else' + print >> fd, ' return null;' + print >> fd, ' }' + print >> fd, ' public void addTo%s(%s value) {' % (jname,jtype) + print >> fd, ' LassoJNI.%s_add(this, value);' % prefix + print >> fd, ' }' + if m[2].get('elem_type') not in ('xmlNode*',): + print >> fd, ' public void removeFrom%s(%s value) {' % (jname,jtype) + print >> fd, ' LassoJNI.%s_remove(this, value);' % prefix + print >> fd, ' }' + elif type == 'GHashTable*': + print >> fd, ' public void set%s(Map map) {' % jname + print >> fd, ' %s[] arr = null;' % jtype + print >> fd, ' if (map != null) {' + print >> fd, ' arr = new %s[map.size()*2];' % jtype + print >> fd, ' mapToArray(map,arr);' + print >> fd, ' }' + print >> fd, ' LassoJNI.%s_set(this, arr);' % prefix + print >> fd, ' }' + print >> fd, ' public Map get%s() {' % jname + print >> fd, ' return arrayToMap(LassoJNI.%s_get(this));' % prefix + print >> fd, ' }' + print >> fd, ' public void addTo%s(String key, %s value) {' % (jname,jtype) + print >> fd, ' LassoJNI.%s_add(this, key, value);' % prefix + print >> fd, ' }' +# print >> fd, ' public void removeFrom%s(String key) {' % (jname) +# print >> fd, ' LassoJNI.%s_remove(this, key);' % prefix +# print >> fd, ' }' + #print ' void set%s(%s[] value)' % (jname,jtype) + #print ' %s[] get%s()' % (jtype,jname) + #print ' void addTo%s(String key, %s value)' % (jname,jtype) + #print ' void removeFrom%s(String key)' % (jname,jtype) + #print ' %s get%sByName(String key)' % (jtype,jname) + else: + print >> fd, ' public void set%s(%s value) {' % (jname,jtype) + print >> fd, ' LassoJNI.%s_set(this, value);' % prefix + print >> fd, ' }' + print >> fd, ' public %s get%s() {' % (jtype,jname) + print >> fd, ' return LassoJNI.%s_get(this);' % prefix + print >> fd, ' }' + #print ' void set%s(%s value)' % (jname,jtype) + #print ' %s get%s()' % (jtype,jname) + print >> fd, ' /* Methods */' + for m in c.methods: + return_type = self.JNI_return_type(m.return_type) + jni_name = self.JNI_function_name(m) + mname = method_name(m,class_name) + args = m.args + doc = m.docstring + def normalize(str,first=' * '): + wrapper = textwrap.TextWrapper() + wrapper.initial_indent = first + wrapper.subsequent_indent = ' * ' + str = re.sub(r'\bNULL\b','null', str) + str = re.sub(r'#Lasso(\w+)',r'{@@link \1}',str) + str = re.sub(r'[^.]*must *be *freed *by[^.]*\.?', '', str) + str = re.sub(r'[^.]*internally[^.]*\.?[^.]*freed[^.]*\.?', '', str) + + str = re.sub(r'[^.]*\bfreed?\b[^.]*\.?', '', str) + str = re.sub(r'(a +)?#?GList\*?','an array', str) + return wrapper.fill(re.sub(r'@\b(\w+)\b',r'\1',str)) + if doc: + first = normalize(doc.description, ' /** ') + if first: + print >> fd, first + else: + print >> fd, ' /**\n' + print >> fd, ' *' + for name, desc in doc.parameters: + print >> fd, normalize(desc, ' * @param %s ' % utils.format_as_camelcase(name)) + if doc.return_value: + print >> fd, normalize(doc.return_value, ' * @return ') + if m.errors: + for err in m.errors: + err = error_to_exception(err)[0] + print >> fd, normalize(err,' * @throws ') + print >> fd, ' **/' + if m.return_type == 'GList*' or m.return_type == 'const GList*': + print >> fd, ' public List %s(%s) {' % (mname,generate_arg_list(self,args[1:])) + arglist = generate_arg_list2(args[1:]) + if arglist: + arglist = ', ' + arglist + print >> fd, ' Object[] arr = LassoJNI.%s(this%s);' % (jni_name,arglist) + print >> fd, ' if (arr != null)' + print >> fd, ' return Arrays.asList(arr);' + print >> fd, ' else' + print >> fd, ' return null;' + print >> fd, ' }' + else: + print >> fd, ' public %s %s(%s) {' % (return_type,mname,generate_arg_list(self,args[1:])) + print >> fd, ' ', + if m.return_type: + print >> fd, 'return', + arglist = generate_arg_list2(args[1:]) + if arglist: + arglist = ', ' + arglist + if m.errors: + print >> fd, 'LassoException.throwError(', + print >> fd,'LassoJNI.%s(this%s)' % (jni_name,arglist), + if m.errors: + print >> fd, ');' + else: + print >> fd, ';' + print >> fd, ' }' + print >> fd, '}' + fd.close() diff --git a/bindings/java/wrapper_bottom.c b/bindings/java/wrapper_bottom.c new file mode 100644 index 00000000..e69de29b diff --git a/bindings/java/wrapper_top.c b/bindings/java/wrapper_top.c new file mode 100644 index 00000000..03736866 --- /dev/null +++ b/bindings/java/wrapper_top.c @@ -0,0 +1,783 @@ +#include +#include +#include +#include "com_entrouvert_lasso_LassoJNI.h" +#include +#include "../ghashtable.h" + +#define LASSO_ROOT "com/entrouvert/lasso/" +#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("LassoJNI"); } } +#define PTR_TO_JLONG(x) (jlong)((ptrdiff_t)x) + +static GQuark lasso_wrapper_key = 0; +typedef int (*Converter)(JNIEnv *env, void *from, jobject *to); +typedef int *(*OutConverter)(JNIEnv *env, jobject from, gpointer *to); + +/* Static declarations */ +static int gpointer_equal(gpointer p1, gpointer p2); +static int new_object_with_gobject(JNIEnv *env, GObject *obj, char *clsName, jobject *jobj); +static int jstring_to_local_string(JNIEnv *env, jstring jstr, const char **str); +static void release_local_string(JNIEnv *env, jstring str, const char *utf_str); +static int get_jlong_field(JNIEnv *env, jobject obj, char *field, jlong *dest); +static jclass get_jclass_by_name(JNIEnv *env, char *name); +static int get_array_element(JNIEnv *env, jobjectArray arr, jsize i, jobject *dest); +static int set_array_element(JNIEnv *env, jobjectArray arr, jsize i, jobject value); +static int get_array_size(JNIEnv *env, jobjectArray arr, jsize *dest); +static int create_object_array(JNIEnv *env, char *clsName, jsize size, jobjectArray *jarr); +static jobject get_shadow_object(JNIEnv *env, GObject *obj); +static void set_shadow_object(JNIEnv *env, GObject *obj, jobject shadow_object); +static void exception(JNIEnv *env, char *message); +static int string_to_jstring(JNIEnv *env, const char* str, jstring *jstr); +static int string_to_jstring_and_free(JNIEnv *env, char* str, jstring *jstr); +static int jstring_to_string(JNIEnv *env, jstring jstr, char **str); +static int xml_node_to_jstring(JNIEnv *env, xmlNode *xmlnode, jstring *jstr); +static int jstring_to_xml_node(JNIEnv *env, jstring jstr, xmlNode **xmlnode); +static int gobject_to_jobject_aux(JNIEnv *env, GObject *obj, gboolean doRef, jobject *job); +static int gobject_to_jobject(JNIEnv *env, GObject *obj, jobject *jobj); +static int gobject_to_jobject_and_ref(JNIEnv *env, GObject *obj, jobject *jobj); + +static int jobject_to_gobject(JNIEnv *env, jobject obj, GObject **gobj); +static int jobject_to_gobject_for_list(JNIEnv *env, jobject *obj, GObject **gobj); +static void free_glist(GList **list, GFunc free_function); +static int get_list(JNIEnv *env, char *clsName, GList *list, Converter convert, jobjectArray *jarr); +static int set_list(JNIEnv *env, GList **list, jobjectArray jarr, GFunc free_function, OutConverter convert); +static int remove_from_list(JNIEnv *env,GList **list,jobject obj,GFunc free_function,GCompareFunc compare,OutConverter convert); +static int add_to_list(JNIEnv* env, GList** list, jobject obj, OutConverter convert); +static int get_hash(JNIEnv *env, char *clsName, GHashTable *hashtable, Converter convert, jobjectArray *jarr); +static int set_hash_of_objects(JNIEnv *env, GHashTable *hashtable, jobjectArray jarr); +static int set_hash_of_strings(JNIEnv *env, GHashTable *hashtable, jobjectArray jarr); +static int remove_from_hash(JNIEnv *env, GHashTable *hashtable, jstring jkey); +static int add_to_hash(JNIEnv *env, GHashTable *hashtable, jstring jkey, jobject jvalue, OutConverter convert, GFunc free_function); +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_for_list) +// 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) +#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_for_list) +#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_for_list,(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) + + +static int +gpointer_equal(gpointer p1, gpointer p2) { + return p1 != p2; +} +static int +new_object_with_gobject(JNIEnv *env, GObject *obj, char *clsName, jobject *jobj) { + jclass cls; + jmethodID mid; + + g_error_if_fail(env && clsName && obj && G_IS_OBJECT(obj)); + + g_return_val_if_fail((cls = (*env)->FindClass(env, clsName)), 0); + g_return_val_if_fail((mid = (*env)->GetMethodID(env, cls, "", "(J)V")), 0); + g_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); + g_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, char *field, jlong *dest) +{ + jclass cls; + jfieldID fid; + + cls = (*env)->GetObjectClass(env, obj); + g_return_val_if_fail(cls, 0); + fid = (*env)->GetFieldID(env, cls, field, "J"); + g_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, 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); + g_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, char *clsName, jsize size, jobjectArray *jarr) { + jclass cls; + + g_error_if_fail(env && clsName && jarr); + + cls = get_jclass_by_name(env, clsName); + g_return_val_if_fail(cls, 0); + *jarr = (*env)->NewObjectArray(env, size, get_jclass_by_name(env, clsName), NULL); + g_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, lasso_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, lasso_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, lasso_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, lasso_wrapper_key, NULL); + if (shadow_object) { + weakRef = (*env)->NewWeakGlobalRef(env, shadow_object); + g_object_set_qdata(obj, lasso_wrapper_key, weakRef); + } +} +/** Throw a new RuntimeException containing this message. */ +static void +exception(JNIEnv *env, char *message) { + jclass cls = (*env)->FindClass(env, "java/lang/RuntimeException"); + if (cls != NULL) { + (*env)->ThrowNew(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); + g_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) { + g_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; + + g_return_val_if_fail(jstring_to_local_string(env, jstr, &local_str), 0); + if (local_str) { + *str = g_strdup(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; + + 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; + if (buf->conv == NULL) { + str = (char*)buf->buffer->content; + } else { + str = buf->conv->content; + } + ret = string_to_jstring(env, 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; + int ret = 1; + + g_error_if_fail(env && xmlnode); + g_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); + if (node != NULL) { + node = xmlCopyNode(node, 1); + } + } +out: + *xmlnode = node; + if (doc) + xmlFreeDoc(doc); + if (jstr && local_str) + release_local_string(env, jstr, local_str); + return ret; +} + +/* lasso objects handling impl */ +static void +create_class_name(char *dest, const char *typename) { + char *ret; + + ret = strstr(typename, "Lasso"); + if (ret) { + typename = ret+5; + } + strncpy(dest+sizeof(LASSO_ROOT)-1, typename,50); + dest[sizeof(LASSO_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(LASSO_ROOT)+50] = LASSO_ROOT; + const char *typename; + + 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 a new java object encapsulating this lasso 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 lasso 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; + GObject *gobject; + + g_error_if_fail(env); + + if (! obj) { + *gobj = NULL; + return 1; + } + g_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 { + *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_for_list(JNIEnv *env, jobject *obj, GObject **gobj) { + g_return_val_if_fail(jobject_to_gobject(env, obj, gobj), 0); + if (*gobj) { + g_object_ref(*gobj); + } + return 1; +} + +/* List handling */ +static void +free_glist(GList **list, GFunc free_function) { + g_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, char *clsName, GList *list, Converter convert, jobjectArray *jarr) { + jsize l,i; + jclass cls; + + g_error_if_fail (env && clsName && convert); + l = g_list_length(list); + if (!l) { + *jarr = NULL; + goto out; + } + cls = get_jclass_by_name(env, clsName); + g_return_val_if_fail(cls, 0); + + g_return_val_if_fail(create_object_array(env, clsName, l, jarr), 0); + for (i=0;idata, &item), 0); + g_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; + jsize size; + jsize i; + 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; + + 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; + GList *found; + + g_error_if_fail(env && list && compare && convert && free_function); + g_return_val_if_fail(obj, 1); + g_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; + GList *found; + + g_error_if_fail(env && list); + g_return_val_if_fail(jstr, 1); + g_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; + + g_error_if_fail(env && list && convert); + g_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,i; + + GList *keys = NULL, *values = NULL; + int ret = 1; + + g_error_if_fail (env && hashtable && convert); + l = g_hash_table_size(hashtable); + g_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; + jobject value; + + 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, i; + gpointer *array; + + g_error_if_fail (env && hashtable); + if (jarr) { + /** First increment ref count of object in jarr */ + g_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; + GObject *gobj; + + g_return_val_if_fail(get_array_element(env, jarr, i, &jobj), 0); + g_return_val_if_fail(jobject_to_gobject(env, jobj, &gobj), 0); + g_object_ref(gobj); + } + } + /** Remove old values, if hashtable is well initialized + * it should unref objects automatically. */ + g_hashtable_remove_all(hashtable); + /** Insert new values */ + if (jarr) { + for (i = 0; i < l; i += 2) { + jstring jkey; + char *key; + jobject jvalue; + GObject *value; + + g_return_val_if_fail(get_array_element(env, jarr, i, &jkey), 0); + g_return_val_if_fail(get_array_element(env, jarr, i+1, &jvalue), 0); + g_return_val_if_fail(jstring_to_string(env, jkey, &key), 0); + if (! jobject_to_gobject(env, jvalue, &value)) { + if (key) + g_free(key); + g_hashtable_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; +} +/** 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,i; + + g_error_if_fail (env && hashtable); + + g_hash_table_remove_all(hashtable); + if (jarr) { + g_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; + char *key; + jstring jvalue; + char *value; + + g_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), 0) { + 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; + + g_error_if_fail (env && hashtable); + + g_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; + gpointer value; + + g_error_if_fail (env && hashtable && convert); + + g_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); +} + +/* 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"); +} +JNIEXPORT void JNICALL Java_com_entrouvert_lasso_LassoJNI_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_lasso_LassoJNI_set_1shadow_1object(JNIEnv *env, jclass cls, jlong cptr, jobject shadow_object) { + GObject *gobj; + + gobj = convert_jlong_to_gobject(cptr); + set_shadow_object(env, gobj, shadow_object); +} -- cgit