rjb 1.3.0-universal-darwin-10

Sign up to get free protection for your applications and to get access to all the features.
data/ext/riconv.c ADDED
@@ -0,0 +1,218 @@
1
+ /*
2
+ * Rjb - Ruby <-> Java Bridge
3
+ * Copyright(c) 2004 Kuwashima
4
+ *
5
+ * This library is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * This library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * $Id: riconv.c 117 2010-06-04 12:16:25Z arton $
16
+ */
17
+
18
+ #include "ruby.h"
19
+ #include "extconf.h"
20
+
21
+ #if defined _WIN32 || defined __CYGWIN__
22
+ #include <windows.h>
23
+ #endif
24
+
25
+ #if defined HAVE_NL_LANGINFO
26
+ #include <langinfo.h>
27
+ static const char* const NL_EUC_TABLE[] = { "EUC-JISX0213", "EUC-JP", "EUC-JP-MS" };
28
+ static const char* const NL_SJIS_TABLE[] = { "SHIFT_JIS", "SHIFT_JISX0213", "WINDOWS-31J" };
29
+ #endif
30
+
31
+ #if defined HAVE_SETLOCALE
32
+ #include <locale.h>
33
+ #endif
34
+ static const char* const LOCALE_EUC_TABLE[] = { "japanese", "ja_JP.eucJP", "japanese.euc", "ja_JP", "ja_JP.ujis" };
35
+ static const char* const LOCALE_SJIS_TABLE[] = { "japanese.sjis", "ja_JP.SJIS" };
36
+ static const char* const LOCALE_UTF8_TABLE[] = { "ja_JP.UTF-8", "ja_JP.utf8" };
37
+
38
+ #include "riconv.h"
39
+
40
+ static const char* const CS_EUCJP = "EUC-JP";
41
+ static const char* const CS_CP932 = "CP932";
42
+ static const char* const CS_SJIS = "SHIFT_JIS";
43
+ static const char* const CS_UTF8 = "UTF-8";
44
+
45
+
46
+ #if RJB_RUBY_VERSION_CODE < 190
47
+ static VALUE objIconvJ2R;
48
+ static VALUE objIconvR2J;
49
+ static const char* charcode; //is this necessary?
50
+ static char Kcode = '\0';
51
+
52
+ static int find_table(const char* const str, const char* const table[])
53
+ {
54
+ int i;
55
+ int size = sizeof(table) / sizeof(table[0]);
56
+ for (i = 0; i < size; ++i)
57
+ {
58
+ if (strstr(str, table[i])) return 1;
59
+ }
60
+ return 0;
61
+ }
62
+ #endif
63
+
64
+ #if RJB_RUBY_VERSION_CODE < 190
65
+ static const char* get_charcode_name_by_locale(const char* const name)
66
+ {
67
+ if (find_table(name, LOCALE_UTF8_TABLE))
68
+ return NULL;
69
+ else if (find_table(name, LOCALE_EUC_TABLE))
70
+ return CS_EUCJP;
71
+ else if (find_table(name, LOCALE_SJIS_TABLE))
72
+ return CS_SJIS;
73
+ else
74
+ return NULL;
75
+ }
76
+ /*
77
+ * Get better charcode name.
78
+ */
79
+ static const char* get_charcode_name()
80
+ {
81
+ const char* result = NULL;
82
+ const char* lang = NULL;
83
+
84
+ switch(Kcode)
85
+ {
86
+ case 'E':
87
+ result = CS_EUCJP;
88
+ break;
89
+ case 'S':
90
+ #if defined _WIN32 || defined __CYGWIN__
91
+ result = CS_CP932;
92
+ #else
93
+ result = CS_SJIS;
94
+ #endif
95
+ break;
96
+ case 'U':
97
+ //as is.
98
+ break;
99
+ case 'N':
100
+ default:
101
+ #if defined _WIN32 || defined __CYGWIN__
102
+ if (932 == GetACP()) result = CS_CP932;
103
+ #elif defined HAVE_NL_LANGINFO
104
+ setlocale(LC_ALL, "C"); //initialize
105
+ lang = nl_langinfo(CODESET);
106
+ if (find_table(lang, NL_EUC_TABLE))
107
+ result = CS_EUCJP;
108
+ else if (find_table(lang, NL_SJIS_TABLE))
109
+ result = CS_SJIS;
110
+ #elif defined HAVE_SETLOCALE
111
+ setlocale(LC_ALL, "C"); //initialize
112
+ result = get_charcode_name_by_locale(setlocale(LC_ALL, NULL));
113
+ #elif defined HAVE_GETENV
114
+ if (result = get_charcode_name_by_locale(getenv("LC_ALL")))
115
+ ;
116
+ else if (result = get_charcode_name_by_locale(getenv("LC_CTYPE")))
117
+ ;
118
+ else if (result = get_charcode_name_by_locale(getenv("LANG")))
119
+ ;
120
+ #endif
121
+ break;
122
+ }
123
+ return result;
124
+ }
125
+ #endif
126
+
127
+ #if RJB_RUBY_VERSION_CODE < 190
128
+ static void reinit()
129
+ {
130
+ charcode = get_charcode_name();
131
+ if (charcode)
132
+ {
133
+ VALUE rb_iconv_klass = rb_const_get(rb_cObject, rb_intern("Iconv"));
134
+ if (RTEST(rb_iconv_klass)) {
135
+ ID sym_new = rb_intern("new");
136
+ rb_gc_unregister_address(&objIconvR2J);
137
+ objIconvR2J = rb_funcall(rb_iconv_klass, sym_new, 2, rb_str_new2(CS_UTF8), rb_str_new2(charcode));
138
+ rb_gc_register_address(&objIconvR2J);
139
+ rb_gc_unregister_address(&objIconvJ2R);
140
+ objIconvJ2R = rb_funcall(rb_iconv_klass, sym_new, 2, rb_str_new2(charcode), rb_str_new2(CS_UTF8));
141
+ rb_gc_register_address(&objIconvJ2R);
142
+ }
143
+ }
144
+ else
145
+ {
146
+ objIconvR2J = objIconvJ2R = Qnil;
147
+ }
148
+ }
149
+ #endif
150
+
151
+ #if RJB_RUBY_VERSION_CODE < 190
152
+ static void check_kcode()
153
+ {
154
+ VALUE rb_iconv_klass = rb_const_get(rb_cObject, rb_intern("Iconv"));
155
+ VALUE kcode = rb_gv_get("$KCODE");
156
+ if (RTEST(rb_iconv_klass) && TYPE(kcode) == T_STRING) {
157
+ char* kcodep = StringValuePtr(kcode);
158
+ char upper_kcode = toupper(*kcodep);
159
+ if (Kcode != upper_kcode)
160
+ {
161
+ Kcode = upper_kcode;
162
+ reinit();
163
+ }
164
+ }
165
+ else
166
+ {
167
+ objIconvR2J = objIconvJ2R = Qnil;
168
+ }
169
+ }
170
+ #endif
171
+
172
+ VALUE exticonv_local_to_utf8(VALUE local_string)
173
+ {
174
+ #if RJB_RUBY_VERSION_CODE < 190
175
+ check_kcode();
176
+ if(RTEST(objIconvR2J))
177
+ {
178
+ return rb_funcall(objIconvR2J, rb_intern("iconv"), 1, local_string);
179
+ }
180
+ else
181
+ {
182
+ return local_string;
183
+ }
184
+ #else
185
+ VALUE rb_cEncoding, encoding, sjis, eucjp, iso2022jp;
186
+ rb_cEncoding = rb_const_get(rb_cObject, rb_intern("Encoding"));
187
+ sjis = rb_const_get(rb_cEncoding, rb_intern("SHIFT_JIS"));
188
+ eucjp = rb_const_get(rb_cEncoding, rb_intern("EUC_JP"));
189
+ iso2022jp = rb_const_get(rb_cEncoding, rb_intern("ISO_2022_JP"));
190
+ encoding = rb_funcall(local_string, rb_intern("encoding"), 0);
191
+
192
+ if (encoding == sjis || encoding == eucjp || encoding == iso2022jp)
193
+ {
194
+ return rb_funcall(local_string, rb_intern("encode"), 1, rb_str_new2("utf-8"));
195
+ }
196
+ else
197
+ {
198
+ return local_string;
199
+ }
200
+ #endif
201
+ }
202
+
203
+ VALUE exticonv_utf8_to_local(VALUE utf8_string)
204
+ {
205
+ #if RJB_RUBY_VERSION_CODE < 190
206
+ check_kcode();
207
+ if(RTEST(objIconvR2J))
208
+ {
209
+ return rb_funcall(objIconvJ2R, rb_intern("iconv"), 1, utf8_string);
210
+ }
211
+ else
212
+ {
213
+ return utf8_string;
214
+ }
215
+ #else
216
+ return rb_funcall(utf8_string, rb_intern("force_encoding"), 1, rb_str_new2("utf-8"));
217
+ #endif
218
+ }
data/ext/riconv.h ADDED
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Rjb - Ruby <-> Java Bridge
3
+ * Copyright(c) 2004 Kuwashima
4
+ *
5
+ * This library is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * This library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * $Id: riconv.h 43 2007-12-26 18:55:04Z kuwa1 $
16
+ */
17
+ #ifndef _RICONV_H
18
+ #define _RICONV_H
19
+
20
+
21
+ VALUE exticonv_local_to_utf8(VALUE);
22
+ VALUE exticonv_utf8_to_local(VALUE);
23
+
24
+ #endif /* _RICONV_H */
data/ext/rjb.c ADDED
@@ -0,0 +1,3170 @@
1
+ /*
2
+ * Rjb - Ruby <-> Java Bridge
3
+ * Copyright(c) 2004,2005,2006,2007,2008,2009,2010 arton
4
+ *
5
+ * This library is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * This library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * $Id: rjb.c 147 2010-10-23 05:10:33Z arton $
16
+ */
17
+
18
+ #define RJB_VERSION "1.3.0"
19
+
20
+ #include "ruby.h"
21
+ #include "extconf.h"
22
+ #if RJB_RUBY_VERSION_CODE < 190
23
+ #include "st.h"
24
+ #else
25
+ #include "ruby/st.h"
26
+ #endif
27
+ #include "jniwrap.h"
28
+ #include "jp_co_infoseek_hp_arton_rjb_RBridge.h"
29
+ #include "riconv.h"
30
+ #include "rjb.h"
31
+ #include "ctype.h"
32
+
33
+ /*
34
+ * Method Modifier Flag defined in
35
+ * http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88358
36
+ */
37
+ #define ACC_PUBLIC 0x0001
38
+ #define ACC_PRIVATE 0x0002
39
+ #define ACC_PROTECTED 0x0004
40
+ #define ACC_STATIC 0x0008
41
+ #define ACC_FINAL 0x0010
42
+ #define ACC_VOLATILE 0x0040
43
+ #define ACC_TRANSIENT 0x0080
44
+
45
+ #define RJB_FIND_CLASS(var, name) \
46
+ var = rjb_find_class_by_name(jenv, name); \
47
+ rjb_check_exception(jenv, 1)
48
+ #define RJB_HOLD_CLASS(var, name) \
49
+ var = rjb_find_class_by_name(jenv, name); \
50
+ rjb_check_exception(jenv, 1); \
51
+ var = (*jenv)->NewGlobalRef(jenv, var)
52
+ #define RJB_LOAD_METHOD(var, obj, name, sig) \
53
+ var = (*jenv)->GetMethodID(jenv, obj, name, sig); \
54
+ rjb_check_exception(jenv, 1)
55
+ #define RJB_LOAD_STATIC_METHOD(var, obj, name, sig) \
56
+ var = (*jenv)->GetStaticMethodID(jenv, obj, name, sig); \
57
+ rjb_check_exception(jenv, 1)
58
+ #if defined(RUBINIUS)
59
+ #define CLASS_NEW(obj, name) rb_define_class_under(rjb, name, obj)
60
+ #define CLASS_INHERITED(spr, kls) rb_funcall(spr, rb_intern("inherited"), 1, kls)
61
+ #else
62
+ #define CLASS_NEW(obj, name) rb_define_class_under(rjb, name, obj)
63
+ #define CLASS_INHERITED(spr, kls) rb_class_inherited(spr, kls)
64
+ #endif
65
+ #define IS_RJB_OBJECT(v) (CLASS_INHERITED(rjbi, rb_obj_class(v)) || rb_obj_class(v) == rjb)
66
+ #define USER_INITIALIZE "@user_initialize"
67
+
68
+ static void register_class(VALUE, VALUE);
69
+ static VALUE import_class(JNIEnv* jenv, jclass, VALUE);
70
+ static VALUE register_instance(JNIEnv* jenv, VALUE klass, struct jv_data*, jobject);
71
+ static VALUE rjb_s_free(struct jv_data*);
72
+ static VALUE rjb_class_forname(int argc, VALUE* argv, VALUE self);
73
+ static void setup_metadata(JNIEnv* jenv, VALUE self, struct jv_data*, VALUE classname);
74
+ static VALUE jarray2rv(JNIEnv* jenv, jvalue val);
75
+ static jarray r2objarray(JNIEnv* jenv, VALUE v, const char* cls);
76
+ static VALUE jv2rv_withprim(JNIEnv* jenv, jobject o);
77
+ static J2R get_arrayconv(const char* cname, char* depth);
78
+
79
+ static VALUE rjb;
80
+ static VALUE jklass;
81
+ static VALUE rjbc;
82
+ static VALUE rjbi;
83
+ static VALUE rjbb;
84
+
85
+ static ID user_initialize;
86
+ static ID cvar_classpath;
87
+
88
+ VALUE rjb_loaded_classes;
89
+ static VALUE proxies;
90
+ JavaVM* rjb_jvm;
91
+ jclass rjb_rbridge;
92
+ jmethodID rjb_register_bridge;
93
+ jmethodID rjb_load_class;
94
+ static JNIEnv* main_jenv;
95
+ static VALUE primitive_conversion = Qfalse;
96
+
97
+ /*
98
+ * Object cache, never destroyed
99
+ */
100
+ /* method */
101
+ static jmethodID method_getModifiers;
102
+ static jmethodID method_getName;
103
+ static jmethodID getParameterTypes;
104
+ static jmethodID getReturnType;
105
+ /* field */
106
+ static jmethodID field_getModifiers;
107
+ static jmethodID field_getName;
108
+ static jmethodID field_getType;
109
+ /* constructor */
110
+ static jmethodID ctrGetParameterTypes;
111
+ /* class */
112
+ static jclass j_class;
113
+ jmethodID rjb_class_getName;
114
+ /* throwable */
115
+ jclass rjb_j_throwable;
116
+ jmethodID rjb_throwable_getMessage;
117
+ /* String global reference */
118
+ static jclass j_string;
119
+ static jmethodID str_tostring;
120
+ /* Object global reference */
121
+ static jclass j_object;
122
+ /* ClassLoader */
123
+ static jclass j_classloader;
124
+ static jmethodID get_system_classloader;
125
+ /* URLClassLoader */
126
+ static jclass j_url_loader;
127
+ static jobject url_loader;
128
+ static jmethodID url_loader_new;
129
+ /* URL global reference */
130
+ static jclass j_url;
131
+ static jmethodID url_new;
132
+
133
+ enum PrimitiveType {
134
+ PRM_INT = 0,
135
+ PRM_LONG,
136
+ PRM_DOUBLE,
137
+ PRM_BOOLEAN,
138
+ PRM_CHARACTER,
139
+ PRM_SHORT,
140
+ PRM_BYTE,
141
+ PRM_FLOAT,
142
+ /* */
143
+ PRM_LAST
144
+ };
145
+
146
+ /*
147
+ * Native type conversion table
148
+ */
149
+ typedef struct jobject_ruby_table {
150
+ const char* classname;
151
+ const char* to_prim_method;
152
+ const char* prmsig;
153
+ const char* ctrsig;
154
+ jclass klass; /* primitive class */
155
+ jmethodID to_prim_id;
156
+ jmethodID ctr_id;
157
+ J2R func;
158
+ } jprimitive_table;
159
+
160
+ JNIEnv* rjb_attach_current_thread(void)
161
+ {
162
+ JNIEnv* env;
163
+ (*rjb_jvm)->AttachCurrentThread(rjb_jvm, (void**)&env, '\0');
164
+ return env;
165
+ }
166
+
167
+ void rjb_release_string(JNIEnv *jenv, jstring str, const char* chrs)
168
+ {
169
+ (*jenv)->ReleaseStringUTFChars(jenv, str, chrs);
170
+ (*jenv)->DeleteLocalRef(jenv, str);
171
+ }
172
+
173
+ static char* java2jniname(char* jnicls)
174
+ {
175
+ char* p;
176
+ for (p = jnicls; *p; p++)
177
+ {
178
+ if (*p == '.')
179
+ {
180
+ *p = '/';
181
+ }
182
+ }
183
+ return jnicls;
184
+ }
185
+
186
+ static char* jniname2java(char* jniname)
187
+ {
188
+ char* p;
189
+ for (p = jniname; *p; p++)
190
+ {
191
+ if (*p == '/')
192
+ {
193
+ *p = '.';
194
+ }
195
+ }
196
+ return jniname;
197
+ }
198
+
199
+ static char* next_sig(char* p)
200
+ {
201
+ if (!*p)
202
+ {
203
+ return p;
204
+ }
205
+ if (*p == '[')
206
+ {
207
+ p++;
208
+ }
209
+ if (*p == 'L')
210
+ {
211
+ while (*p && *p != ';')
212
+ {
213
+ p++;
214
+ }
215
+ }
216
+ return (*p) ? ++p : p;
217
+ }
218
+
219
+ static VALUE jstring2val(JNIEnv* jenv, jstring s)
220
+ {
221
+ const char* p;
222
+ VALUE v;
223
+
224
+ if (s == NULL)
225
+ {
226
+ return Qnil;
227
+ }
228
+ p = (*jenv)->GetStringUTFChars(jenv, s, NULL);
229
+ v = rb_str_new2(p);
230
+ v = exticonv_utf8_to_local(v);
231
+ rjb_release_string(jenv, s, p);
232
+ return v;
233
+ }
234
+
235
+ /*
236
+ * Type conversion tables
237
+ */
238
+ typedef struct type_conversion_table {
239
+ const char* jtype;
240
+ const char* jntype;
241
+ R2J r2j;
242
+ J2R j2r;
243
+ J2R ja2r;
244
+ R2JARRAY r2ja;
245
+ off_t jcall; /* for instance method */
246
+ off_t jscall; /* for static method */
247
+ } jconv_table;
248
+
249
+ /*
250
+ * conversion methods
251
+ * val will be released in this function.
252
+ */
253
+ static VALUE jv2rclass(JNIEnv* jenv, jclass jc)
254
+ {
255
+ const char* cname;
256
+ VALUE clsname;
257
+ VALUE v;
258
+ jstring nm = (*jenv)->CallObjectMethod(jenv, jc, rjb_class_getName);
259
+ rjb_check_exception(jenv, 0);
260
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
261
+ clsname = rb_str_new2(cname);
262
+ rjb_release_string(jenv, nm, cname);
263
+ v = rb_hash_aref(rjb_loaded_classes, clsname);
264
+ if (v == Qnil)
265
+ {
266
+ v = import_class(jenv, jc, clsname);
267
+ }
268
+ (*jenv)->DeleteLocalRef(jenv, jc);
269
+ return v;
270
+ }
271
+
272
+ static VALUE jv2rv_r(JNIEnv* jenv, jvalue val)
273
+ {
274
+ const char* cname;
275
+ jstring nm;
276
+ jclass klass;
277
+ VALUE clsname;
278
+ VALUE v;
279
+ struct jv_data* ptr;
280
+ /* object to ruby */
281
+ if (!val.l) return Qnil;
282
+ klass = (*jenv)->GetObjectClass(jenv, val.l);
283
+
284
+ if ((*jenv)->IsSameObject(jenv, klass, j_class))
285
+ {
286
+ (*jenv)->DeleteLocalRef(jenv, klass);
287
+ return jv2rclass(jenv, val.l);
288
+ }
289
+ nm = (*jenv)->CallObjectMethod(jenv, klass, rjb_class_getName);
290
+ rjb_check_exception(jenv, 0);
291
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
292
+ if (*cname == '[')
293
+ {
294
+ char depth = 0;
295
+ J2R j2r = get_arrayconv(cname, &depth);
296
+ rjb_release_string(jenv, nm, cname);
297
+ v = j2r(jenv, val);
298
+ (*jenv)->DeleteLocalRef(jenv, klass);
299
+ (*jenv)->DeleteLocalRef(jenv, val.l);
300
+ return v;
301
+ }
302
+ clsname = rb_str_new2(cname);
303
+ rjb_release_string(jenv, nm, cname);
304
+ v = rb_hash_aref(rjb_loaded_classes, clsname);
305
+ if (v == Qnil)
306
+ {
307
+ v = import_class(jenv, klass, clsname);
308
+ }
309
+ Data_Get_Struct(v, struct jv_data, ptr);
310
+ v = register_instance(jenv, v, (struct jv_data*)ptr, val.l);
311
+ (*jenv)->DeleteLocalRef(jenv, klass);
312
+ (*jenv)->DeleteLocalRef(jenv, val.l);
313
+ return v;
314
+ }
315
+
316
+ VALUE jv2rv(JNIEnv* jenv, jvalue val)
317
+ {
318
+ if (RTEST(primitive_conversion))
319
+ {
320
+ return jv2rv_withprim(jenv, val.l);
321
+ }
322
+ return jv2rv_r(jenv, val);
323
+ }
324
+
325
+ static VALUE jvoid2rv(JNIEnv* jenv, jvalue val)
326
+ {
327
+ return Qnil;
328
+ }
329
+
330
+ static VALUE jbyte2rv(JNIEnv* jenv, jvalue val)
331
+ {
332
+ return INT2NUM(val.b);
333
+ }
334
+
335
+ static VALUE jchar2rv(JNIEnv* jenv, jvalue val)
336
+ {
337
+ return INT2NUM(val.c);
338
+ }
339
+
340
+ static VALUE jdouble2rv(JNIEnv* jenv, jvalue val)
341
+ {
342
+ return rb_float_new(val.d);
343
+ }
344
+
345
+ static VALUE jfloat2rv(JNIEnv* jenv, jvalue val)
346
+ {
347
+ return rb_float_new((double)val.f);
348
+ }
349
+
350
+ static VALUE jint2rv(JNIEnv* jenv, jvalue val)
351
+ {
352
+ return INT2NUM(val.i);
353
+ }
354
+
355
+ static VALUE jlong2rv(JNIEnv* jenv, jvalue val)
356
+ {
357
+ #if HAVE_LONG_LONG
358
+ return LL2NUM(val.j);
359
+ #else
360
+ char bignum[64];
361
+ sprintf(bignum, "%ld * 0x100000000 + 0x%lx",
362
+ (long)(val.j >> 32), (unsigned long)val.j);
363
+ return rb_eval_string(bignum);
364
+ #endif
365
+ }
366
+
367
+ static VALUE jshort2rv(JNIEnv* jenv, jvalue val)
368
+ {
369
+ return INT2NUM(val.s);
370
+ }
371
+
372
+ static VALUE jboolean2rv(JNIEnv* jenv, jvalue val)
373
+ {
374
+ return (val.z) ? Qtrue : Qfalse;
375
+ }
376
+
377
+ static VALUE jstring2rv(JNIEnv* jenv, jvalue val)
378
+ {
379
+ return jstring2val(jenv, (jstring)val.l);
380
+ }
381
+
382
+ static VALUE ja2r(J2R conv, JNIEnv* jenv, jvalue val, int depth)
383
+ {
384
+ jsize len;
385
+ VALUE v;
386
+ int i;
387
+ if (!val.l) return Qnil;
388
+ if (depth == 1)
389
+ {
390
+ return conv(jenv, val);
391
+ }
392
+ len = (*jenv)->GetArrayLength(jenv, val.l);
393
+ v = rb_ary_new2(len);
394
+ for (i = 0; i < len; i++)
395
+ {
396
+ jvalue wrap;
397
+ wrap.l = (*jenv)->GetObjectArrayElement(jenv, val.l, i);
398
+ rb_ary_push(v, ja2r(conv, jenv, wrap, depth - 1));
399
+ }
400
+ (*jenv)->DeleteLocalRef(jenv, val.l);
401
+ return v;
402
+ }
403
+
404
+ static VALUE jarray2rv(JNIEnv* jenv, jvalue val)
405
+ {
406
+ jsize len;
407
+ VALUE v;
408
+ int i;
409
+ if (!val.l) return Qnil;
410
+ len = (*jenv)->GetArrayLength(jenv, val.l);
411
+ v = rb_ary_new2(len);
412
+ for (i = 0; i < len; i++)
413
+ {
414
+ jvalue wrap;
415
+ wrap.l = (*jenv)->GetObjectArrayElement(jenv, val.l, i);
416
+ /* wrap.l will be release in jv2rv */
417
+ rb_ary_push(v, jv2rv(jenv, wrap));
418
+ }
419
+ (*jenv)->DeleteLocalRef(jenv, val.l);
420
+ return v;
421
+ }
422
+
423
+ static VALUE ca2rv(JNIEnv* jenv, void* p)
424
+ {
425
+ return INT2FIX(*(jchar*)p);
426
+ }
427
+
428
+ static VALUE da2rv(JNIEnv* jenv, void* p)
429
+ {
430
+ return rb_float_new(*(jdouble*)p);
431
+ }
432
+
433
+ static VALUE fa2rv(JNIEnv* jenv, void* p)
434
+ {
435
+ return rb_float_new(*(jfloat*)p);
436
+ }
437
+
438
+ static VALUE ia2rv(JNIEnv* jenv, void* p)
439
+ {
440
+ return INT2NUM(*(jint*)p);
441
+ }
442
+
443
+ static VALUE la2rv(JNIEnv* jenv, void* p)
444
+ {
445
+ #if HAVE_LONG_LONG
446
+ return LL2NUM(*(jlong*)p);
447
+ #else
448
+ return LONG2NUM(*(jlong*)p);
449
+ #endif
450
+ }
451
+
452
+ static VALUE sa2rv(JNIEnv* jenv, void* p)
453
+ {
454
+ return INT2FIX(*(jshort*)p);
455
+ }
456
+
457
+ static VALUE ba2rv(JNIEnv* jenv, void* p)
458
+ {
459
+ return (*(jboolean*)p) ? Qtrue : Qfalse;
460
+ }
461
+
462
+ /*
463
+ * val : released in this function.
464
+ */
465
+ static VALUE call_conv(JNIEnv* jenv, jvalue val, size_t sz, void* p, CONV conv, size_t fnc)
466
+ {
467
+ int i;
468
+ char* cp = (char*)p;
469
+ jsize len = (*jenv)->GetArrayLength(jenv, val.l);
470
+ VALUE v = rb_ary_new2(len);
471
+ for (i = 0; i < len; i++)
472
+ {
473
+ rb_ary_push(v, conv(jenv, cp));
474
+ cp += sz;
475
+ }
476
+ (*(RELEASEARRAY*)(((char*)*jenv) + fnc))(jenv, val.l, p, JNI_ABORT);
477
+ (*jenv)->DeleteLocalRef(jenv, val.l);
478
+ return v;
479
+ }
480
+
481
+ static VALUE jbytearray2rv(JNIEnv* jenv, jvalue val)
482
+ {
483
+ jsize len = (*jenv)->GetArrayLength(jenv, val.l);
484
+ jbyte* p = (*jenv)->GetByteArrayElements(jenv, val.l, NULL);
485
+ VALUE v = rb_str_new((char*)p, len);
486
+ (*jenv)->ReleaseByteArrayElements(jenv, val.l, p, JNI_ABORT);
487
+ (*jenv)->DeleteLocalRef(jenv, val.l);
488
+ return v;
489
+ }
490
+ static VALUE jchararray2rv(JNIEnv* jenv, jvalue val)
491
+ {
492
+ jchar* p = (*jenv)->GetCharArrayElements(jenv, val.l, NULL);
493
+ return call_conv(jenv, val, sizeof(jchar), p, ca2rv,
494
+ offsetof(struct JNINativeInterface_, ReleaseCharArrayElements));
495
+ }
496
+ static VALUE jdoublearray2rv(JNIEnv* jenv, jvalue val)
497
+ {
498
+ jdouble* p = (*jenv)->GetDoubleArrayElements(jenv, val.l, NULL);
499
+ return call_conv(jenv, val, sizeof(jdouble), p, da2rv,
500
+ offsetof(struct JNINativeInterface_, ReleaseDoubleArrayElements));
501
+ }
502
+ static VALUE jfloatarray2rv(JNIEnv* jenv, jvalue val)
503
+ {
504
+ jfloat* p = (*jenv)->GetFloatArrayElements(jenv, val.l, NULL);
505
+ return call_conv(jenv, val, sizeof(jfloat), p, fa2rv,
506
+ offsetof(struct JNINativeInterface_, ReleaseFloatArrayElements));
507
+ }
508
+ static VALUE jintarray2rv(JNIEnv* jenv, jvalue val)
509
+ {
510
+ jint* p = (*jenv)->GetIntArrayElements(jenv, val.l, NULL);
511
+ return call_conv(jenv, val, sizeof(jint), p, ia2rv,
512
+ offsetof(struct JNINativeInterface_, ReleaseIntArrayElements));
513
+ }
514
+ static VALUE jlongarray2rv(JNIEnv* jenv, jvalue val)
515
+ {
516
+ jlong* p = (*jenv)->GetLongArrayElements(jenv, val.l, NULL);
517
+ return call_conv(jenv, val, sizeof(jlong), p, la2rv,
518
+ offsetof(struct JNINativeInterface_, ReleaseLongArrayElements));
519
+ }
520
+ static VALUE jshortarray2rv(JNIEnv* jenv, jvalue val)
521
+ {
522
+ jshort* p = (*jenv)->GetShortArrayElements(jenv, val.l, NULL);
523
+ return call_conv(jenv, val, sizeof(jshort), p, sa2rv,
524
+ offsetof(struct JNINativeInterface_, ReleaseShortArrayElements));
525
+ }
526
+ static VALUE jstringarray2rv(JNIEnv* jenv, jvalue val)
527
+ {
528
+ int i;
529
+ jsize len = (*jenv)->GetArrayLength(jenv, val.l);
530
+ VALUE v = rb_ary_new2(len);
531
+ for (i = 0; i < len; i++)
532
+ {
533
+ jobject p = (*jenv)->GetObjectArrayElement(jenv, val.l, i);
534
+ rb_ary_push(v, jstring2val(jenv, (jstring)p));
535
+ }
536
+ (*jenv)->DeleteLocalRef(jenv, val.l);
537
+ return v;
538
+ }
539
+ static VALUE jbooleanarray2rv(JNIEnv* jenv, jvalue val)
540
+ {
541
+ jboolean* p = (*jenv)->GetBooleanArrayElements(jenv, val.l, NULL);
542
+ return call_conv(jenv, val, sizeof(jboolean), p, ba2rv,
543
+ offsetof(struct JNINativeInterface_, ReleaseBooleanArrayElements));
544
+ }
545
+
546
+ /*
547
+ * table that handles java primitive type.
548
+ * index: according to enum PrimitiveType.
549
+ */
550
+ static jprimitive_table jpcvt[] = {
551
+ { "java/lang/Integer", "intValue", "()I", "(I)V", NULL, 0, 0, jint2rv, },
552
+ { "java/lang/Long", "longValue", "()J", "(J)V", NULL, 0, 0, jlong2rv, },
553
+ { "java/lang/Double", "doubleValue", "()D", "(D)V", NULL, 0, 0, jdouble2rv, },
554
+ { "java/lang/Boolean", "booleanValue", "()Z", "(Z)Ljava/lang/Boolean;",
555
+ NULL, 0, 0, jboolean2rv, },
556
+ { "java/lang/Character", "charValue", "()C", NULL, NULL, 0, 0, jchar2rv, },
557
+ { "java/lang/Short", "intValue", "()I", NULL, NULL, 0, 0, jint2rv, },
558
+ { "java/lang/Byte", "intValue", "()I", NULL, NULL, 0, 0, jint2rv, },
559
+ { "java/lang/Float", "doubleValue", "()D", NULL, NULL, 0, 0, jdouble2rv, },
560
+ };
561
+
562
+ /*
563
+ * o will be released in this function.
564
+ */
565
+ static VALUE jv2rv_withprim(JNIEnv* jenv, jobject o)
566
+ {
567
+ jvalue jv;
568
+ int i;
569
+ jclass klass;
570
+ jv.j = 0;
571
+ if (!o)
572
+ rb_raise(rb_eRuntimeError, "Object is NULL");
573
+ klass = (*jenv)->GetObjectClass(jenv, o);
574
+ for (i = PRM_INT; i < PRM_LAST; i++)
575
+ {
576
+ if ((*jenv)->IsSameObject(jenv, jpcvt[i].klass, klass))
577
+ {
578
+ switch (*(jpcvt[i].to_prim_method))
579
+ {
580
+ case 'i':
581
+ jv.i = (*jenv)->CallIntMethod(jenv, o, jpcvt[i].to_prim_id);
582
+ break;
583
+ case 'b':
584
+ jv.z = (*jenv)->CallBooleanMethod(jenv, o, jpcvt[i].to_prim_id);
585
+ break;
586
+ case 'd':
587
+ jv.d = (*jenv)->CallDoubleMethod(jenv, o, jpcvt[i].to_prim_id);
588
+ break;
589
+ case 'c':
590
+ jv.c = (*jenv)->CallCharMethod(jenv, o, jpcvt[i].to_prim_id);
591
+ break;
592
+ case 'l':
593
+ jv.j = (*jenv)->CallLongMethod(jenv, o, jpcvt[i].to_prim_id);
594
+ break;
595
+ default:
596
+ rb_raise(rb_eRuntimeError, "no convertor defined(%d)", i);
597
+ break;
598
+ }
599
+ (*jenv)->DeleteLocalRef(jenv, o);
600
+ return jpcvt[i].func(jenv, jv);
601
+ }
602
+ }
603
+ if ((*jenv)->IsSameObject(jenv, j_string, klass))
604
+ {
605
+ return jstring2val(jenv, o);
606
+ }
607
+ jv.l = o;
608
+ return jv2rv_r(jenv, jv);
609
+ }
610
+
611
+ /*
612
+ * functions convert VALUE to jvalue
613
+ */
614
+ static void rv2jv(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
615
+ {
616
+ jv->l = NULL;
617
+ }
618
+
619
+ static void rv2jbyte(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
620
+ {
621
+ if (!release)
622
+ jv->b = (jbyte)NUM2INT(val);
623
+ }
624
+ static void rv2jchar(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
625
+ {
626
+ if (!release)
627
+ jv->c = (jchar)NUM2INT(val);
628
+ }
629
+ static void rv2jdouble(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
630
+ {
631
+ if (release) return;
632
+ switch (TYPE(val))
633
+ {
634
+ case T_FIXNUM:
635
+ jv->d = NUM2INT(val);
636
+ break;
637
+ case T_FLOAT:
638
+ jv->d = NUM2DBL(val);
639
+ break;
640
+ default:
641
+ rb_raise(rb_eRuntimeError, "can't change to double");
642
+ break;
643
+ }
644
+ }
645
+ static void rv2jfloat(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
646
+ {
647
+ if (release) return;
648
+ switch (TYPE(val))
649
+ {
650
+ case T_FIXNUM:
651
+ jv->f = (float)NUM2INT(val);
652
+ break;
653
+ case T_FLOAT:
654
+ jv->f = (float)NUM2DBL(val);
655
+ break;
656
+ default:
657
+ rb_raise(rb_eRuntimeError, "can't change to float");
658
+ break;
659
+ }
660
+ }
661
+ static void rv2jint(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
662
+ {
663
+ if (!release)
664
+ jv->i = NUM2INT(val);
665
+ }
666
+ static void rv2jlong(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
667
+ {
668
+ if (release) return;
669
+ switch (TYPE(val))
670
+ {
671
+ case T_FIXNUM:
672
+ jv->j = FIX2LONG(val);
673
+ break;
674
+ default:
675
+ #if HAVE_LONG_LONG
676
+ jv->j = NUM2LL(val);
677
+ #else
678
+ rb_raise(rb_eRuntimeError, "can't change to long");
679
+ #endif
680
+ break;
681
+ }
682
+ }
683
+ static void rv2jshort(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
684
+ {
685
+ if (release) return;
686
+ if (TYPE(val) == T_FIXNUM)
687
+ {
688
+ int n = FIX2INT(val);
689
+ if (abs(n) < 0x7fff)
690
+ {
691
+ jv->s = (short)n;
692
+ return;
693
+ }
694
+ }
695
+ rb_raise(rb_eRuntimeError, "can't change to short");
696
+ }
697
+ static void rv2jboolean(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
698
+ {
699
+ if (!release)
700
+ jv->z = (RTEST(val)) ? JNI_TRUE : JNI_FALSE;
701
+ }
702
+ static void rv2jstring(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
703
+ {
704
+ if (!release)
705
+ {
706
+ if (TYPE(val) == T_DATA && IS_RJB_OBJECT(val))
707
+ {
708
+ struct jvi_data* ptr;
709
+ Data_Get_Struct(val, struct jvi_data, ptr);
710
+ if ((*jenv)->IsInstanceOf(jenv, ptr->obj, j_string))
711
+ {
712
+ jv->l = ptr->obj;
713
+ }
714
+ else
715
+ {
716
+ jmethodID tostr;
717
+ jstring js;
718
+ tostr = (*jenv)->GetMethodID(jenv, ptr->klass, "toString", "()Ljava/lang/String;");
719
+ rjb_check_exception(jenv, 0);
720
+ js = (*jenv)->CallObjectMethod(jenv, ptr->obj, tostr);
721
+ rjb_check_exception(jenv, 0);
722
+ jv->l = js;
723
+ }
724
+ }
725
+ else
726
+ {
727
+ if (NIL_P(val))
728
+ {
729
+ jv->l = NULL;
730
+ }
731
+ else
732
+ {
733
+ val = exticonv_local_to_utf8(val);
734
+ jv->l = (*jenv)->NewStringUTF(jenv, StringValuePtr(val));
735
+ }
736
+ }
737
+ }
738
+ else
739
+ {
740
+ if (TYPE(val) == T_DATA)
741
+ {
742
+ if (IS_RJB_OBJECT(val))
743
+ {
744
+ struct jvi_data* ptr;
745
+ Data_Get_Struct(val, struct jvi_data, ptr);
746
+ if ((*jenv)->IsInstanceOf(jenv, ptr->obj, j_string))
747
+ {
748
+ return; /* never delete at this time */
749
+ }
750
+ }
751
+ }
752
+ (*jenv)->DeleteLocalRef(jenv, jv->l);
753
+ }
754
+ }
755
+
756
+ /*
757
+ * psig may be NULL (from proxy/array call)
758
+ */
759
+ static void rv2jobject(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
760
+ {
761
+ if (!release)
762
+ {
763
+ jv->l = NULL;
764
+ if (val == Qtrue || val == Qfalse)
765
+ {
766
+ jv->l = (*jenv)->CallStaticObjectMethod(jenv,
767
+ jpcvt[PRM_BOOLEAN].klass, jpcvt[PRM_BOOLEAN].ctr_id,
768
+ (val == Qtrue) ? JNI_TRUE : JNI_FALSE);
769
+ }
770
+ else if (NIL_P(val))
771
+ {
772
+ /* no-op */
773
+ }
774
+ else if (FIXNUM_P(val))
775
+ {
776
+ jvalue arg;
777
+ int idx = PRM_INT;
778
+ #if HAVE_LONG_LONG
779
+ arg.j = FIX2LONG(val);
780
+ if (arg.j < INT_MIN || arg.j > INT_MAX)
781
+ {
782
+ idx = PRM_LONG;
783
+ }
784
+ #else
785
+ arg.i = FIX2LONG(val);
786
+ #endif
787
+ jv->l = (*jenv)->NewObject(jenv, jpcvt[idx].klass,
788
+ jpcvt[idx].ctr_id, arg);
789
+ }
790
+ else
791
+ {
792
+ jvalue arg;
793
+ switch (TYPE(val))
794
+ {
795
+ case T_DATA:
796
+ if (IS_RJB_OBJECT(val))
797
+ {
798
+ /* TODO: check instanceof (class (in psig) ) */
799
+ struct jvi_data* ptr;
800
+ Data_Get_Struct(val, struct jvi_data, ptr);
801
+ jv->l = ptr->obj;
802
+ }
803
+ else if (rb_obj_class(val) == rjbb)
804
+ {
805
+ struct rj_bridge* ptr;
806
+ Data_Get_Struct(val, struct rj_bridge, ptr);
807
+ jv->l = ptr->proxy;
808
+ }
809
+ else if (CLASS_INHERITED(rjbc, rb_obj_class(val)))
810
+ {
811
+ struct jv_data* ptr;
812
+ Data_Get_Struct(val, struct jv_data, ptr);
813
+ jv->l = ptr->idata.obj;
814
+ }
815
+ break;
816
+ case T_STRING:
817
+ rv2jstring(jenv, val, jv, NULL, 0);
818
+ break;
819
+ case T_FLOAT:
820
+ arg.d = NUM2DBL(val);
821
+ jv->l = (*jenv)->NewObject(jenv, jpcvt[PRM_DOUBLE].klass,
822
+ jpcvt[PRM_DOUBLE].ctr_id, arg.d);
823
+ break;
824
+ case T_ARRAY:
825
+ jv->l = r2objarray(jenv, val, "Ljava/lang/Object;");
826
+ break;
827
+ #if HAVE_LONG_LONG
828
+ case T_BIGNUM:
829
+ arg.j = rb_big2ll(val);
830
+ jv->l = (*jenv)->NewObject(jenv, jpcvt[PRM_LONG].klass,
831
+ jpcvt[PRM_LONG].ctr_id, arg);
832
+ break;
833
+ #endif
834
+ default:
835
+ rb_raise(rb_eRuntimeError, "can't convert to java type");
836
+ break;
837
+ }
838
+ }
839
+ }
840
+ else
841
+ {
842
+ switch (TYPE(val))
843
+ {
844
+ case T_STRING:
845
+ case T_FLOAT:
846
+ case T_ARRAY:
847
+ case T_BIGNUM:
848
+ if (jv->l) (*jenv)->DeleteLocalRef(jenv, jv->l);
849
+ break;
850
+ }
851
+ }
852
+ }
853
+
854
+ static void check_fixnumarray(VALUE v)
855
+ {
856
+ int i;
857
+ int len = RARRAY_LEN(v);
858
+ VALUE* p = RARRAY_PTR(v);
859
+ /* check all fixnum (overflow is permit) */
860
+ for (i = 0; i < len; i++)
861
+ {
862
+ if (!FIXNUM_P(*p++))
863
+ {
864
+ rb_raise(rb_eRuntimeError, "array element must be a fixnum");
865
+ }
866
+ }
867
+ }
868
+
869
+ static jarray r2barray(JNIEnv* jenv, VALUE v, const char* cls)
870
+ {
871
+ jarray ary = NULL;
872
+ if (TYPE(v) == T_STRING)
873
+ {
874
+ ary = (*jenv)->NewByteArray(jenv, RSTRING_LEN(v));
875
+ (*jenv)->SetByteArrayRegion(jenv, ary, 0, RSTRING_LEN(v),
876
+ (const jbyte*)RSTRING_PTR(v));
877
+ }
878
+ else if (TYPE(v) == T_ARRAY)
879
+ {
880
+ int i;
881
+ jbyte* pb;
882
+ check_fixnumarray(v);
883
+ ary = (*jenv)->NewByteArray(jenv, RARRAY_LEN(v));
884
+ pb = (*jenv)->GetByteArrayElements(jenv, ary, NULL);
885
+ for (i = 0; i < RARRAY_LEN(v); i++)
886
+ {
887
+ *(pb + i) = (jbyte)FIX2ULONG(RARRAY_PTR(v)[i]);
888
+ }
889
+ (*jenv)->ReleaseByteArrayElements(jenv, ary, pb, 0);
890
+ }
891
+ if (!ary)
892
+ {
893
+ rb_raise(rb_eRuntimeError, "can't coerce to byte array");
894
+ }
895
+ return ary;
896
+ }
897
+
898
+ static jarray r2carray(JNIEnv* jenv, VALUE v, const char* cls)
899
+ {
900
+ jarray ary = NULL;
901
+ if (TYPE(v) == T_ARRAY)
902
+ {
903
+ int i;
904
+ jchar* pb;
905
+ check_fixnumarray(v);
906
+ ary = (*jenv)->NewCharArray(jenv, RARRAY_LEN(v));
907
+ pb = (*jenv)->GetCharArrayElements(jenv, ary, NULL);
908
+ for (i = 0; i < RARRAY_LEN(v); i++)
909
+ {
910
+ *(pb + i) = (jchar)FIX2ULONG(RARRAY_PTR(v)[i]);
911
+ }
912
+ (*jenv)->ReleaseCharArrayElements(jenv, ary, pb, 0);
913
+ return ary;
914
+ }
915
+ rb_raise(rb_eRuntimeError, "can't coerce to char array");
916
+ }
917
+
918
+ static jarray r2darray(JNIEnv* jenv, VALUE v, const char* cls)
919
+ {
920
+ jarray ary = NULL;
921
+ if (TYPE(v) == T_ARRAY)
922
+ {
923
+ int i;
924
+ jdouble* pb;
925
+ ary = (*jenv)->NewDoubleArray(jenv, RARRAY_LEN(v));
926
+ pb = (*jenv)->GetDoubleArrayElements(jenv, ary, NULL);
927
+ for (i = 0; i < RARRAY_LEN(v); i++)
928
+ {
929
+ *(pb + i) = (jdouble)rb_num2dbl(RARRAY_PTR(v)[i]);
930
+ }
931
+ (*jenv)->ReleaseDoubleArrayElements(jenv, ary, pb, 0);
932
+ return ary;
933
+ }
934
+ rb_raise(rb_eRuntimeError, "can't coerce to double array");
935
+ }
936
+
937
+ static jarray r2farray(JNIEnv* jenv, VALUE v, const char* cls)
938
+ {
939
+ jarray ary = NULL;
940
+ if (TYPE(v) == T_ARRAY)
941
+ {
942
+ int i;
943
+ jfloat* pb;
944
+ ary = (*jenv)->NewFloatArray(jenv, RARRAY_LEN(v));
945
+ pb = (*jenv)->GetFloatArrayElements(jenv, ary, NULL);
946
+ for (i = 0; i < RARRAY_LEN(v); i++)
947
+ {
948
+ *(pb + i) = (jfloat)rb_num2dbl(RARRAY_PTR(v)[i]);
949
+ }
950
+ (*jenv)->ReleaseFloatArrayElements(jenv, ary, pb, 0);
951
+ return ary;
952
+ }
953
+ rb_raise(rb_eRuntimeError, "can't coerce to float array");
954
+ }
955
+
956
+ static jarray r2iarray(JNIEnv* jenv, VALUE v, const char* cls)
957
+ {
958
+ jarray ary = NULL;
959
+ if (TYPE(v) == T_ARRAY)
960
+ {
961
+ int i;
962
+ jint* pb;
963
+ check_fixnumarray(v);
964
+ ary = (*jenv)->NewIntArray(jenv, RARRAY_LEN(v));
965
+ pb = (*jenv)->GetIntArrayElements(jenv, ary, NULL);
966
+ for (i = 0; i < RARRAY_LEN(v); i++)
967
+ {
968
+ *(pb + i) = (jint)FIX2LONG(RARRAY_PTR(v)[i]);
969
+ }
970
+ (*jenv)->ReleaseIntArrayElements(jenv, ary, pb, 0);
971
+ return ary;
972
+ }
973
+ rb_raise(rb_eRuntimeError, "can't coerce to int array");
974
+ }
975
+
976
+ static jarray r2larray(JNIEnv* jenv, VALUE v, const char* cls)
977
+ {
978
+ jarray ary = NULL;
979
+ if (TYPE(v) == T_ARRAY)
980
+ {
981
+ int i;
982
+ jlong* pb;
983
+ ary = (*jenv)->NewLongArray(jenv, RARRAY_LEN(v));
984
+ pb = (*jenv)->GetLongArrayElements(jenv, ary, NULL);
985
+ for (i = 0; i < RARRAY_LEN(v); i++)
986
+ {
987
+ #if HAVE_LONG_LONG
988
+ *(pb + i) = (jlong)rb_num2ll(RARRAY_PTR(v)[i]);
989
+ #else
990
+ *(pb + i) = (jlong)FIX2LONG(RARRAY_PTR(v)[i]);
991
+ #endif
992
+ }
993
+ (*jenv)->ReleaseLongArrayElements(jenv, ary, pb, 0);
994
+ return ary;
995
+ }
996
+ rb_raise(rb_eRuntimeError, "can't coerce to long array");
997
+ }
998
+
999
+ static jarray r2sarray(JNIEnv* jenv, VALUE v, const char* cls)
1000
+ {
1001
+ jarray ary = NULL;
1002
+ if (TYPE(v) == T_ARRAY)
1003
+ {
1004
+ int i;
1005
+ jshort* pb;
1006
+ check_fixnumarray(v);
1007
+ ary = (*jenv)->NewShortArray(jenv, RARRAY_LEN(v));
1008
+ pb = (*jenv)->GetShortArrayElements(jenv, ary, NULL);
1009
+ for (i = 0; i < RARRAY_LEN(v); i++)
1010
+ {
1011
+ *(pb + i) = (jshort)FIX2LONG(RARRAY_PTR(v)[i]);
1012
+ }
1013
+ (*jenv)->ReleaseShortArrayElements(jenv, ary, pb, 0);
1014
+ return ary;
1015
+ }
1016
+ rb_raise(rb_eRuntimeError, "can't coerce to short array");
1017
+ }
1018
+
1019
+ static jarray r2boolarray(JNIEnv* jenv, VALUE v, const char* cls)
1020
+ {
1021
+ jarray ary = NULL;
1022
+ if (TYPE(v) == T_ARRAY)
1023
+ {
1024
+ int i;
1025
+ jboolean* pb;
1026
+ ary = (*jenv)->NewBooleanArray(jenv, RARRAY_LEN(v));
1027
+ pb = (*jenv)->GetBooleanArrayElements(jenv, ary, NULL);
1028
+ for (i = 0; i < RARRAY_LEN(v); i++)
1029
+ {
1030
+ *(pb + i)
1031
+ = (!RTEST(RARRAY_PTR(v)[i]))
1032
+ ? JNI_FALSE : JNI_TRUE;
1033
+ }
1034
+ (*jenv)->ReleaseBooleanArrayElements(jenv, ary, pb, 0);
1035
+ return ary;
1036
+ }
1037
+ rb_raise(rb_eRuntimeError, "can't coerce to boolean array");
1038
+ }
1039
+
1040
+ static jarray r2voidarray(JNIEnv* jenv, VALUE v, const char* cls)
1041
+ {
1042
+ rb_raise(rb_eRuntimeError, "void never arrayed");
1043
+ }
1044
+
1045
+ static jarray r2objarray(JNIEnv* jenv, VALUE v, const char* cls)
1046
+ {
1047
+ jarray ary = NULL;
1048
+ if (TYPE(v) == T_ARRAY)
1049
+ {
1050
+ int i;
1051
+ ary = (*jenv)->NewObjectArray(jenv, RARRAY_LEN(v), j_object, NULL);
1052
+ rjb_check_exception(jenv, 0);
1053
+ for (i = 0; i < RARRAY_LEN(v); i++)
1054
+ {
1055
+ jvalue jv;
1056
+ rv2jobject(jenv, RARRAY_PTR(v)[i], &jv, NULL, 0);
1057
+ (*jenv)->SetObjectArrayElement(jenv, ary, i, jv.l);
1058
+ }
1059
+ return ary;
1060
+ }
1061
+ rb_raise(rb_eRuntimeError, "can't coerce to object array");
1062
+ }
1063
+
1064
+ /*
1065
+ * Type convertion tables
1066
+ */
1067
+ static const jconv_table jcvt[] = {
1068
+ { "byte", "B", rv2jbyte, jbyte2rv,
1069
+ jbytearray2rv, r2barray,
1070
+ offsetof(struct JNINativeInterface_, CallByteMethodA),
1071
+ offsetof(struct JNINativeInterface_, CallStaticByteMethodA), },
1072
+ { "char", "C", rv2jchar, jchar2rv,
1073
+ jchararray2rv, r2carray,
1074
+ offsetof(struct JNINativeInterface_, CallCharMethodA),
1075
+ offsetof(struct JNINativeInterface_, CallStaticCharMethodA), },
1076
+ { "double", "D", rv2jdouble, jdouble2rv,
1077
+ jdoublearray2rv, r2darray,
1078
+ offsetof(struct JNINativeInterface_, CallDoubleMethodA),
1079
+ offsetof(struct JNINativeInterface_, CallStaticDoubleMethodA), },
1080
+ { "float", "F", rv2jfloat, jfloat2rv,
1081
+ jfloatarray2rv, r2farray,
1082
+ offsetof(struct JNINativeInterface_, CallFloatMethodA),
1083
+ offsetof(struct JNINativeInterface_, CallStaticFloatMethodA), },
1084
+ { "int", "I", rv2jint, jint2rv,
1085
+ jintarray2rv, r2iarray,
1086
+ offsetof(struct JNINativeInterface_, CallIntMethodA),
1087
+ offsetof(struct JNINativeInterface_, CallStaticIntMethodA), },
1088
+ { "long", "J", rv2jlong, jlong2rv,
1089
+ jlongarray2rv, r2larray,
1090
+ offsetof(struct JNINativeInterface_, CallLongMethodA),
1091
+ offsetof(struct JNINativeInterface_, CallStaticLongMethodA), },
1092
+ { "short", "S", rv2jshort, jshort2rv,
1093
+ jshortarray2rv, r2sarray,
1094
+ offsetof(struct JNINativeInterface_, CallShortMethodA),
1095
+ offsetof(struct JNINativeInterface_, CallStaticShortMethodA), },
1096
+ { "boolean", "Z", rv2jboolean, jboolean2rv,
1097
+ jbooleanarray2rv, r2boolarray,
1098
+ offsetof(struct JNINativeInterface_, CallBooleanMethodA),
1099
+ offsetof(struct JNINativeInterface_, CallStaticBooleanMethodA), },
1100
+ { "void", "V", rv2jv, jvoid2rv,
1101
+ NULL, r2voidarray,
1102
+ offsetof(struct JNINativeInterface_, CallVoidMethodA),
1103
+ offsetof(struct JNINativeInterface_, CallStaticVoidMethodA), },
1104
+ { "java.lang.String", "Ljava.lang.String;", rv2jstring, jstring2rv,
1105
+ jstringarray2rv, r2objarray,
1106
+ offsetof(struct JNINativeInterface_, CallObjectMethodA),
1107
+ offsetof(struct JNINativeInterface_, CallStaticObjectMethodA), },
1108
+ };
1109
+
1110
+ static void rv2jarray(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
1111
+ {
1112
+ if (*psig != '[')
1113
+ {
1114
+ rb_raise(rb_eRuntimeError, "argument signature not array");
1115
+ }
1116
+ if (release)
1117
+ {
1118
+ (*jenv)->DeleteLocalRef(jenv, jv->l);
1119
+ }
1120
+ else
1121
+ {
1122
+ int i;
1123
+ jarray ja = NULL;
1124
+ if (NIL_P(val))
1125
+ {
1126
+ /* no-op, null for an array */
1127
+ }
1128
+ else if (*(psig + 1) == '[')
1129
+ {
1130
+ if (TYPE(val) != T_ARRAY) {
1131
+ rb_raise(rb_eRuntimeError, "array's rank unmatch");
1132
+ }
1133
+ ja = (*jenv)->NewObjectArray(jenv, RARRAY_LEN(val), j_object, NULL);
1134
+ rjb_check_exception(jenv, 0);
1135
+ for (i = 0; i < RARRAY_LEN(val); i++)
1136
+ {
1137
+ jvalue jv;
1138
+ rv2jarray(jenv, RARRAY_PTR(val)[i], &jv, psig + 1, 0);
1139
+ (*jenv)->SetObjectArrayElement(jenv, ja, i, jv.l);
1140
+ }
1141
+ }
1142
+ else
1143
+ {
1144
+ R2JARRAY r2a = r2objarray;
1145
+ for (i = 0; i < COUNTOF(jcvt); i++)
1146
+ {
1147
+ if (*(psig + 1) == jcvt[i].jntype[0])
1148
+ {
1149
+ r2a = jcvt[i].r2ja;
1150
+ break;
1151
+ }
1152
+ }
1153
+ ja = r2a(jenv, val, psig + 1);
1154
+ }
1155
+ jv->l = ja;
1156
+ }
1157
+ }
1158
+
1159
+ /*
1160
+ */
1161
+ static R2J get_r2j(JNIEnv* jenv, jobject o, int* siglen, char* sigp)
1162
+ {
1163
+ int len, i;
1164
+ const char* cname;
1165
+ R2J result = NULL;
1166
+ jstring nm = (*jenv)->CallObjectMethod(jenv, o, rjb_class_getName);
1167
+ rjb_check_exception(jenv, 0);
1168
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1169
+ if (*cname == '[')
1170
+ {
1171
+ if (siglen)
1172
+ {
1173
+ len = strlen(cname);
1174
+ *siglen += len;
1175
+ strcpy(sigp, cname);
1176
+ }
1177
+ result = rv2jarray;
1178
+ }
1179
+ else
1180
+ {
1181
+ for (i = 0; i < COUNTOF(jcvt); i++)
1182
+ {
1183
+ if (!strcmp(cname, jcvt[i].jtype))
1184
+ {
1185
+ if (siglen)
1186
+ {
1187
+ *siglen += strlen(jcvt[i].jntype);
1188
+ strcpy(sigp, jcvt[i].jntype);
1189
+ }
1190
+ result = jcvt[i].r2j;
1191
+ break;
1192
+ }
1193
+ }
1194
+ if (!result)
1195
+ {
1196
+ if (siglen)
1197
+ {
1198
+ *siglen += sprintf(sigp, "L%s;", cname);
1199
+ }
1200
+ result = rv2jobject;
1201
+ }
1202
+ }
1203
+ rjb_release_string(jenv, nm, cname);
1204
+ return result;
1205
+ }
1206
+
1207
+ static J2R get_arrayconv(const char* cname, char* pdepth)
1208
+ {
1209
+ int i;
1210
+ int start;
1211
+ for (start = 1; *(cname + start) == '['; start++);
1212
+ *pdepth = (char)start;
1213
+ for (i = 0; i < COUNTOF(jcvt); i++)
1214
+ {
1215
+ if (*(cname + start) == jcvt[i].jntype[0])
1216
+ {
1217
+ if (jcvt[i].jntype[0] == 'L'
1218
+ && strncmp(cname + start, jcvt[i].jntype, strlen(jcvt[i].jntype)))
1219
+ {
1220
+ break;
1221
+ }
1222
+ return jcvt[i].ja2r;
1223
+ }
1224
+ }
1225
+ return &jarray2rv;
1226
+ }
1227
+
1228
+ static J2R get_j2r(JNIEnv* jenv, jobject cls, char* psig, char* pdepth, char* ppsig, off_t* piv, int static_method)
1229
+ {
1230
+ int i;
1231
+ J2R result = NULL;
1232
+ const char* cname;
1233
+ const char* jname = NULL;
1234
+ jstring nm = (*jenv)->CallObjectMethod(jenv, cls, rjb_class_getName);
1235
+ rjb_check_exception(jenv, 0);
1236
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1237
+
1238
+ if (*cname == '[')
1239
+ {
1240
+ result = get_arrayconv(cname, pdepth);
1241
+ jname = cname;
1242
+ }
1243
+ else
1244
+ {
1245
+ for (i = 0; i < COUNTOF(jcvt); i++)
1246
+ {
1247
+ if (!strcmp(cname, jcvt[i].jtype))
1248
+ {
1249
+ result = jcvt[i].j2r;
1250
+ *piv = (static_method) ? jcvt[i].jscall : jcvt[i].jcall;
1251
+ if (jcvt[i].jntype[0] != 'L')
1252
+ {
1253
+ *psig = jcvt[i].jntype[0];
1254
+ }
1255
+ jname = jcvt[i].jntype;
1256
+ break;
1257
+ }
1258
+ }
1259
+ }
1260
+ if (ppsig)
1261
+ {
1262
+ if (!jname)
1263
+ {
1264
+ sprintf(ppsig, "L%s;", cname);
1265
+ }
1266
+ else
1267
+ {
1268
+ strcpy(ppsig, jname);
1269
+ }
1270
+ java2jniname(ppsig);
1271
+ }
1272
+ rjb_release_string(jenv, nm, cname);
1273
+ return result;
1274
+ }
1275
+
1276
+ static void setup_j2r(JNIEnv* jenv, jobject cls, struct cls_method* pm, int static_method)
1277
+ {
1278
+ off_t iv = 0;
1279
+ J2R result = get_j2r(jenv, cls, &pm->basic.result_signature, &pm->basic.result_arraydepth, NULL, &iv, static_method);
1280
+ pm->result_convert = (result) ? result : jv2rv;
1281
+ if (iv)
1282
+ {
1283
+ pm->method = iv;
1284
+ }
1285
+ else
1286
+ {
1287
+ pm->method = (static_method)
1288
+ ? offsetof(struct JNINativeInterface_, CallStaticObjectMethodA)
1289
+ : offsetof(struct JNINativeInterface_, CallObjectMethodA);
1290
+ }
1291
+ }
1292
+
1293
+ static void fill_convert(JNIEnv* jenv, struct cls_constructor* cls, jobjectArray tp, int count)
1294
+ {
1295
+ int i, siglen;
1296
+ R2J* tbl = ALLOC_N(R2J, count);
1297
+ char** sig = (char**)ALLOCA_N(char*, count);
1298
+ char siga[256];
1299
+ cls->arg_convert = tbl;
1300
+ memset(tbl, 0, sizeof(R2J) * count);
1301
+ siglen = 0;
1302
+ for (i = 0; i < count; i++)
1303
+ {
1304
+ jobject o = (*jenv)->GetObjectArrayElement(jenv, tp, i);
1305
+ *(tbl + i) = get_r2j(jenv, o, &siglen, siga);
1306
+ *(sig + i) = ALLOCA_N(char, strlen(siga) + 1);
1307
+ strcpy(*(sig + i), siga);
1308
+ }
1309
+ cls->method_signature = ALLOC_N(char, siglen + 1);
1310
+ *(cls->method_signature) = 0;
1311
+ for (i = 0; i < count; i++)
1312
+ {
1313
+ strcat(cls->method_signature, *(sig + i));
1314
+ }
1315
+ }
1316
+
1317
+ /*
1318
+ * create method info structure
1319
+ * m = instance of Method class
1320
+ * c = instance of the class
1321
+ */
1322
+ static void setup_methodbase(JNIEnv* jenv, struct cls_constructor* pm,
1323
+ jobjectArray parama, jsize pcount)
1324
+ {
1325
+ pm->arg_count = pcount;
1326
+ pm->method_signature = NULL;
1327
+ pm->result_signature = 'O';
1328
+ pm->result_arraydepth = 0;
1329
+ pm->arg_convert = NULL;
1330
+ if (pcount)
1331
+ {
1332
+ fill_convert(jenv, pm, parama, pcount);
1333
+ }
1334
+ }
1335
+
1336
+ static void register_methodinfo(struct cls_method* newpm, st_table* tbl)
1337
+ {
1338
+ struct cls_method* pm;
1339
+
1340
+ if (st_lookup(tbl, newpm->name, (st_data_t*)&pm))
1341
+ {
1342
+ newpm->next = pm->next;
1343
+ pm->next = newpm;
1344
+ }
1345
+ else
1346
+ {
1347
+ newpm->next = NULL;
1348
+ st_insert(tbl, newpm->name, (VALUE)newpm);
1349
+ }
1350
+ }
1351
+
1352
+ static struct cls_method* clone_methodinfo(struct cls_method* pm)
1353
+ {
1354
+ struct cls_method* result = ALLOC(struct cls_method);
1355
+ memcpy(result, pm, sizeof(struct cls_method));
1356
+ return result;
1357
+ }
1358
+
1359
+ static int make_alias(const char* jname, char* rname)
1360
+ {
1361
+ int ret = 0;
1362
+ while (*jname)
1363
+ {
1364
+ if (isupper(*jname))
1365
+ {
1366
+ *rname++ = '_';
1367
+ *rname++ = tolower(*jname++);
1368
+ ret = 1;
1369
+ }
1370
+ else
1371
+ {
1372
+ *rname++ = *jname++;
1373
+ }
1374
+ }
1375
+ *rname = '\0';
1376
+ return ret;
1377
+ }
1378
+
1379
+ static void create_methodinfo(JNIEnv* jenv, st_table* tbl, jobject m, int static_method)
1380
+ {
1381
+ struct cls_method* result;
1382
+ struct cls_method* pm;
1383
+ const char* jname;
1384
+ int alias;
1385
+ jstring nm;
1386
+ jobjectArray parama;
1387
+ jobject cls;
1388
+ jsize param_count;
1389
+ char* rname;
1390
+
1391
+ result = ALLOC(struct cls_method);
1392
+ parama = (*jenv)->CallObjectMethod(jenv, m, getParameterTypes);
1393
+ rjb_check_exception(jenv, 0);
1394
+ param_count = (*jenv)->GetArrayLength(jenv, parama);
1395
+ rjb_check_exception(jenv, 0);
1396
+ setup_methodbase(jenv, &result->basic, parama, param_count);
1397
+ nm = (*jenv)->CallObjectMethod(jenv, m, method_getName);
1398
+ rjb_check_exception(jenv, 0);
1399
+ jname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1400
+ rname = ALLOCA_N(char, strlen(jname) * 2 + 8);
1401
+ alias = make_alias(jname, rname);
1402
+ result->name = rb_intern(jname);
1403
+ rjb_release_string(jenv, nm, jname);
1404
+ result->basic.id = (*jenv)->FromReflectedMethod(jenv, m);
1405
+ rjb_check_exception(jenv, 0);
1406
+ cls = (*jenv)->CallObjectMethod(jenv, m, getReturnType);
1407
+ rjb_check_exception(jenv, 0);
1408
+ setup_j2r(jenv, cls, result, static_method);
1409
+ (*jenv)->DeleteLocalRef(jenv, cls);
1410
+ result->static_method = static_method;
1411
+ register_methodinfo(result, tbl);
1412
+ /* create method alias */
1413
+ pm = NULL;
1414
+ if (strlen(rname) > 3
1415
+ && (*rname == 'g' || *rname == 's') && *(rname + 1) == 'e' && *(rname + 2) == 't')
1416
+ {
1417
+ pm = clone_methodinfo(result);
1418
+ if (*rname == 's')
1419
+ {
1420
+ if (result->basic.arg_count == 1)
1421
+ {
1422
+ rname += 3;
1423
+ strcat(rname, "=");
1424
+ }
1425
+ }
1426
+ else
1427
+ {
1428
+ rname += 3;
1429
+ }
1430
+ if (*rname == '_') rname++;
1431
+ }
1432
+ else if (strlen(rname) > 2 && result->basic.result_signature == 'Z'
1433
+ && *rname == 'i' && *(rname + 1) == 's')
1434
+ {
1435
+ pm = clone_methodinfo(result);
1436
+ rname += 2;
1437
+ if (*rname == '_') rname++;
1438
+ strcat(rname, "?");
1439
+ }
1440
+ else if (alias)
1441
+ {
1442
+ pm = clone_methodinfo(result);
1443
+ }
1444
+ if (pm)
1445
+ {
1446
+ pm->name = rb_intern(rname);
1447
+ register_methodinfo(pm, tbl);
1448
+ }
1449
+ }
1450
+
1451
+ static void create_fieldinfo(JNIEnv* jenv, st_table* tbl, jobject f, int readonly, int static_field)
1452
+ {
1453
+ struct cls_field* result;
1454
+ const char* jname;
1455
+ jstring nm;
1456
+ jobject cls;
1457
+ char sigs[256];
1458
+ off_t iv = 0;
1459
+
1460
+ result = ALLOC(struct cls_field);
1461
+ memset(result, 0, sizeof(struct cls_field));
1462
+ nm = (*jenv)->CallObjectMethod(jenv, f, field_getName);
1463
+ rjb_check_exception(jenv, 0);
1464
+ jname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1465
+ result->name = rb_intern(jname);
1466
+ rjb_release_string(jenv, nm, jname);
1467
+ result->id = (*jenv)->FromReflectedField(jenv, f);
1468
+ rjb_check_exception(jenv, 0);
1469
+ cls = (*jenv)->CallObjectMethod(jenv, f, field_getType);
1470
+ rjb_check_exception(jenv, 0);
1471
+ result->value_convert = get_j2r(jenv, cls, &result->result_signature, &result->result_arraydepth, sigs, &iv, 0);
1472
+ result->arg_convert = get_r2j(jenv, cls, NULL, NULL);
1473
+ (*jenv)->DeleteLocalRef(jenv, cls);
1474
+ result->field_signature = ALLOC_N(char, strlen(sigs) + 1);
1475
+ strcpy(result->field_signature, sigs);
1476
+ if (!result->value_convert) result->value_convert = jv2rv;
1477
+ result->readonly = readonly;
1478
+ result->static_field = static_field;
1479
+ st_insert(tbl, result->name, (VALUE)result);
1480
+ }
1481
+
1482
+ static void setup_constructors(JNIEnv* jenv, struct cls_constructor*** pptr, jobjectArray methods)
1483
+ {
1484
+ int i;
1485
+ struct cls_constructor* pc;
1486
+ jsize mcount = (*jenv)->GetArrayLength(jenv, methods);
1487
+ struct cls_constructor** tbl = ALLOC_N(struct cls_constructor*, mcount + 1);
1488
+ *pptr = tbl;
1489
+ for (i = 0; i < mcount; i++)
1490
+ {
1491
+ jobjectArray parama;
1492
+ jsize pcount;
1493
+ jobject c = (*jenv)->GetObjectArrayElement(jenv, methods, i);
1494
+ rjb_check_exception(jenv, 0);
1495
+ pc = ALLOC(struct cls_constructor);
1496
+ tbl[i] = pc;
1497
+ parama = (*jenv)->CallObjectMethod(jenv, c, ctrGetParameterTypes);
1498
+ rjb_check_exception(jenv, 0);
1499
+ pcount = (*jenv)->GetArrayLength(jenv, parama);
1500
+ rjb_check_exception(jenv, 0);
1501
+ setup_methodbase(jenv, pc, parama, pcount);
1502
+ pc->id = (*jenv)->FromReflectedMethod(jenv, c);
1503
+ (*jenv)->DeleteLocalRef(jenv, c);
1504
+ }
1505
+ tbl[mcount] = NULL;
1506
+ }
1507
+
1508
+ static void setup_methods(JNIEnv* jenv, st_table** tbl, st_table** static_tbl,
1509
+ jobjectArray methods)
1510
+ {
1511
+ int i;
1512
+ jint modifier;
1513
+ jsize mcount = (*jenv)->GetArrayLength(jenv, methods);
1514
+ *tbl = st_init_numtable_with_size(mcount);
1515
+ *static_tbl = st_init_numtable();
1516
+ for (i = 0; i < mcount; i++)
1517
+ {
1518
+ jobject m = (*jenv)->GetObjectArrayElement(jenv, methods, i);
1519
+ rjb_check_exception(jenv, 0);
1520
+ modifier = (*jenv)->CallIntMethod(jenv, m, method_getModifiers);
1521
+ if (!(modifier & ACC_STATIC))
1522
+ {
1523
+ create_methodinfo(jenv, *tbl, m, 0);
1524
+ }
1525
+ else
1526
+ {
1527
+ create_methodinfo(jenv, *static_tbl, m, 1);
1528
+ }
1529
+ (*jenv)->DeleteLocalRef(jenv, m);
1530
+ }
1531
+ }
1532
+
1533
+ static void setup_fields(JNIEnv* jenv, st_table** tbl, jobjectArray flds)
1534
+ {
1535
+ int i;
1536
+ jint modifier;
1537
+ jsize fcount = (*jenv)->GetArrayLength(jenv, flds);
1538
+ *tbl = st_init_numtable_with_size(fcount);
1539
+ for (i = 0; i < fcount; i++)
1540
+ {
1541
+ jobject f = (*jenv)->GetObjectArrayElement(jenv, flds, i);
1542
+ rjb_check_exception(jenv, 0);
1543
+ modifier = (*jenv)->CallIntMethod(jenv, f, field_getModifiers);
1544
+ create_fieldinfo(jenv, *tbl, f, modifier & ACC_FINAL, modifier & ACC_STATIC);
1545
+ (*jenv)->DeleteLocalRef(jenv, f);
1546
+ }
1547
+ }
1548
+
1549
+ static void load_constants(JNIEnv* jenv, jclass klass, VALUE self, jobjectArray flds)
1550
+ {
1551
+ int i;
1552
+ jint modifier;
1553
+ jsize fcount = (*jenv)->GetArrayLength(jenv, flds);
1554
+ for (i = 0; i < fcount; i++)
1555
+ {
1556
+ jobject f = (*jenv)->GetObjectArrayElement(jenv, flds, i);
1557
+ rjb_check_exception(jenv, 0);
1558
+ modifier = (*jenv)->CallIntMethod(jenv, f, field_getModifiers);
1559
+ rjb_check_exception(jenv, 0);
1560
+ if ((modifier & (ACC_PUBLIC | ACC_STATIC | ACC_FINAL)) == (ACC_PUBLIC | ACC_STATIC | ACC_FINAL))
1561
+ {
1562
+ jstring nm;
1563
+ const char* cname;
1564
+ jobject cls;
1565
+ char sig;
1566
+ char depth;
1567
+ off_t iv;
1568
+ J2R j2r;
1569
+ jvalue jv;
1570
+ jfieldID jfid;
1571
+ char sigs[256];
1572
+ char* pname;
1573
+
1574
+ /* constants make define directly in the ruby object */
1575
+ cls = (*jenv)->CallObjectMethod(jenv, f, field_getType);
1576
+ rjb_check_exception(jenv, 0);
1577
+ iv = 0;
1578
+ sig = depth = 0;
1579
+ j2r = get_j2r(jenv, cls, &sig, &depth, sigs, &iv, 1);
1580
+ if (!j2r) j2r = jv2rv;
1581
+ (*jenv)->DeleteLocalRef(jenv, cls);
1582
+ nm = (*jenv)->CallObjectMethod(jenv, f, field_getName);
1583
+ rjb_check_exception(jenv, 0);
1584
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1585
+ rjb_check_exception(jenv, 0);
1586
+ jfid = (*jenv)->GetStaticFieldID(jenv, klass, cname, sigs);
1587
+ rjb_check_exception(jenv, 0);
1588
+ switch (sig)
1589
+ {
1590
+ case 'D':
1591
+ jv.d = (*jenv)->GetStaticDoubleField(jenv, klass, jfid);
1592
+ break;
1593
+ case 'Z':
1594
+ jv.z = (*jenv)->GetStaticBooleanField(jenv, klass, jfid);
1595
+ break;
1596
+ case 'B':
1597
+ jv.b = (*jenv)->GetStaticByteField(jenv, klass, jfid);
1598
+ break;
1599
+ case 'F':
1600
+ jv.f = (*jenv)->GetStaticFloatField(jenv, klass, jfid);
1601
+ break;
1602
+ case 'C':
1603
+ jv.c = (*jenv)->GetStaticCharField(jenv, klass, jfid);
1604
+ break;
1605
+ case 'S':
1606
+ jv.s = (*jenv)->GetStaticShortField(jenv, klass, jfid);
1607
+ break;
1608
+ case 'J':
1609
+ jv.j = (*jenv)->GetStaticLongField(jenv, klass, jfid);
1610
+ break;
1611
+ case 'I':
1612
+ jv.i = (*jenv)->GetStaticIntField(jenv, klass, jfid);
1613
+ break;
1614
+ default:
1615
+ jv.l = (*jenv)->GetStaticObjectField(jenv, klass, jfid);
1616
+ break;
1617
+ }
1618
+ pname = (char*)cname;
1619
+ if (!isupper(*cname))
1620
+ {
1621
+ pname = ALLOCA_N(char, strlen(cname) + 1);
1622
+ strcpy(pname, cname);
1623
+ *pname = toupper(*pname);
1624
+ if (!isupper(*pname)
1625
+ || rb_const_defined(rb_obj_class(self), rb_intern(pname)))
1626
+ {
1627
+ pname = NULL;
1628
+ }
1629
+ }
1630
+ if (pname)
1631
+ {
1632
+ rb_define_const(rb_obj_class(self), pname, j2r(jenv, jv));
1633
+ }
1634
+ rjb_release_string(jenv, nm, cname);
1635
+ }
1636
+ (*jenv)->DeleteLocalRef(jenv, f);
1637
+ }
1638
+ }
1639
+
1640
+ static void setup_metadata(JNIEnv* jenv, VALUE self, struct jv_data* ptr, VALUE classname)
1641
+ {
1642
+ jmethodID mid;
1643
+ jobjectArray methods;
1644
+ jobjectArray flds;
1645
+
1646
+ jclass klass = (*jenv)->GetObjectClass(jenv, ptr->idata.obj);
1647
+ ptr->idata.klass = (*jenv)->NewGlobalRef(jenv, klass);
1648
+ rjb_check_exception(jenv, 0);
1649
+ mid = (*jenv)->GetMethodID(jenv, klass, "getMethods", "()[Ljava/lang/reflect/Method;");
1650
+ rjb_check_exception(jenv, 0);
1651
+ methods = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid);
1652
+ rjb_check_exception(jenv, 0);
1653
+ setup_methods(jenv, &ptr->idata.methods, &ptr->static_methods, methods);
1654
+ mid = (*jenv)->GetMethodID(jenv, klass, "getConstructors", "()[Ljava/lang/reflect/Constructor;");
1655
+ rjb_check_exception(jenv, 0);
1656
+ methods = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid);
1657
+ rjb_check_exception(jenv, 0);
1658
+ setup_constructors(jenv, &ptr->constructors, methods);
1659
+ mid = (*jenv)->GetMethodID(jenv, klass, "getFields", "()[Ljava/lang/reflect/Field;");
1660
+ rjb_check_exception(jenv, 0);
1661
+ flds = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid);
1662
+ rjb_check_exception(jenv, 0);
1663
+ setup_fields(jenv, &ptr->idata.fields, flds);
1664
+
1665
+ register_class(self, classname);
1666
+ load_constants(jenv, ptr->idata.obj, self, flds);
1667
+ }
1668
+
1669
+ /*
1670
+ * load Java Virtual Machine
1671
+ * def load(class_path = '', vmargs = [])
1672
+ * class_path: passes for the class dir and jar name
1673
+ * vmargs: strng array of vmarg (such as -Xrs)
1674
+ *
1675
+ * change in rjb 0.1.7, omit first argument for JNI version.
1676
+ * because I misunderstood the number means (JVM but JNI).
1677
+ */
1678
+ static VALUE rjb_s_load(int argc, VALUE* argv, VALUE self)
1679
+ {
1680
+ JNIEnv* jenv;
1681
+ JavaVMInitArgs vm_args;
1682
+ jint res;
1683
+ VALUE classpath;
1684
+ VALUE user_path;
1685
+ VALUE vm_argv;
1686
+ char* userpath;
1687
+ ID stradd = rb_intern("<<");
1688
+ ID pathsep = rb_intern("PATH_SEPARATOR");
1689
+ int i;
1690
+ jclass jmethod;
1691
+ jclass jfield;
1692
+ jclass jconstructor;
1693
+
1694
+ if (rjb_jvm)
1695
+ {
1696
+ return Qnil;
1697
+ }
1698
+
1699
+ memset(&vm_args, 0, sizeof(vm_args));
1700
+ vm_args.version = JNI_VERSION_1_4;
1701
+ rb_scan_args(argc, argv, "02", &user_path, &vm_argv);
1702
+ if (!NIL_P(user_path))
1703
+ {
1704
+ Check_Type(user_path, T_STRING);
1705
+ }
1706
+ else
1707
+ {
1708
+ user_path = rb_str_new2(".");
1709
+ }
1710
+ classpath = rb_cvar_get(rjb, cvar_classpath);
1711
+ for (i = 0; i < RARRAY_LEN(classpath); i++)
1712
+ {
1713
+ rb_funcall(user_path, stradd, 1, rb_const_get(rb_cFile, pathsep));
1714
+ rb_funcall(user_path, stradd, 1, rb_ary_entry(classpath, 0));
1715
+ }
1716
+ userpath = StringValueCStr(user_path);
1717
+
1718
+ if (!NIL_P(vm_argv))
1719
+ {
1720
+ Check_Type(vm_argv, T_ARRAY);
1721
+ }
1722
+ jenv = NULL;
1723
+ res = rjb_create_jvm(&jenv, &vm_args, userpath, vm_argv);
1724
+ if (res < 0)
1725
+ {
1726
+ rjb_jvm = NULL;
1727
+ rb_raise(rb_eRuntimeError, "can't create Java VM");
1728
+ } else {
1729
+ main_jenv = jenv;
1730
+ }
1731
+
1732
+ RJB_FIND_CLASS(jconstructor, "java/lang/reflect/Constructor");
1733
+ RJB_LOAD_METHOD(ctrGetParameterTypes, jconstructor, "getParameterTypes", "()[Ljava/lang/Class;");
1734
+ RJB_FIND_CLASS(jmethod, "java/lang/reflect/Method");
1735
+ RJB_LOAD_METHOD(method_getModifiers, jmethod, "getModifiers", "()I");
1736
+ RJB_LOAD_METHOD(method_getName, jmethod, "getName", "()Ljava/lang/String;");
1737
+ RJB_LOAD_METHOD(getParameterTypes, jmethod, "getParameterTypes", "()[Ljava/lang/Class;");
1738
+ RJB_LOAD_METHOD(getReturnType, jmethod, "getReturnType", "()Ljava/lang/Class;");
1739
+ rjb_check_exception(jenv, 1);
1740
+
1741
+ RJB_FIND_CLASS(jfield, "java/lang/reflect/Field");
1742
+ RJB_LOAD_METHOD(field_getModifiers, jfield, "getModifiers", "()I");
1743
+ RJB_LOAD_METHOD(field_getName, jfield, "getName", "()Ljava/lang/String;");
1744
+ RJB_LOAD_METHOD(field_getType, jfield, "getType", "()Ljava/lang/Class;");
1745
+ rjb_check_exception(jenv, 1);
1746
+
1747
+ RJB_HOLD_CLASS(j_class, "java/lang/Class");
1748
+ RJB_LOAD_METHOD(rjb_class_getName, j_class, "getName", "()Ljava/lang/String;");
1749
+ rjb_check_exception(jenv, 1);
1750
+
1751
+ RJB_HOLD_CLASS(rjb_j_throwable, "java/lang/Throwable");
1752
+ RJB_LOAD_METHOD(rjb_throwable_getMessage, rjb_j_throwable, "getMessage", "()Ljava/lang/String;");
1753
+ rjb_check_exception(jenv, 1);
1754
+
1755
+ RJB_HOLD_CLASS(j_string, "java/lang/String");
1756
+ RJB_LOAD_METHOD(str_tostring, j_string, "toString", "()Ljava/lang/String;");
1757
+ rjb_check_exception(jenv, 1);
1758
+
1759
+ RJB_HOLD_CLASS(j_object, "java/lang/Object");
1760
+ rjb_check_exception(jenv, 1);
1761
+
1762
+ RJB_HOLD_CLASS(j_url, "java/net/URL");
1763
+ RJB_LOAD_METHOD(url_new, j_url, "<init>", "(Ljava/lang/String;)V");
1764
+ rjb_check_exception(jenv, 1);
1765
+
1766
+ for (i = PRM_INT; i < PRM_LAST; i++)
1767
+ {
1768
+ jclass klass;
1769
+ RJB_FIND_CLASS(klass, jpcvt[i].classname);
1770
+ if (i == PRM_BOOLEAN)
1771
+ {
1772
+ RJB_LOAD_STATIC_METHOD(jpcvt[i].ctr_id, klass, "valueOf", jpcvt[i].ctrsig);
1773
+ }
1774
+ else if (jpcvt[i].ctrsig)
1775
+ {
1776
+ RJB_LOAD_METHOD(jpcvt[i].ctr_id, klass, "<init>", jpcvt[i].ctrsig);
1777
+ }
1778
+ RJB_LOAD_METHOD(jpcvt[i].to_prim_id, klass,
1779
+ jpcvt[i].to_prim_method, jpcvt[i].prmsig);
1780
+
1781
+ jpcvt[i].klass = (*jenv)->NewGlobalRef(jenv, klass);
1782
+ }
1783
+
1784
+ jklass = import_class(jenv, j_class, rb_str_new2("java.lang.Class"));
1785
+ rb_define_method(rb_singleton_class(jklass), "forName", rjb_class_forname, -1);
1786
+ rb_define_alias(rb_singleton_class(jklass), "for_name", "forName");
1787
+ rb_gc_register_address(&jklass);
1788
+
1789
+ return Qnil;
1790
+ }
1791
+
1792
+ /*
1793
+ * load Java Virtual Machine with default arguments.
1794
+ */
1795
+ VALUE rjb_load_vm_default()
1796
+ {
1797
+ if (rjb_jvm) return Qfalse;
1798
+
1799
+ rb_warning("Rjb::implicit jvm loading");
1800
+ return rjb_s_load(0, NULL, 0);
1801
+ }
1802
+
1803
+ /*
1804
+ * common prelude
1805
+ */
1806
+ JNIEnv* rjb_prelude()
1807
+ {
1808
+ JNIEnv* jenv = NULL;
1809
+ rjb_load_vm_default();
1810
+ jenv = rjb_attach_current_thread();
1811
+ (*jenv)->ExceptionClear(jenv);
1812
+ return jenv;
1813
+ }
1814
+
1815
+ jobject get_systemloader(JNIEnv* jenv)
1816
+ {
1817
+ if (!j_classloader)
1818
+ {
1819
+ RJB_HOLD_CLASS(j_classloader, "java/lang/ClassLoader");
1820
+ RJB_LOAD_STATIC_METHOD(get_system_classloader, j_classloader,
1821
+ "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
1822
+ rjb_check_exception(jenv, 1);
1823
+ }
1824
+ return (*jenv)->CallStaticObjectMethod(jenv, j_classloader, get_system_classloader);
1825
+ }
1826
+
1827
+ static jobject get_class_loader(JNIEnv* jenv)
1828
+ {
1829
+ return (url_loader) ? url_loader : get_systemloader(jenv);
1830
+ }
1831
+
1832
+ /*
1833
+ * unload Java Virtual Machine
1834
+ *
1835
+ * def unload()
1836
+ * classes.clear
1837
+ * unload(jvm)
1838
+ * end
1839
+ */
1840
+ static int clear_classes(VALUE key, VALUE val, VALUE dummy)
1841
+ {
1842
+ return ST_DELETE;
1843
+ }
1844
+ static VALUE rjb_s_unload(int argc, VALUE* argv, VALUE self)
1845
+ {
1846
+ int result = 0;
1847
+ #if defined(HAVE_RB_HASH_FOREACH) || defined(RUBINIUS)
1848
+ rb_hash_foreach(rjb_loaded_classes, clear_classes, 0);
1849
+ #else
1850
+ #if defined(RHASH_TBL)
1851
+ st_foreach(RHASH_TBL(rjb_loaded_classes), clear_classes, 0);
1852
+ #else
1853
+ st_foreach(RHASH(rjb_loaded_classes)->tbl, clear_classes, 0);
1854
+ #endif
1855
+ #endif
1856
+
1857
+ if (rjb_jvm)
1858
+ {
1859
+ JNIEnv* jenv = rjb_attach_current_thread();
1860
+ (*jenv)->ExceptionClear(jenv);
1861
+ result = (*rjb_jvm)->DestroyJavaVM(rjb_jvm);
1862
+ rjb_jvm = NULL;
1863
+ }
1864
+ return INT2NUM(result);
1865
+ }
1866
+
1867
+ static VALUE rjb_s_loaded(VALUE self)
1868
+ {
1869
+ return (rjb_jvm) ? Qtrue : Qfalse;
1870
+ }
1871
+
1872
+ /*
1873
+ * return all classes that were already loaded.
1874
+ * this method simply returns the global hash,
1875
+ * but it's safe because the hash was frozen.
1876
+ */
1877
+ static VALUE rjb_s_classes(VALUE self)
1878
+ {
1879
+ return rjb_loaded_classes;
1880
+ }
1881
+
1882
+ /**
1883
+ * For JRuby conpatible option
1884
+ */
1885
+ static VALUE rjb_s_set_pconversion(VALUE self, VALUE val)
1886
+ {
1887
+ primitive_conversion = (RTEST(val)) ? Qtrue : Qfalse;
1888
+ return val;
1889
+ }
1890
+
1891
+ /**
1892
+ * For JRuby conpatible option
1893
+ */
1894
+ static VALUE rjb_s_get_pconversion(VALUE self)
1895
+ {
1896
+ return primitive_conversion;
1897
+ }
1898
+
1899
+
1900
+ /*
1901
+ * free java class
1902
+ */
1903
+ #if 0
1904
+ static void free_constructor(struct cls_constructor* p)
1905
+ {
1906
+ free(p->arg_convert);
1907
+ free(p->method_signature);
1908
+ }
1909
+ static int free_method_item(ID key, struct cls_method* pm, int dummy)
1910
+ {
1911
+ for (; pm; pm = pm->next)
1912
+ {
1913
+ free_constructor(&pm->basic);
1914
+ }
1915
+ return ST_CONTINUE;
1916
+ }
1917
+ #endif
1918
+
1919
+ /*
1920
+ * finalize Object instance
1921
+ */
1922
+ static VALUE rjb_delete_ref(struct jvi_data* ptr)
1923
+ {
1924
+ JNIEnv* jenv = rjb_attach_current_thread();
1925
+ if (jenv)
1926
+ {
1927
+ (*jenv)->DeleteGlobalRef(jenv, ptr->obj);
1928
+ }
1929
+ return Qnil;
1930
+ }
1931
+
1932
+ /*
1933
+ * finalize Bridge instance
1934
+ */
1935
+ static VALUE rj_bridge_free(struct rj_bridge* ptr)
1936
+ {
1937
+ JNIEnv* jenv = rjb_attach_current_thread();
1938
+ (*jenv)->DeleteLocalRef(jenv, ptr->proxy);
1939
+ (*jenv)->DeleteLocalRef(jenv, ptr->bridge);
1940
+ return Qnil;
1941
+ }
1942
+
1943
+ /*
1944
+ * mark wrapped object in the Bridge
1945
+ */
1946
+ static void rj_bridge_mark(struct rj_bridge* ptr)
1947
+ {
1948
+ rb_gc_mark(ptr->wrapped);
1949
+ }
1950
+
1951
+ /*
1952
+ * finalize Class instance
1953
+ */
1954
+ static VALUE rjb_s_free(struct jv_data* ptr)
1955
+ {
1956
+ /* class never delete
1957
+ JNIEnv* jenv = rjb_attach_current_thread();
1958
+ struct cls_constructor** c;
1959
+
1960
+ rjb_delete_ref(&ptr->idata);
1961
+ if (ptr->constructors)
1962
+ {
1963
+ for (c = ptr->constructors; *c; c++)
1964
+ {
1965
+ free_constructor(*c);
1966
+ }
1967
+ }
1968
+ free(ptr->constructors);
1969
+ if (ptr->idata.methods)
1970
+ {
1971
+ st_foreach(ptr->idata.methods, (int(*)())free_method_item, 0);
1972
+ st_free_table(ptr->idata.methods);
1973
+ }
1974
+ (*jenv)->DeleteGlobalRef(jenv, ptr->idata.klass);
1975
+ st_delete(RHASH(rjb_loaded_classes)->tbl, clsname, NULL);
1976
+ */
1977
+ return Qnil;
1978
+ }
1979
+
1980
+ /*
1981
+ * create new instance of this class
1982
+ */
1983
+ static VALUE createinstance(JNIEnv* jenv, int argc, VALUE* argv,
1984
+ VALUE self, struct cls_constructor* pc)
1985
+ {
1986
+ int i;
1987
+ char* psig = pc->method_signature;
1988
+ jobject obj = NULL;
1989
+ VALUE result;
1990
+ struct jv_data* jklass;
1991
+ struct jvi_data* org;
1992
+ jvalue* args = (argc) ? ALLOCA_N(jvalue, argc) : NULL;
1993
+
1994
+ Data_Get_Struct(self, struct jv_data, jklass);
1995
+ org = &jklass->idata;
1996
+
1997
+ for (i = 0; i < argc; i++)
1998
+ {
1999
+ R2J pr2j = *(pc->arg_convert + i);
2000
+ pr2j(jenv, argv[i], args + i, psig, 0);
2001
+ psig = next_sig(psig);
2002
+ rjb_check_exception(jenv, 1);
2003
+ }
2004
+ obj = (*jenv)->NewObjectA(jenv, org->obj, pc->id, args);
2005
+ if (!obj)
2006
+ {
2007
+ rjb_check_exception(jenv, 1);
2008
+ }
2009
+ psig = pc->method_signature;
2010
+ for (i = 0; i < argc; i++)
2011
+ {
2012
+ R2J pr2j = *(pc->arg_convert + i);
2013
+ pr2j(jenv, argv[i], args + i, psig, 1);
2014
+ psig = next_sig(psig);
2015
+ }
2016
+
2017
+ result = register_instance(jenv, self, jklass, obj);
2018
+ (*jenv)->DeleteLocalRef(jenv, obj);
2019
+ return result;
2020
+ }
2021
+
2022
+ static VALUE import_class(JNIEnv* jenv, jclass jcls, VALUE clsname)
2023
+ {
2024
+ VALUE v;
2025
+ VALUE rexp;
2026
+ struct jv_data* ptr;
2027
+ char* pclsname = StringValueCStr(clsname);
2028
+ char* nm = ALLOCA_N(char, strlen(pclsname) + 1);
2029
+ strcpy(nm, pclsname);
2030
+ *nm = toupper(*nm);
2031
+ for (pclsname = nm; *pclsname; pclsname++)
2032
+ {
2033
+ if (*pclsname == '.')
2034
+ {
2035
+ *pclsname = '_';
2036
+ }
2037
+ }
2038
+ rexp = rb_define_class_under(rjb, nm, rjbc);
2039
+ ptr = ALLOC(struct jv_data);
2040
+ memset(ptr, 0, sizeof(struct jv_data));
2041
+ v = Data_Wrap_Struct(rexp, NULL, rjb_s_free, ptr);
2042
+ ptr->idata.obj = (*jenv)->NewGlobalRef(jenv, jcls);
2043
+ setup_metadata(jenv, v, ptr, clsname);
2044
+ return v;
2045
+ }
2046
+
2047
+ static VALUE rjb_i_prepare_proxy(VALUE self)
2048
+ {
2049
+ return rb_funcall(self, rb_intern("instance_eval"), 1,
2050
+ rb_str_new2("instance_eval(&" USER_INITIALIZE ")"));
2051
+ }
2052
+
2053
+ static VALUE register_instance(JNIEnv* jenv, VALUE klass, struct jv_data* org, jobject obj)
2054
+ {
2055
+ VALUE v;
2056
+ VALUE iproc;
2057
+ struct jvi_data* ptr = ALLOC(struct jvi_data);
2058
+ memset(ptr, 0, sizeof(struct jvi_data));
2059
+ v = Data_Wrap_Struct(rjbi, NULL, rjb_delete_ref, ptr);
2060
+ ptr->klass = org->idata.obj;
2061
+ ptr->obj = (*jenv)->NewGlobalRef(jenv, obj);
2062
+ ptr->methods = org->idata.methods;
2063
+ ptr->fields = org->idata.fields;
2064
+ iproc = rb_ivar_get(klass, user_initialize);
2065
+ if (iproc != Qnil)
2066
+ {
2067
+ rb_ivar_set(v, user_initialize, iproc);
2068
+ rb_funcall(v, rb_intern("_prepare_proxy"), 0, 0);
2069
+ }
2070
+ return v;
2071
+ }
2072
+
2073
+ /*
2074
+ * temporary signature check
2075
+ * return !0 if found
2076
+ */
2077
+ static int check_rtype(JNIEnv* jenv, VALUE v, char* p)
2078
+ {
2079
+ char* pcls = NULL;
2080
+ if (*p == 'L')
2081
+ {
2082
+ char* pt = strchr(p, ';');
2083
+ if (pt)
2084
+ {
2085
+ int len = pt - p - 1;
2086
+ pcls = ALLOCA_N(char, len + 1);
2087
+ strncpy(pcls, p + 1, len);
2088
+ *(pcls + len) = '\0';
2089
+ }
2090
+ }
2091
+ if (pcls && !strcmp("java.lang.Object", pcls))
2092
+ {
2093
+ return 1;
2094
+ }
2095
+ switch (TYPE(v))
2096
+ {
2097
+ case T_FIXNUM:
2098
+ return strchr("BCDFIJS", *p) != NULL;
2099
+ case T_FLOAT:
2100
+ return strchr("DF", *p) != NULL;
2101
+ case T_STRING:
2102
+ return pcls && !strcmp("java.lang.String", pcls);
2103
+ case T_TRUE:
2104
+ case T_FALSE:
2105
+ return *p == 'Z';
2106
+ case T_ARRAY:
2107
+ return *p == '[';
2108
+ case T_DATA:
2109
+ if (IS_RJB_OBJECT(v) && pcls)
2110
+ {
2111
+ /* imported object */
2112
+ jclass cls;
2113
+ struct jvi_data* ptr;
2114
+ int result = 0;
2115
+ if (!strcmp("java.lang.String", pcls)) return 1;
2116
+ Data_Get_Struct(v, struct jvi_data, ptr);
2117
+ RJB_FIND_CLASS(cls, java2jniname(pcls));
2118
+ if (cls)
2119
+ {
2120
+ result = (cls && (*jenv)->IsInstanceOf(jenv, ptr->obj, cls));
2121
+ (*jenv)->DeleteLocalRef(jenv, cls);
2122
+ }
2123
+ return result;
2124
+ }
2125
+ /* fall down to the next case */
2126
+ case T_OBJECT:
2127
+ /* fall down to the next case */
2128
+ default:
2129
+ if (pcls || *p == '[')
2130
+ {
2131
+ return 1;
2132
+ }
2133
+ return 0;
2134
+ }
2135
+ }
2136
+
2137
+ /*
2138
+ * new instance with signature
2139
+ */
2140
+ static VALUE rjb_newinstance_s(int argc, VALUE* argv, VALUE self)
2141
+ {
2142
+ VALUE vsig, rest;
2143
+ char* sig;
2144
+ VALUE ret = Qnil;
2145
+ struct jv_data* ptr;
2146
+ int found = 0;
2147
+ JNIEnv* jenv = rjb_prelude();
2148
+
2149
+ rb_scan_args(argc, argv, "1*", &vsig, &rest);
2150
+ sig = StringValueCStr(vsig);
2151
+ Data_Get_Struct(self, struct jv_data, ptr);
2152
+ if (ptr->constructors)
2153
+ {
2154
+ struct cls_constructor** pc = ptr->constructors;
2155
+ for (pc = ptr->constructors; *pc; pc++)
2156
+ {
2157
+ if ((*pc)->arg_count == argc - 1
2158
+ && !strcmp(sig, (*pc)->method_signature))
2159
+ {
2160
+ found = 1;
2161
+ ret = createinstance(jenv, argc - 1, argv + 1, self, *pc);
2162
+ break;
2163
+ }
2164
+ }
2165
+ }
2166
+ if (!found) {
2167
+ rb_raise(rb_eRuntimeError, "Constructor not found");
2168
+ }
2169
+ return ret;
2170
+ }
2171
+
2172
+ static VALUE rjb_newinstance(int argc, VALUE* argv, VALUE self)
2173
+ {
2174
+ VALUE ret = Qnil;
2175
+ struct jv_data* ptr;
2176
+ struct cls_constructor** pc;
2177
+ int found = 0;
2178
+ JNIEnv* jenv = rjb_prelude();
2179
+
2180
+ Data_Get_Struct(self, struct jv_data, ptr);
2181
+
2182
+ if (ptr->constructors)
2183
+ {
2184
+ int i;
2185
+ char* psig;
2186
+ for (pc = ptr->constructors; *pc; pc++)
2187
+ {
2188
+ if ((*pc)->arg_count == argc)
2189
+ {
2190
+ found = 1;
2191
+ psig = (*pc)->method_signature;
2192
+ for (i = 0; i < argc; i++)
2193
+ {
2194
+ if (!check_rtype(jenv, *(argv + i), psig))
2195
+ {
2196
+ found = 0;
2197
+ break;
2198
+ }
2199
+ psig = next_sig(psig);
2200
+ }
2201
+ if (found)
2202
+ {
2203
+ ret = createinstance(jenv, argc, argv, self, *pc);
2204
+ break;
2205
+ }
2206
+ }
2207
+ }
2208
+ }
2209
+ if (!found) {
2210
+ rb_raise(rb_eRuntimeError, "Constructor not found");
2211
+ }
2212
+ return ret;
2213
+ }
2214
+
2215
+ /*
2216
+ * find java class using added classloader
2217
+ */
2218
+ jclass rjb_find_class_by_name(JNIEnv* jenv, const char* name)
2219
+ {
2220
+ jclass cls;
2221
+ if (url_loader)
2222
+ {
2223
+ jvalue v;
2224
+ char* binname = ALLOCA_N(char, strlen(name) + 32);
2225
+ strcpy(binname, name);
2226
+ v.l = (*jenv)->NewStringUTF(jenv, jniname2java(binname));
2227
+ cls = (*jenv)->CallObjectMethod(jenv, url_loader, rjb_load_class, v);
2228
+ (*jenv)->DeleteLocalRef(jenv, v.l);
2229
+ }
2230
+ else
2231
+ {
2232
+ cls = (*jenv)->FindClass(jenv, name);
2233
+ }
2234
+ return cls;
2235
+ }
2236
+
2237
+ /*
2238
+ * find java class from classname
2239
+ */
2240
+ jclass rjb_find_class(JNIEnv* jenv, VALUE name)
2241
+ {
2242
+ char* cname;
2243
+ char* jnicls;
2244
+
2245
+ Check_Type(name, T_STRING);
2246
+ cname = StringValueCStr(name);
2247
+ jnicls = ALLOCA_N(char, strlen(cname) + 1);
2248
+ strcpy(jnicls, cname);
2249
+ return rjb_find_class_by_name(jenv, java2jniname(jnicls));
2250
+ }
2251
+
2252
+ /*
2253
+ * get specified method signature
2254
+ */
2255
+ static VALUE get_signatures(VALUE mname, st_table* st)
2256
+ {
2257
+ VALUE ret;
2258
+ struct cls_method* pm;
2259
+ ID rmid = rb_to_id(mname);
2260
+
2261
+ if (!st_lookup(st, rmid, (st_data_t*)&pm))
2262
+ {
2263
+ const char* tname = rb_id2name(rmid);
2264
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname);
2265
+ }
2266
+ ret = rb_ary_new();
2267
+ for (; pm; pm = pm->next)
2268
+ {
2269
+ if (pm->basic.method_signature) {
2270
+ rb_ary_push(ret, rb_str_new2(pm->basic.method_signature));
2271
+ } else {
2272
+ rb_ary_push(ret, Qnil);
2273
+ }
2274
+ }
2275
+ return ret;
2276
+ }
2277
+
2278
+ static VALUE rjb_get_signatures(VALUE self, VALUE mname)
2279
+ {
2280
+ struct jv_data* ptr;
2281
+
2282
+ Data_Get_Struct(self, struct jv_data, ptr);
2283
+ return get_signatures(mname, ptr->idata.methods);
2284
+ }
2285
+
2286
+ static VALUE rjb_get_static_signatures(VALUE self, VALUE mname)
2287
+ {
2288
+ struct jv_data* ptr;
2289
+
2290
+ Data_Get_Struct(self, struct jv_data, ptr);
2291
+ return get_signatures(mname, ptr->static_methods);
2292
+ }
2293
+
2294
+ static VALUE rjb_get_ctor_signatures(VALUE self)
2295
+ {
2296
+ VALUE ret;
2297
+ struct jv_data* ptr;
2298
+ struct cls_constructor** pc;
2299
+
2300
+ Data_Get_Struct(self, struct jv_data, ptr);
2301
+ ret = rb_ary_new();
2302
+ if (ptr->constructors)
2303
+ {
2304
+ for (pc = ptr->constructors; *pc; pc++)
2305
+ {
2306
+ rb_ary_push(ret, rb_str_new2((*pc)->method_signature));
2307
+ }
2308
+ }
2309
+ return ret;
2310
+ }
2311
+
2312
+ /*
2313
+ * jclass Rjb::bind(rbobj, interface_name)
2314
+ */
2315
+ static VALUE rjb_s_bind(VALUE self, VALUE rbobj, VALUE itfname)
2316
+ {
2317
+ VALUE result = Qnil;
2318
+ jclass itf;
2319
+ JNIEnv* jenv = rjb_prelude();
2320
+
2321
+ itf = rjb_find_class(jenv, itfname);
2322
+ rjb_check_exception(jenv, 1);
2323
+ if (itf)
2324
+ {
2325
+ struct rj_bridge* ptr = ALLOC(struct rj_bridge);
2326
+ memset(ptr, 0, sizeof(struct rj_bridge));
2327
+ ptr->bridge = (*jenv)->NewGlobalRef(jenv,
2328
+ (*jenv)->AllocObject(jenv, rjb_rbridge));
2329
+ if (!ptr->bridge)
2330
+ {
2331
+ free(ptr);
2332
+ rjb_check_exception(jenv, 1);
2333
+ return Qnil;
2334
+ }
2335
+ ptr->proxy = (*jenv)->CallObjectMethod(jenv, ptr->bridge,
2336
+ rjb_register_bridge, itf);
2337
+ ptr->proxy = (*jenv)->NewGlobalRef(jenv, ptr->proxy);
2338
+ ptr->wrapped = rbobj;
2339
+ result = Data_Wrap_Struct(rjbb, rj_bridge_mark, rj_bridge_free, ptr);
2340
+ rb_ary_push(proxies, result);
2341
+ }
2342
+ return result;
2343
+ }
2344
+
2345
+ /*
2346
+ * Rjb's class is not Class but Object, so add class_eval for the Java class.
2347
+ */
2348
+ static VALUE rjb_class_eval(int argc, VALUE* argv, VALUE self)
2349
+ {
2350
+ if (rb_block_given_p())
2351
+ {
2352
+ rb_ivar_set(self, user_initialize, rb_block_proc());
2353
+ }
2354
+ return self;
2355
+ }
2356
+
2357
+ /*
2358
+ * jclass Rjb::bind(rbobj, interface_name)
2359
+ */
2360
+ static VALUE rjb_s_unbind(VALUE self, VALUE rbobj)
2361
+ {
2362
+ #if defined(RUBINIUS)
2363
+ return rb_funcall(proxies, rb_intern("delete"), 1, rbobj);
2364
+ #else
2365
+ return rb_ary_delete(proxies, rbobj);
2366
+ #endif
2367
+ }
2368
+
2369
+ /*
2370
+ * Jclass Rjb::import(classname)
2371
+ */
2372
+ static VALUE rjb_s_import(VALUE self, VALUE clsname)
2373
+ {
2374
+ JNIEnv* jenv;
2375
+ jclass jcls;
2376
+ VALUE v = rb_hash_aref(rjb_loaded_classes, clsname);
2377
+ if (v != Qnil)
2378
+ {
2379
+ return v;
2380
+ }
2381
+
2382
+ jenv = rjb_prelude();
2383
+ jcls = rjb_find_class(jenv, clsname);
2384
+ if (!jcls)
2385
+ {
2386
+ rjb_check_exception(jenv, 0);
2387
+ rb_raise(rb_eRuntimeError, "`%s' not found", StringValueCStr(clsname));
2388
+ }
2389
+ v = import_class(jenv, jcls, clsname);
2390
+ return v;
2391
+ }
2392
+
2393
+ static void register_class(VALUE self, VALUE clsname)
2394
+ {
2395
+ rb_define_singleton_method(self, "new", rjb_newinstance, -1);
2396
+ rb_define_singleton_method(self, "new_with_sig", rjb_newinstance_s, -1);
2397
+ rb_define_singleton_method(self, "class_eval", rjb_class_eval, -1);
2398
+ rb_define_singleton_method(self, "sigs", rjb_get_signatures, 1);
2399
+ rb_define_singleton_method(self, "static_sigs", rjb_get_static_signatures, 1);
2400
+ rb_define_singleton_method(self, "ctor_sigs", rjb_get_ctor_signatures, 0);
2401
+ rb_ivar_set(self, user_initialize, Qnil);
2402
+ /*
2403
+ * the hash was frozen, so it need to call st_ func directly.
2404
+ */
2405
+
2406
+ #if defined(HAVE_RB_HASH_ASET) || defined(RUBINIUS)
2407
+ rb_hash_aset(rjb_loaded_classes, clsname, self);
2408
+ #else
2409
+ #ifdef RHASH_TBL
2410
+ st_insert(RHASH_TBL(rjb_loaded_classes), clsname, self);
2411
+ #else
2412
+ st_insert(RHASH(rjb_loaded_classes)->tbl, clsname, self);
2413
+ #endif
2414
+ #endif
2415
+ }
2416
+
2417
+ static jobject conv_jarname_to_url(JNIEnv* jenv, VALUE jarname)
2418
+ {
2419
+ jvalue arg;
2420
+ jobject url;
2421
+ size_t len;
2422
+ char* jarp;
2423
+ char* urlp;
2424
+
2425
+ SafeStringValue(jarname);
2426
+ jarp = StringValueCStr(jarname);
2427
+ urlp = ALLOCA_N(char, strlen(jarp) + 32);
2428
+ if (strncmp(jarp, "http:", 5) && strncmp(jarp, "https:", 6))
2429
+ {
2430
+ #if defined(DOSISH)
2431
+ if (strlen(jarp) > 1 && jarp[1] == ':')
2432
+ {
2433
+ sprintf(urlp, "file:///%s", jarp);
2434
+ }
2435
+ else
2436
+ #endif
2437
+ {
2438
+ sprintf(urlp, "file://%s", jarp);
2439
+ }
2440
+ }
2441
+ else
2442
+ {
2443
+ strcpy(urlp, jarp);
2444
+ }
2445
+ #if defined(DOSISH)
2446
+ for (len = 0; len < strlen(urlp); len++)
2447
+ {
2448
+ if (urlp[len] == '\\')
2449
+ {
2450
+ urlp[len] = '/';
2451
+ }
2452
+ }
2453
+ #endif
2454
+ arg.l = (*jenv)->NewStringUTF(jenv, urlp);
2455
+ rjb_check_exception(jenv, 0);
2456
+ url = (*jenv)->NewObject(jenv, j_url, url_new, arg);
2457
+ rjb_check_exception(jenv, 0);
2458
+ return url;
2459
+ }
2460
+
2461
+ /*
2462
+ * Rjb::add_classpath(jarname)
2463
+ */
2464
+ static VALUE rjb_s_add_classpath(VALUE self, VALUE jarname)
2465
+ {
2466
+ VALUE cpath = rb_cvar_get(self, cvar_classpath);
2467
+ SafeStringValue(jarname);
2468
+ rb_ary_push(cpath, jarname);
2469
+ return cpath;
2470
+ }
2471
+
2472
+ /*
2473
+ * Rjb::add_jar(jarname)
2474
+ */
2475
+ static VALUE rjb_s_add_jar(VALUE self, VALUE jarname)
2476
+ {
2477
+ size_t i;
2478
+ JNIEnv* jenv;
2479
+ size_t count;
2480
+ jvalue args[2];
2481
+
2482
+ if (rb_type(jarname) != T_ARRAY)
2483
+ {
2484
+ SafeStringValue(jarname);
2485
+ count = 0;
2486
+ }
2487
+ else
2488
+ {
2489
+ count = RARRAY_LEN(jarname);
2490
+ }
2491
+ jenv = rjb_prelude();
2492
+ if (!j_url_loader)
2493
+ {
2494
+ j_url_loader = (*jenv)->NewGlobalRef(jenv,
2495
+ (*jenv)->FindClass(jenv, "java/net/URLClassLoader"));
2496
+ RJB_LOAD_METHOD(rjb_load_class, j_url_loader, "loadClass",
2497
+ "(Ljava/lang/String;)Ljava/lang/Class;");
2498
+ RJB_LOAD_METHOD(url_loader_new, j_url_loader, "<init>",
2499
+ "([Ljava/net/URL;Ljava/lang/ClassLoader;)V");
2500
+ }
2501
+ args[0].l = (*jenv)->NewObjectArray(jenv, (count == 0) ? 1 : count, j_url, NULL);
2502
+ rjb_check_exception(jenv, 0);
2503
+ if (!count)
2504
+ {
2505
+ (*jenv)->SetObjectArrayElement(jenv, args[0].l, 0,
2506
+ conv_jarname_to_url(jenv, jarname));
2507
+ }
2508
+ else
2509
+ {
2510
+ for (i = 0; i < count; i++) {
2511
+ (*jenv)->SetObjectArrayElement(jenv, args[0].l, i,
2512
+ conv_jarname_to_url(jenv, rb_ary_entry(jarname, i)));
2513
+ }
2514
+ }
2515
+ rjb_check_exception(jenv, 0);
2516
+ args[1].l = get_class_loader(jenv);
2517
+ url_loader = (*jenv)->NewObjectA(jenv, j_url_loader, url_loader_new, args);
2518
+ rjb_check_exception(jenv, 0);
2519
+ (*jenv)->NewGlobalRef(jenv, url_loader);
2520
+ (*jenv)->DeleteLocalRef(jenv, args[0].l);
2521
+ return Qtrue;
2522
+ }
2523
+
2524
+ /*
2525
+ * return class name
2526
+ */
2527
+ static VALUE rjb_i_class(VALUE self)
2528
+ {
2529
+ JNIEnv* jenv = rjb_attach_current_thread();
2530
+ struct jvi_data* ptr;
2531
+ jstring nm;
2532
+ Data_Get_Struct(self, struct jvi_data, ptr);
2533
+ nm = (*jenv)->CallObjectMethod(jenv, ptr->klass, rjb_class_getName);
2534
+ rjb_check_exception(jenv, 0);
2535
+ return jstring2val(jenv, nm);
2536
+ }
2537
+
2538
+ /*
2539
+ * invoker
2540
+ */
2541
+ static VALUE getter(JNIEnv* jenv, struct cls_field* pf, struct jvi_data* ptr)
2542
+ {
2543
+ jvalue jv;
2544
+ switch (pf->result_signature)
2545
+ {
2546
+ case 'D':
2547
+ if (pf->static_field)
2548
+ {
2549
+ jv.d = (*jenv)->GetStaticDoubleField(jenv, ptr->klass, pf->id);
2550
+ }
2551
+ else
2552
+ {
2553
+ jv.d = (*jenv)->GetDoubleField(jenv, ptr->obj, pf->id);
2554
+ }
2555
+ break;
2556
+ case 'Z':
2557
+ if (pf->static_field)
2558
+ {
2559
+ jv.z = (*jenv)->GetStaticBooleanField(jenv, ptr->klass, pf->id);
2560
+ }
2561
+ else
2562
+ {
2563
+ jv.z = (*jenv)->GetBooleanField(jenv, ptr->obj, pf->id);
2564
+ }
2565
+ break;
2566
+ case 'B':
2567
+ if (pf->static_field)
2568
+ {
2569
+ jv.b = (*jenv)->GetStaticByteField(jenv, ptr->klass, pf->id);
2570
+ }
2571
+ else
2572
+ {
2573
+ jv.b = (*jenv)->GetByteField(jenv, ptr->obj, pf->id);
2574
+ }
2575
+ break;
2576
+ case 'F':
2577
+ if (pf->static_field)
2578
+ {
2579
+ jv.f = (*jenv)->GetStaticFloatField(jenv, ptr->klass, pf->id);
2580
+ }
2581
+ else
2582
+ {
2583
+ jv.f = (*jenv)->GetFloatField(jenv, ptr->obj, pf->id);
2584
+ }
2585
+ break;
2586
+ case 'C':
2587
+ if (pf->static_field)
2588
+ {
2589
+ jv.c = (*jenv)->GetStaticCharField(jenv, ptr->klass, pf->id);
2590
+ }
2591
+ else
2592
+ {
2593
+ jv.c = (*jenv)->GetCharField(jenv, ptr->obj, pf->id);
2594
+ }
2595
+ break;
2596
+ case 'S':
2597
+ if (pf->static_field)
2598
+ {
2599
+ jv.s = (*jenv)->GetStaticShortField(jenv, ptr->klass, pf->id);
2600
+ }
2601
+ else
2602
+ {
2603
+ jv.s = (*jenv)->GetShortField(jenv, ptr->obj, pf->id);
2604
+ }
2605
+ break;
2606
+ case 'J':
2607
+ if (pf->static_field)
2608
+ {
2609
+ jv.j = (*jenv)->GetStaticLongField(jenv, ptr->klass, pf->id);
2610
+ }
2611
+ else
2612
+ {
2613
+ jv.j = (*jenv)->GetLongField(jenv, ptr->obj, pf->id);
2614
+ }
2615
+ break;
2616
+ case 'I':
2617
+ if (pf->static_field)
2618
+ {
2619
+ jv.i = (*jenv)->GetStaticIntField(jenv, ptr->klass, pf->id);
2620
+ }
2621
+ else
2622
+ {
2623
+ jv.i = (*jenv)->GetIntField(jenv, ptr->obj, pf->id);
2624
+ }
2625
+ break;
2626
+ default:
2627
+ if (pf->static_field)
2628
+ {
2629
+ jv.l = (*jenv)->GetStaticObjectField(jenv, ptr->klass, pf->id);
2630
+ }
2631
+ else
2632
+ {
2633
+ jv.l = (*jenv)->GetObjectField(jenv, ptr->obj, pf->id);
2634
+ }
2635
+ break;
2636
+ }
2637
+ if (pf->result_arraydepth)
2638
+ {
2639
+ return ja2r(pf->value_convert, jenv, jv, pf->result_arraydepth);
2640
+ }
2641
+ else
2642
+ {
2643
+ return pf->value_convert(jenv, jv);
2644
+ }
2645
+ }
2646
+
2647
+ static void setter(JNIEnv* jenv, struct cls_field* pf, struct jvi_data* ptr, VALUE val)
2648
+ {
2649
+ jvalue jv;
2650
+ pf->arg_convert(jenv, val, &jv, pf->field_signature, 0);
2651
+ switch (*pf->field_signature)
2652
+ {
2653
+ case 'D':
2654
+ if (pf->static_field)
2655
+ {
2656
+ (*jenv)->SetStaticDoubleField(jenv, ptr->klass, pf->id, jv.d);
2657
+ }
2658
+ else
2659
+ {
2660
+ (*jenv)->SetDoubleField(jenv, ptr->obj, pf->id, jv.d);
2661
+ }
2662
+ break;
2663
+ case 'Z':
2664
+ if (pf->static_field)
2665
+ {
2666
+ (*jenv)->SetStaticBooleanField(jenv, ptr->klass, pf->id, jv.z);
2667
+ }
2668
+ else
2669
+ {
2670
+ (*jenv)->SetBooleanField(jenv, ptr->obj, pf->id, jv.z);
2671
+ }
2672
+ break;
2673
+ case 'B':
2674
+ if (pf->static_field)
2675
+ {
2676
+ (*jenv)->SetStaticByteField(jenv, ptr->klass, pf->id, jv.b);
2677
+ }
2678
+ else
2679
+ {
2680
+ (*jenv)->SetByteField(jenv, ptr->obj, pf->id, jv.b);
2681
+ }
2682
+ break;
2683
+ case 'F':
2684
+ if (pf->static_field)
2685
+ {
2686
+ (*jenv)->SetStaticFloatField(jenv, ptr->klass, pf->id, jv.f);
2687
+ }
2688
+ else
2689
+ {
2690
+ (*jenv)->SetFloatField(jenv, ptr->obj, pf->id, jv.f);
2691
+ }
2692
+ break;
2693
+ case 'C':
2694
+ if (pf->static_field)
2695
+ {
2696
+ (*jenv)->SetStaticCharField(jenv, ptr->klass, pf->id, jv.c);
2697
+ }
2698
+ else
2699
+ {
2700
+ (*jenv)->SetCharField(jenv, ptr->obj, pf->id, jv.c);
2701
+ }
2702
+ break;
2703
+ case 'S':
2704
+ if (pf->static_field)
2705
+ {
2706
+ (*jenv)->SetStaticShortField(jenv, ptr->klass, pf->id, jv.s);
2707
+ }
2708
+ else
2709
+ {
2710
+ (*jenv)->SetShortField(jenv, ptr->obj, pf->id, jv.s);
2711
+ }
2712
+ break;
2713
+ case 'J':
2714
+ if (pf->static_field)
2715
+ {
2716
+ (*jenv)->SetStaticLongField(jenv, ptr->klass, pf->id, jv.j);
2717
+ }
2718
+ else
2719
+ {
2720
+ (*jenv)->SetLongField(jenv, ptr->obj, pf->id, jv.j);
2721
+ }
2722
+ break;
2723
+ case 'I':
2724
+ if (pf->static_field)
2725
+ {
2726
+ (*jenv)->SetStaticIntField(jenv, ptr->klass, pf->id, jv.i);
2727
+ }
2728
+ else
2729
+ {
2730
+ (*jenv)->SetIntField(jenv, ptr->obj, pf->id, jv.i);
2731
+ }
2732
+ break;
2733
+ default:
2734
+ if (pf->static_field)
2735
+ {
2736
+ (*jenv)->SetStaticObjectField(jenv, ptr->klass, pf->id, jv.l);
2737
+ }
2738
+ else
2739
+ {
2740
+ (*jenv)->SetObjectField(jenv, ptr->obj, pf->id, jv.l);
2741
+ }
2742
+ break;
2743
+ }
2744
+ pf->arg_convert(jenv, val, &jv, pf->field_signature, 1);
2745
+ }
2746
+
2747
+ static VALUE invoke(JNIEnv* jenv, struct cls_method* pm, struct jvi_data* ptr,
2748
+ int argc, VALUE* argv, const char* sig)
2749
+ {
2750
+ int i, found;
2751
+ jvalue jv;
2752
+ jvalue* args;
2753
+ char* psig;
2754
+ struct cls_method* orgpm = pm;
2755
+
2756
+ for (found = 0; pm; pm = pm->next)
2757
+ {
2758
+ if (argc == pm->basic.arg_count)
2759
+ {
2760
+ if (sig)
2761
+ {
2762
+ if (!strcmp(sig, pm->basic.method_signature))
2763
+ {
2764
+ found = 1;
2765
+ break;
2766
+ }
2767
+ }
2768
+ else
2769
+ {
2770
+ psig = pm->basic.method_signature;
2771
+ found = 1;
2772
+ for (i = 0; i < argc; i++)
2773
+ {
2774
+ if (!check_rtype(jenv, *(argv + i), psig))
2775
+ {
2776
+ found = 0;
2777
+ break;
2778
+ }
2779
+ psig = next_sig(psig);
2780
+ }
2781
+ if (found) break;
2782
+ }
2783
+ }
2784
+ }
2785
+ if (!found)
2786
+ {
2787
+ const char* tname = rb_id2name(orgpm->name);
2788
+ if (sig)
2789
+ {
2790
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s(\'%s\')'", tname, sig);
2791
+ }
2792
+ else
2793
+ {
2794
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname);
2795
+ }
2796
+ }
2797
+ args = (argc) ? ALLOCA_N(jvalue, argc) : NULL;
2798
+ psig = pm->basic.method_signature;
2799
+ for (i = 0; i < argc; i++)
2800
+ {
2801
+ R2J pr2j = *(pm->basic.arg_convert + i);
2802
+ pr2j(jenv, argv[i], args + i, psig, 0);
2803
+ psig = next_sig(psig);
2804
+ }
2805
+ switch (pm->basic.result_signature)
2806
+ {
2807
+ case 'D':
2808
+ {
2809
+ INVOKEAD voked = *(INVOKEAD*)(((char*)*jenv) + pm->method);
2810
+ jv.d = voked(jenv, ptr->obj, pm->basic.id, args);
2811
+ }
2812
+ break;
2813
+ case 'Z':
2814
+ case 'B':
2815
+ {
2816
+ INVOKEAZ vokez = *(INVOKEAZ*)(((char*)*jenv) + pm->method);
2817
+ jv.z = vokez(jenv, ptr->obj, pm->basic.id, args);
2818
+ }
2819
+ break;
2820
+ case 'F':
2821
+ {
2822
+ INVOKEAF vokef = *(INVOKEAF*)(((char*)*jenv) + pm->method);
2823
+ jv.f = vokef(jenv, ptr->obj, pm->basic.id, args);
2824
+ }
2825
+ break;
2826
+ case 'C':
2827
+ case 'S':
2828
+ {
2829
+ INVOKEAS vokes = *(INVOKEAS*)(((char*)*jenv) + pm->method);
2830
+ jv.s = vokes(jenv, ptr->obj, pm->basic.id, args);
2831
+ }
2832
+ break;
2833
+ #if HAVE_LONG_LONG
2834
+ case 'J':
2835
+ {
2836
+ INVOKEAL vokel = *(INVOKEAL*)(((char*)*jenv) + pm->method);
2837
+ jv.j = vokel(jenv, ptr->obj, pm->basic.id, args);
2838
+ }
2839
+ break;
2840
+ #endif
2841
+ default:
2842
+ {
2843
+ INVOKEA voke = *(INVOKEA*)(((char*)*jenv) + pm->method);
2844
+ jv.l = voke(jenv, ptr->obj, pm->basic.id, args);
2845
+ }
2846
+ break;
2847
+ }
2848
+ rjb_check_exception(jenv, 1);
2849
+ psig = pm->basic.method_signature;
2850
+ for (i = 0; i < argc; i++)
2851
+ {
2852
+ R2J pr2j = *(pm->basic.arg_convert + i);
2853
+ pr2j(jenv, argv[i], args + i, psig, 1);
2854
+ psig = next_sig(psig);
2855
+ }
2856
+ if (pm->basic.result_arraydepth)
2857
+ {
2858
+ return ja2r(pm->result_convert, jenv, jv, pm->basic.result_arraydepth);
2859
+ }
2860
+ else
2861
+ {
2862
+ return pm->result_convert(jenv, jv);
2863
+ }
2864
+ }
2865
+
2866
+ /*
2867
+ * Object invocation
2868
+ */
2869
+ static VALUE invoke_by_instance(ID rmid, int argc, VALUE* argv,
2870
+ struct jvi_data* ptr, char* sig)
2871
+ {
2872
+ VALUE ret = Qnil;
2873
+ JNIEnv* jenv = rjb_attach_current_thread();
2874
+ struct cls_field* pf;
2875
+ struct cls_method* pm;
2876
+ const char* tname = rb_id2name(rmid);
2877
+
2878
+ if (argc == 0 && st_lookup(ptr->fields, rmid, (st_data_t*)&pf))
2879
+ {
2880
+ ret = getter(jenv, pf, ptr);
2881
+ }
2882
+ else
2883
+ {
2884
+ if (argc == 1 && *(tname + strlen(tname) - 1) == '=')
2885
+ {
2886
+ char* fname = ALLOCA_N(char, strlen(tname) + 1);
2887
+ strcpy(fname, tname);
2888
+ fname[strlen(tname) - 1] = '\0';
2889
+ if (st_lookup(ptr->fields, rb_intern(fname), (st_data_t*)&pf))
2890
+ {
2891
+ setter(jenv, pf, ptr, *argv);
2892
+ return ret;
2893
+ }
2894
+ /* fall through for the setter alias name */
2895
+ }
2896
+ if (st_lookup(ptr->methods, rmid, (st_data_t*)&pm))
2897
+ {
2898
+ ret = invoke(jenv, pm, ptr, argc, argv, sig);
2899
+ }
2900
+ else
2901
+ {
2902
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname);
2903
+ }
2904
+ }
2905
+ return ret;
2906
+ }
2907
+
2908
+ static VALUE rjb_i_invoke(int argc, VALUE* argv, VALUE self)
2909
+ {
2910
+ VALUE vsig, rmid, rest;
2911
+ char* sig;
2912
+ struct jvi_data* ptr;
2913
+
2914
+ rb_scan_args(argc, argv, "2*", &rmid, &vsig, &rest);
2915
+ rmid = rb_to_id(rmid);
2916
+ sig = StringValueCStr(vsig);
2917
+ Data_Get_Struct(self, struct jvi_data, ptr);
2918
+
2919
+ return invoke_by_instance(rmid, argc -2, argv + 2, ptr, sig);
2920
+ }
2921
+
2922
+ static VALUE rjb_i_missing(int argc, VALUE* argv, VALUE self)
2923
+ {
2924
+ struct jvi_data* ptr;
2925
+ ID rmid = rb_to_id(argv[0]);
2926
+
2927
+ Data_Get_Struct(self, struct jvi_data, ptr);
2928
+
2929
+ return invoke_by_instance(rmid, argc -1, argv + 1, ptr, NULL);
2930
+ }
2931
+
2932
+ /*
2933
+ * Class invocation (first static method, then instance method)
2934
+ */
2935
+ static VALUE invoke_by_class(ID rmid, int argc, VALUE* argv,
2936
+ struct jv_data* ptr, char* sig)
2937
+ {
2938
+ VALUE ret = Qnil;
2939
+ struct jv_data* clsptr;
2940
+ struct cls_field* pf;
2941
+ struct cls_method* pm;
2942
+ const char* tname = rb_id2name(rmid);
2943
+ JNIEnv* jenv = rjb_attach_current_thread();
2944
+
2945
+ Data_Get_Struct(jklass, struct jv_data, clsptr);
2946
+ if (argc == 0 && st_lookup(ptr->idata.fields, rmid, (st_data_t*)&pf))
2947
+ {
2948
+ if (!pf->static_field)
2949
+ {
2950
+ rb_raise(rb_eRuntimeError, "instance field `%s' for class", tname);
2951
+ }
2952
+ ret = getter(jenv, pf, &ptr->idata);
2953
+ }
2954
+ else if (argc == 1 && *(tname + strlen(tname) - 1) == '=')
2955
+ {
2956
+ char* fname = ALLOCA_N(char, strlen(tname) + 1);
2957
+ strcpy(fname, tname);
2958
+ fname[strlen(tname) - 1] = '\0';
2959
+ if (st_lookup(ptr->idata.fields, rb_intern(fname), (st_data_t*)&pf))
2960
+ {
2961
+ if (!pf->static_field)
2962
+ {
2963
+ rb_raise(rb_eRuntimeError, "instance field `%s' for class", fname);
2964
+ }
2965
+ setter(jenv, pf, &ptr->idata, *argv);
2966
+ }
2967
+ else
2968
+ {
2969
+ rb_raise(rb_eRuntimeError, "Fail: unknown field name `%s'", fname);
2970
+ }
2971
+ }
2972
+ else if (st_lookup(ptr->static_methods, rmid, (st_data_t*)&pm))
2973
+ {
2974
+ ret = invoke(jenv, pm, &ptr->idata, argc, argv, sig);
2975
+ }
2976
+ else if (st_lookup(clsptr->idata.methods, rmid, (st_data_t*)&pm))
2977
+ {
2978
+ ret = invoke(jenv, pm, &ptr->idata, argc, argv, sig);
2979
+ }
2980
+ else
2981
+ {
2982
+ if (st_lookup(ptr->idata.methods, rmid, (st_data_t*)&pm))
2983
+ {
2984
+ rb_raise(rb_eRuntimeError, "instance method `%s' for class", tname);
2985
+ }
2986
+ else
2987
+ {
2988
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname);
2989
+ }
2990
+ }
2991
+
2992
+ return ret;
2993
+ }
2994
+
2995
+ static VALUE rjb_invoke(int argc, VALUE* argv, VALUE self)
2996
+ {
2997
+ VALUE vsig, rmid, rest;
2998
+ char* sig;
2999
+ struct jv_data* ptr;
3000
+
3001
+ rb_scan_args(argc, argv, "2*", &rmid, &vsig, &rest);
3002
+ rmid = rb_to_id(rmid);
3003
+ sig = StringValueCStr(vsig);
3004
+ Data_Get_Struct(self, struct jv_data, ptr);
3005
+
3006
+ return invoke_by_class(rmid, argc - 2, argv + 2, ptr, sig);
3007
+ }
3008
+
3009
+ static VALUE find_const(VALUE pv)
3010
+ {
3011
+ VALUE* p = (VALUE*)pv;
3012
+ return rb_const_get(*p, (ID)*(p + 1));
3013
+ }
3014
+
3015
+ static VALUE rjb_missing(int argc, VALUE* argv, VALUE self)
3016
+ {
3017
+ struct jv_data* ptr;
3018
+ ID rmid = rb_to_id(argv[0]);
3019
+ const char* rmname = rb_id2name(rmid);
3020
+ if (isupper(*rmname))
3021
+ {
3022
+ VALUE r, args[2];
3023
+ int state = 0;
3024
+ args[0] = rb_obj_class(self);
3025
+ args[1] = rmid;
3026
+ r = rb_protect(find_const, (VALUE)args, &state);
3027
+ if (!state)
3028
+ {
3029
+ return r;
3030
+ }
3031
+ }
3032
+
3033
+ Data_Get_Struct(self, struct jv_data, ptr);
3034
+ return invoke_by_class(rmid, argc - 1, argv + 1, ptr, NULL);
3035
+ }
3036
+
3037
+ /*
3038
+ * Class#forName entry.
3039
+ */
3040
+ static VALUE rjb_class_forname(int argc, VALUE* argv, VALUE self)
3041
+ {
3042
+ if (argc == 1)
3043
+ {
3044
+ return rjb_s_import(self, *argv);
3045
+ }
3046
+ else
3047
+ {
3048
+ struct jv_data* ptr;
3049
+ ID rmid = rb_intern("forName");
3050
+ Data_Get_Struct(self, struct jv_data, ptr);
3051
+ return invoke_by_class(rmid, argc, argv, ptr, NULL);
3052
+ }
3053
+ }
3054
+
3055
+ /*
3056
+ * Class initializer called by Ruby while requiring this library
3057
+ */
3058
+ void Init_rjbcore()
3059
+ {
3060
+ #if defined(RUBINIUS)
3061
+ rb_require("iconv");
3062
+ #else
3063
+ rb_protect((VALUE(*)(VALUE))rb_require, (VALUE)"iconv", NULL);
3064
+ #endif
3065
+ rjb_loaded_classes = rb_hash_new();
3066
+ #ifndef RUBINIUS
3067
+ OBJ_FREEZE(rjb_loaded_classes);
3068
+ #endif
3069
+ rb_global_variable(&rjb_loaded_classes);
3070
+ proxies = rb_ary_new();
3071
+ rb_global_variable(&proxies);
3072
+ user_initialize = rb_intern(USER_INITIALIZE);
3073
+
3074
+ rjb = rb_define_module("Rjb");
3075
+ rb_define_module_function(rjb, "load", rjb_s_load, -1);
3076
+ rb_define_module_function(rjb, "unload", rjb_s_unload, -1);
3077
+ rb_define_module_function(rjb, "loaded?", rjb_s_loaded, 0);
3078
+ rb_define_module_function(rjb, "import", rjb_s_import, 1);
3079
+ rb_define_module_function(rjb, "bind", rjb_s_bind, 2);
3080
+ rb_define_module_function(rjb, "unbind", rjb_s_unbind, 1);
3081
+ rb_define_module_function(rjb, "classes", rjb_s_classes, 0);
3082
+ rb_define_module_function(rjb, "throw", rjb_s_throw, -1);
3083
+ rb_define_module_function(rjb, "primitive_conversion=", rjb_s_set_pconversion, 1);
3084
+ rb_define_module_function(rjb, "primitive_conversion", rjb_s_get_pconversion, 0);
3085
+ rb_define_module_function(rjb, "add_classpath", rjb_s_add_classpath, 1);
3086
+ rb_define_module_function(rjb, "add_jar", rjb_s_add_jar, 1);
3087
+ rb_define_alias(rjb, "add_jars", "add_jar");
3088
+ rb_define_const(rjb, "VERSION", rb_str_new2(RJB_VERSION));
3089
+ rb_define_class_variable(rjb, "@@classpath", rb_ary_new());
3090
+ cvar_classpath = rb_intern("@@classpath");
3091
+
3092
+ /* Java class object */
3093
+ rjbc = CLASS_NEW(rb_cObject, "Rjb_JavaClass");
3094
+ rb_gc_register_address(&rjbc);
3095
+ rb_define_method(rjbc, "method_missing", rjb_missing, -1);
3096
+ rb_define_method(rjbc, "_invoke", rjb_invoke, -1);
3097
+ rb_define_method(rjbc, "_classname", rjb_i_class, 0);
3098
+
3099
+ /* Java instance object */
3100
+ rjbi = CLASS_NEW(rb_cObject, "Rjb_JavaProxy");
3101
+ rb_gc_register_address(&rjbi);
3102
+ rb_define_method(rjbi, "method_missing", rjb_i_missing, -1);
3103
+ rb_define_method(rjbi, "_invoke", rjb_i_invoke, -1);
3104
+ rb_define_method(rjbi, "_classname", rjb_i_class, 0);
3105
+ rb_define_method(rjbi, "_prepare_proxy", rjb_i_prepare_proxy, 0);
3106
+ rb_define_alias(rjbi, "include", "extend");
3107
+
3108
+ /* Ruby-Java Bridge object */
3109
+ rjbb = CLASS_NEW(rb_cObject, "Rjb_JavaBridge");
3110
+ rb_gc_register_address(&rjbb);
3111
+ }
3112
+
3113
+ VALUE rjb_safe_funcall(VALUE args)
3114
+ {
3115
+ VALUE* argp = (VALUE*)args;
3116
+ return rb_funcall2(*argp, *(argp + 1), *(argp + 2), argp + 3);
3117
+ }
3118
+
3119
+ /**
3120
+ Entry point from JavaVM through java.reflect.Proxy
3121
+ */
3122
+ JNIEXPORT jobject JNICALL Java_jp_co_infoseek_hp_arton_rjb_RBridge_call
3123
+ (JNIEnv * jenv, jobject bridge, jstring name, jobject proxy, jobjectArray args)
3124
+ {
3125
+ int i;
3126
+ jvalue j;
3127
+ memset(&j, 0, sizeof(j));
3128
+
3129
+ for (i = 0; i < RARRAY_LEN(proxies); i++)
3130
+ {
3131
+ struct rj_bridge* ptr;
3132
+ VALUE val = RARRAY_PTR(proxies)[i];
3133
+ Data_Get_Struct(val, struct rj_bridge, ptr);
3134
+ if ((*jenv)->IsSameObject(jenv, proxy, ptr->proxy))
3135
+ {
3136
+ int sstat;
3137
+ VALUE result;
3138
+ VALUE* argv = NULL;
3139
+ int argc = 3;
3140
+ ID id = rb_to_id(jstring2val(jenv, name));
3141
+ if (args)
3142
+ {
3143
+ int i;
3144
+ jsize js = (*jenv)->GetArrayLength(jenv, args);
3145
+ argc += (int)js;
3146
+ argv = ALLOCA_N(VALUE, argc);
3147
+ memset(argv, 0, sizeof(VALUE*) * argc);
3148
+ for (i = 3; i < argc; i++)
3149
+ {
3150
+ jobject f = (*jenv)->GetObjectArrayElement(jenv, args, i - 3);
3151
+ /* f will be release in jv2rv_withprim */
3152
+ *(argv + i) = jv2rv_withprim(jenv, f);
3153
+ }
3154
+ }
3155
+ else
3156
+ {
3157
+ argv = ALLOCA_N(VALUE, argc + 1);
3158
+ memset(argv, 0, sizeof(VALUE*) * (argc + 1));
3159
+ }
3160
+ *argv = ptr->wrapped;
3161
+ *(argv + 1) = id;
3162
+ *(argv + 2) = argc - 3;
3163
+ result = rb_protect(rjb_safe_funcall, (VALUE)argv, &sstat);
3164
+ rv2jobject(jenv, result, &j, NULL, 0);
3165
+ /* I can't delete this object... */
3166
+ break;
3167
+ }
3168
+ }
3169
+ return j.l;
3170
+ }