summaryrefslogtreecommitdiffstats
path: root/bindings/java
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2008-08-05 14:53:03 +0000
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2008-08-05 14:53:03 +0000
commit1226b060bd441761cac5c9afe44dca92ec69e6e8 (patch)
treeb12d0aa4a9f389e0dd0e39764ea8f433c4668216 /bindings/java
parentf020bb88f6a9157747b12fcc3ad34581eb77d473 (diff)
downloadlasso-1226b060bd441761cac5c9afe44dca92ec69e6e8.tar.gz
lasso-1226b060bd441761cac5c9afe44dca92ec69e6e8.tar.xz
lasso-1226b060bd441761cac5c9afe44dca92ec69e6e8.zip
Move all files related to java into the java subdirectory
Diffstat (limited to 'bindings/java')
-rw-r--r--bindings/java/Makefile.am2
-rw-r--r--bindings/java/lang.py902
-rw-r--r--bindings/java/wrapper_bottom.c0
-rw-r--r--bindings/java/wrapper_top.c783
4 files changed, 1686 insertions, 1 deletions
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
--- /dev/null
+++ b/bindings/java/wrapper_bottom.c
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 <lasso/lasso.h>
+#include <config.h>
+#include <jni.h>
+#include "com_entrouvert_lasso_LassoJNI.h"
+#include <string.h>
+#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, "<init>", "(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;i<l;i++) {
+ jobject item;
+
+ g_return_val_if_fail(convert(env, list->data, &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);
+}