rjb 1.0.0-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,155 @@
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 2 2006-04-11 19:04:40Z arton $
16
+ */
17
+
18
+ #include "ruby.h"
19
+ #include "riconv.h"
20
+
21
+ static const char* cs_eucjp = "EUC-JP";
22
+ static const char* cs_sjis = "Shift_JIS";
23
+ static const char* cs_cp932 = "CP932";
24
+ static const char* cs_ms932 = "MS932";
25
+ static const char* cs_utf8 = "UTF-8";
26
+
27
+ /* Regexp::match�̃��b�p�[ */
28
+ static int regxp_is_match(VALUE str, VALUE regxp)
29
+ {
30
+ return rb_funcall(str, rb_intern("match"), 1, RREGEXP(regxp)) != Qnil ? 1 : 0 ;
31
+ }
32
+
33
+ /* RUBY_PLATFORM����ސ�����Windows�Ȃ�1���A�����łȂ����0��Ԃ� */
34
+ static int platform_is_windows()
35
+ {
36
+ VALUE platform = rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM"));
37
+ return regxp_is_match(platform, rb_str_new2("msvcrt|mswin|bccwin|mingw|cygwin"))
38
+ ? 1
39
+ : 0;
40
+ }
41
+
42
+ /*
43
+ * RUBY_PLATFORM��$KCODE������Iconv�ŗL���ȓK���ȕ����R�[�h����Ԃ�
44
+ * TODO: ���s�‹���LOCALE,LANG,LC_ALL�����Q�l�ɂ���
45
+ */
46
+ static char* get_charset_name()
47
+ {
48
+ char* result = NULL;
49
+ ID id_Iconv = rb_intern("Iconv");
50
+
51
+ if (rb_const_defined(rb_cObject, id_Iconv))
52
+ {
53
+ VALUE kcode = rb_gv_get("$KCODE");
54
+ VALUE platform = rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM"));
55
+ char* kcodep = (TYPE(kcode) == T_STRING) ? StringValuePtr(kcode) : "";
56
+
57
+ switch(toupper(*kcodep))
58
+ {
59
+ case 'E':
60
+ result = (char*)cs_eucjp;
61
+ break;
62
+ case 'S':
63
+ if (platform_is_windows())
64
+ {
65
+ result = (char*)cs_cp932;
66
+ }
67
+ else
68
+ {
69
+ result = (char*)cs_sjis;
70
+ }
71
+ break;
72
+ case 'N':
73
+ if (platform_is_windows())
74
+ {
75
+ result = (char*)cs_cp932;
76
+ }
77
+ else
78
+ {
79
+ result = NULL;
80
+ }
81
+ break;
82
+ case 'U':
83
+ default:
84
+ result = NULL;
85
+ break;
86
+ }
87
+ }else{
88
+ result = NULL;
89
+ }
90
+ return result;
91
+ }
92
+
93
+ /*
94
+ * �g�����C�u������Iconv������ꍇ��1,�Ȃ��ꍇ��0��Ԃ�
95
+ */
96
+ static int has_exticonv()
97
+ {
98
+ ID id_Iconv = rb_intern("Iconv");
99
+ VALUE Iconv = rb_const_get(rb_cObject, id_Iconv);
100
+ if(Iconv == Qnil)
101
+ {
102
+ return 0;
103
+ }
104
+ else
105
+ {
106
+ return 1;
107
+ }
108
+ }
109
+
110
+ VALUE exticonv_local_to_utf8(VALUE local_string)
111
+ {
112
+ char* cs = get_charset_name();
113
+ if(cs)
114
+ {
115
+ return exticonv_cc(local_string, cs, cs_utf8);
116
+ }
117
+ else
118
+ {
119
+ return local_string;
120
+ }
121
+ }
122
+
123
+ VALUE exticonv_utf8_to_local(VALUE utf8_string)
124
+ {
125
+ char* cs = get_charset_name();
126
+ if(cs)
127
+ {
128
+ return exticonv_cc(utf8_string, cs_utf8, cs);
129
+ }
130
+ else
131
+ {
132
+ return utf8_string;
133
+ }
134
+ }
135
+
136
+ VALUE exticonv_cc(VALUE original_string, const char* from, const char* to)
137
+ {
138
+ return exticonv_vv(original_string, rb_str_new2(from), rb_str_new2(to));
139
+ }
140
+
141
+ VALUE exticonv_vv(VALUE original_string, VALUE from, VALUE to)
142
+ {
143
+ if(has_exticonv())
144
+ {
145
+ ID id_Iconv = rb_intern("Iconv");
146
+ ID id_iconv = rb_intern("iconv");
147
+ VALUE Iconv = rb_const_get(rb_cObject, id_Iconv);
148
+ return rb_ary_entry(rb_funcall(Iconv, id_iconv, 3, to, from, original_string), 0);
149
+ }
150
+ else
151
+ {
152
+ //iconv���Ȃ���΂��̂܂ܕԂ�
153
+ return original_string;
154
+ }
155
+ }
@@ -0,0 +1,25 @@
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 2 2006-04-11 19:04:40Z arton $
16
+ */
17
+ #ifndef _RICONV_H
18
+ #define _RICONV_H
19
+
20
+ extern VALUE exticonv_local_to_utf8(VALUE);
21
+ extern VALUE exticonv_utf8_to_local(VALUE);
22
+ extern VALUE exticonv_cc(VALUE, const char*, const char*);
23
+ extern VALUE exticonv_vv(VALUE, VALUE, VALUE);
24
+
25
+ #endif /* _RICONV_H */
@@ -0,0 +1,2651 @@
1
+ /*
2
+ * Rjb - Ruby <-> Java Bridge
3
+ * Copyright(c) 2004,2005,2006 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 15 2006-08-01 13:52:36Z arton $
16
+ */
17
+
18
+ #define RJB_VERSION "1.0.0"
19
+
20
+ #include "ruby.h"
21
+ #include "st.h"
22
+ #include "jniwrap.h"
23
+ #include "jp_co_infoseek_hp_arton_rjb_RBridge.h"
24
+ #include "riconv.h"
25
+ #include "rjb.h"
26
+
27
+ /*
28
+ * Method Modifier Flag defined in
29
+ * http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88358
30
+ */
31
+ #define ACC_PUBLIC 0x0001
32
+ #define ACC_PRIVATE 0x0002
33
+ #define ACC_PROTECTED 0x0004
34
+ #define ACC_STATIC 0x0008
35
+ #define ACC_FINAL 0x0010
36
+ #define ACC_VOLATILE 0x0040
37
+ #define ACC_TRANSIENT 0x0080
38
+
39
+ extern int create_jvm(JNIEnv** pjenv, JavaVMInitArgs*, char*, VALUE);
40
+ static void register_class(VALUE, VALUE);
41
+ static VALUE import_class(JNIEnv* jenv, jclass, VALUE);
42
+ static VALUE register_instance(JNIEnv* jenv, struct jvi_data*, jobject);
43
+ static VALUE rjb_s_free(struct jv_data*);
44
+ static VALUE rjb_class_forname(int argc, VALUE* argv, VALUE self);
45
+ static void setup_metadata(JNIEnv* jenv, VALUE self, struct jv_data*, VALUE classname);
46
+ static jarray r2objarray(JNIEnv* jenv, VALUE v, const char* cls);
47
+
48
+ static VALUE rjb;
49
+ static VALUE jklass;
50
+ VALUE rjbc;
51
+ VALUE rjbi;
52
+ VALUE rjbb;
53
+
54
+ VALUE loaded_classes;
55
+ static VALUE proxies;
56
+ JavaVM* jvm;
57
+ JNIEnv* main_jenv;
58
+ jclass rbridge;
59
+ jmethodID register_bridge;
60
+
61
+ /*
62
+ * Object cache, never destroyed
63
+ */
64
+ /* method */
65
+ static jmethodID method_getModifiers;
66
+ static jmethodID method_getName;
67
+ static jmethodID getParameterTypes;
68
+ static jmethodID getReturnType;
69
+ /* field */
70
+ static jmethodID field_getModifiers;
71
+ static jmethodID field_getName;
72
+ static jmethodID field_getType;
73
+ /* constructor */
74
+ static jmethodID ctrGetParameterTypes;
75
+ /* class */
76
+ jclass j_class;
77
+ jmethodID class_getName;
78
+ /* throwable */
79
+ jclass j_throwable;
80
+ jmethodID throwable_getMessage;
81
+ /* String global reference */
82
+ static jclass j_string;
83
+ static jmethodID str_tostring;
84
+ /* Object global reference */
85
+ static jclass j_object;
86
+
87
+ enum PrimitiveType {
88
+ PRM_INT = 0,
89
+ PRM_LONG,
90
+ PRM_DOUBLE,
91
+ PRM_BOOLEAN,
92
+ PRM_CHARACTER,
93
+ PRM_SHORT,
94
+ PRM_BYTE,
95
+ PRM_FLOAT,
96
+ //
97
+ PRM_LAST
98
+ };
99
+
100
+ /*
101
+ * Native type conversion table
102
+ */
103
+ typedef struct jobject_ruby_table {
104
+ const char* classname;
105
+ const char* to_prim_method;
106
+ const char* prmsig;
107
+ const char* ctrsig;
108
+ jclass klass; /* primitive class */
109
+ jmethodID to_prim_id;
110
+ jmethodID ctr_id;
111
+ J2R func;
112
+ } jprimitive_table;
113
+
114
+ JNIEnv* attach_current_thread(void)
115
+ {
116
+ JNIEnv* env;
117
+ (*jvm)->AttachCurrentThread(jvm, (void**)&env, '\0');
118
+ return env;
119
+ }
120
+
121
+
122
+ void release_string(JNIEnv *jenv, jstring str, const char* chrs)
123
+ {
124
+ (*jenv)->ReleaseStringUTFChars(jenv, str, chrs);
125
+ (*jenv)->DeleteLocalRef(jenv, str);
126
+ }
127
+
128
+ static char* java2jniname(char* jnicls)
129
+ {
130
+ char* p;
131
+ for (p = jnicls; *p; p++)
132
+ {
133
+ if (*p == '.')
134
+ {
135
+ *p = '/';
136
+ }
137
+ }
138
+ return jnicls;
139
+ }
140
+
141
+ static char* jni2javaname(char* jnicls)
142
+ {
143
+ char* p;
144
+ for (p = jnicls; *p; p++)
145
+ {
146
+ if (*p == '/')
147
+ {
148
+ *p = '.';
149
+ }
150
+ }
151
+ return jnicls;
152
+ }
153
+
154
+ static char* next_sig(char* p)
155
+ {
156
+ if (!*p)
157
+ {
158
+ return p;
159
+ }
160
+ if (*p == '[')
161
+ {
162
+ p++;
163
+ }
164
+ if (*p == 'L')
165
+ {
166
+ while (*p && *p != ';')
167
+ {
168
+ p++;
169
+ }
170
+ }
171
+ return (*p) ? ++p : p;
172
+ }
173
+
174
+ static VALUE jstring2val(JNIEnv* jenv, jstring s)
175
+ {
176
+ const char* p;
177
+ VALUE v;
178
+
179
+ if (s == NULL)
180
+ {
181
+ return Qnil;
182
+ }
183
+ p = (*jenv)->GetStringUTFChars(jenv, s, NULL);
184
+ v = rb_str_new2(p);
185
+ v = exticonv_utf8_to_local(v);
186
+ release_string(jenv, s, p);
187
+ return v;
188
+ }
189
+
190
+ /*
191
+ * Type conversion tables
192
+ */
193
+ typedef struct type_conversion_table {
194
+ const char* jtype;
195
+ const char* jntype;
196
+ R2J r2j;
197
+ J2R j2r;
198
+ J2R ja2r;
199
+ R2JARRAY r2ja;
200
+ off_t jcall; /* for instance method */
201
+ off_t jscall; /* for static method */
202
+ } jconv_table;
203
+
204
+ /*
205
+ * conversion methods
206
+ * val will be released in this function.
207
+ */
208
+ static VALUE jv2rclass(JNIEnv* jenv, jclass jc)
209
+ {
210
+ const char* cname;
211
+ VALUE clsname;
212
+ VALUE v;
213
+ jstring nm = (*jenv)->CallObjectMethod(jenv, jc, class_getName);
214
+ check_exception(jenv, 0);
215
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
216
+ clsname = rb_str_new2(cname);
217
+ release_string(jenv, nm, cname);
218
+ v = rb_hash_aref(loaded_classes, clsname);
219
+ if (v == Qnil)
220
+ {
221
+ v = import_class(jenv, jc, clsname);
222
+ }
223
+ (*jenv)->DeleteLocalRef(jenv, jc);
224
+ return v;
225
+ }
226
+
227
+ static VALUE jv2rv(JNIEnv* jenv, jvalue val)
228
+ {
229
+ const char* cname;
230
+ jstring nm;
231
+ jclass klass;
232
+ VALUE clsname;
233
+ VALUE v;
234
+ struct jv_data* ptr;
235
+ // object to ruby
236
+ if (!val.l) return Qnil;
237
+ klass = (*jenv)->GetObjectClass(jenv, val.l);
238
+ if ((*jenv)->IsSameObject(jenv, klass, j_class))
239
+ {
240
+ (*jenv)->DeleteLocalRef(jenv, klass);
241
+ return jv2rclass(jenv, val.l);
242
+ }
243
+ nm = (*jenv)->CallObjectMethod(jenv, klass, class_getName);
244
+ check_exception(jenv, 0);
245
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
246
+ clsname = rb_str_new2(cname);
247
+ release_string(jenv, nm, cname);
248
+ v = rb_hash_aref(loaded_classes, clsname);
249
+ if (v == Qnil)
250
+ {
251
+ v = import_class(jenv, klass, clsname);
252
+ }
253
+ Data_Get_Struct(v, struct jv_data, ptr);
254
+ v = register_instance(jenv, (struct jvi_data*)ptr, val.l);
255
+ (*jenv)->DeleteLocalRef(jenv, klass);
256
+ (*jenv)->DeleteLocalRef(jenv, val.l);
257
+ return v;
258
+ }
259
+
260
+ static VALUE jvoid2rv(JNIEnv* jenv, jvalue val)
261
+ {
262
+ return Qnil;
263
+ }
264
+
265
+ static VALUE jbyte2rv(JNIEnv* jenv, jvalue val)
266
+ {
267
+ return INT2NUM(val.b);
268
+ }
269
+
270
+ static VALUE jchar2rv(JNIEnv* jenv, jvalue val)
271
+ {
272
+ return INT2NUM(val.c);
273
+ }
274
+
275
+ static VALUE jdouble2rv(JNIEnv* jenv, jvalue val)
276
+ {
277
+ return rb_float_new(val.d);
278
+ }
279
+
280
+ static VALUE jfloat2rv(JNIEnv* jenv, jvalue val)
281
+ {
282
+ return rb_float_new((double)val.f);
283
+ }
284
+
285
+ static VALUE jint2rv(JNIEnv* jenv, jvalue val)
286
+ {
287
+ return INT2NUM(val.i);
288
+ }
289
+
290
+ static VALUE jlong2rv(JNIEnv* jenv, jvalue val)
291
+ {
292
+ #if HAVE_LONG_LONG
293
+ return LL2NUM(val.j);
294
+ #else
295
+ char bignum[64];
296
+ sprintf(bignum, "%ld * 0x100000000 + 0x%lx",
297
+ (long)(val.j >> 32), (unsigned long)val.j);
298
+ return rb_eval_string(bignum);
299
+ #endif
300
+ }
301
+
302
+ static VALUE jshort2rv(JNIEnv* jenv, jvalue val)
303
+ {
304
+ return INT2NUM(val.s);
305
+ }
306
+
307
+ static VALUE jboolean2rv(JNIEnv* jenv, jvalue val)
308
+ {
309
+ return (val.z) ? Qtrue : Qfalse;
310
+ }
311
+
312
+ static VALUE jstring2rv(JNIEnv* jenv, jvalue val)
313
+ {
314
+ return jstring2val(jenv, (jstring)val.l);
315
+ }
316
+
317
+ static VALUE ja2r(J2R conv, JNIEnv* jenv, jvalue val, int depth)
318
+ {
319
+ jsize len;
320
+ VALUE v;
321
+ int i;
322
+ if (!val.l) return Qnil;
323
+ if (depth == 1)
324
+ {
325
+ return conv(jenv, val);
326
+ }
327
+ len = (*jenv)->GetArrayLength(jenv, val.l);
328
+ v = rb_ary_new2(len);
329
+ for (i = 0; i < len; i++)
330
+ {
331
+ jvalue wrap;
332
+ wrap.l = (*jenv)->GetObjectArrayElement(jenv, val.l, i);
333
+ rb_ary_push(v, ja2r(conv, jenv, wrap, depth - 1));
334
+ }
335
+ (*jenv)->DeleteLocalRef(jenv, val.l);
336
+ return v;
337
+ }
338
+
339
+ static VALUE jarray2rv(JNIEnv* jenv, jvalue val)
340
+ {
341
+ jsize len;
342
+ VALUE v;
343
+ int i;
344
+ if (!val.l) return Qnil;
345
+ len = (*jenv)->GetArrayLength(jenv, val.l);
346
+ v = rb_ary_new2(len);
347
+ for (i = 0; i < len; i++)
348
+ {
349
+ jvalue wrap;
350
+ wrap.l = (*jenv)->GetObjectArrayElement(jenv, val.l, i);
351
+ /* wrap.l will be release in jv2rv */
352
+ rb_ary_push(v, jv2rv(jenv, wrap));
353
+ }
354
+ (*jenv)->DeleteLocalRef(jenv, val.l);
355
+ return v;
356
+ }
357
+
358
+ static VALUE ca2rv(JNIEnv* jenv, void* p)
359
+ {
360
+ return INT2FIX(*(jchar*)p);
361
+ }
362
+
363
+ static VALUE da2rv(JNIEnv* jenv, void* p)
364
+ {
365
+ return rb_float_new(*(jdouble*)p);
366
+ }
367
+
368
+ static VALUE fa2rv(JNIEnv* jenv, void* p)
369
+ {
370
+ return rb_float_new(*(jfloat*)p);
371
+ }
372
+
373
+ static VALUE ia2rv(JNIEnv* jenv, void* p)
374
+ {
375
+ return INT2NUM(*(jint*)p);
376
+ }
377
+
378
+ static VALUE la2rv(JNIEnv* jenv, void* p)
379
+ {
380
+ #if HAVE_LONG_LONG
381
+ return LL2NUM(*(jlong*)p);
382
+ #else
383
+ return LONG2NUM(*(jlong*)p);
384
+ #endif
385
+ }
386
+
387
+ static VALUE sa2rv(JNIEnv* jenv, void* p)
388
+ {
389
+ return INT2FIX(*(jshort*)p);
390
+ }
391
+
392
+ static VALUE ba2rv(JNIEnv* jenv, void* p)
393
+ {
394
+ return (*(jboolean*)p) ? Qtrue : Qfalse;
395
+ }
396
+
397
+ /*
398
+ * val : released in this function.
399
+ */
400
+ static VALUE call_conv(JNIEnv* jenv, jvalue val, size_t sz, void* p, CONV conv, size_t fnc)
401
+ {
402
+ int i;
403
+ char* cp = (char*)p;
404
+ jsize len = (*jenv)->GetArrayLength(jenv, val.l);
405
+ VALUE v = rb_ary_new2(len);
406
+ VALUE* pv = RARRAY(v)->ptr;
407
+ RARRAY(v)->len = len;
408
+ for (i = 0; i < len; i++)
409
+ {
410
+ *pv++ =conv(jenv, cp);
411
+ cp += sz;
412
+ }
413
+ (*(RELEASEARRAY*)(((char*)*jenv) + fnc))(jenv, val.l, p, JNI_ABORT);
414
+ (*jenv)->DeleteLocalRef(jenv, val.l);
415
+ return v;
416
+ }
417
+
418
+ static VALUE jbytearray2rv(JNIEnv* jenv, jvalue val)
419
+ {
420
+ jsize len = (*jenv)->GetArrayLength(jenv, val.l);
421
+ jbyte* p = (*jenv)->GetByteArrayElements(jenv, val.l, NULL);
422
+ VALUE v = rb_str_new((char*)p, len);
423
+ (*jenv)->ReleaseByteArrayElements(jenv, val.l, p, JNI_ABORT);
424
+ (*jenv)->DeleteLocalRef(jenv, val.l);
425
+ return v;
426
+ }
427
+ static VALUE jchararray2rv(JNIEnv* jenv, jvalue val)
428
+ {
429
+ jchar* p = (*jenv)->GetCharArrayElements(jenv, val.l, NULL);
430
+ return call_conv(jenv, val, sizeof(jchar), p, ca2rv,
431
+ offsetof(struct JNINativeInterface_, ReleaseCharArrayElements));
432
+ }
433
+ static VALUE jdoublearray2rv(JNIEnv* jenv, jvalue val)
434
+ {
435
+ jdouble* p = (*jenv)->GetDoubleArrayElements(jenv, val.l, NULL);
436
+ return call_conv(jenv, val, sizeof(jdouble), p, da2rv,
437
+ offsetof(struct JNINativeInterface_, ReleaseDoubleArrayElements));
438
+ }
439
+ static VALUE jfloatarray2rv(JNIEnv* jenv, jvalue val)
440
+ {
441
+ jfloat* p = (*jenv)->GetFloatArrayElements(jenv, val.l, NULL);
442
+ return call_conv(jenv, val, sizeof(jfloat), p, fa2rv,
443
+ offsetof(struct JNINativeInterface_, ReleaseFloatArrayElements));
444
+ }
445
+ static VALUE jintarray2rv(JNIEnv* jenv, jvalue val)
446
+ {
447
+ jint* p = (*jenv)->GetIntArrayElements(jenv, val.l, NULL);
448
+ return call_conv(jenv, val, sizeof(jint), p, ia2rv,
449
+ offsetof(struct JNINativeInterface_, ReleaseIntArrayElements));
450
+ }
451
+ static VALUE jlongarray2rv(JNIEnv* jenv, jvalue val)
452
+ {
453
+ jlong* p = (*jenv)->GetLongArrayElements(jenv, val.l, NULL);
454
+ return call_conv(jenv, val, sizeof(jlong), p, la2rv,
455
+ offsetof(struct JNINativeInterface_, ReleaseLongArrayElements));
456
+ }
457
+ static VALUE jshortarray2rv(JNIEnv* jenv, jvalue val)
458
+ {
459
+ jshort* p = (*jenv)->GetShortArrayElements(jenv, val.l, NULL);
460
+ return call_conv(jenv, val, sizeof(jshort), p, sa2rv,
461
+ offsetof(struct JNINativeInterface_, ReleaseShortArrayElements));
462
+ }
463
+ static VALUE jstringarray2rv(JNIEnv* jenv, jvalue val)
464
+ {
465
+ int i;
466
+ jsize len = (*jenv)->GetArrayLength(jenv, val.l);
467
+ VALUE v = rb_ary_new2(len);
468
+ for (i = 0; i < len; i++)
469
+ {
470
+ jobject p = (*jenv)->GetObjectArrayElement(jenv, val.l, i);
471
+ rb_ary_push(v, jstring2val(jenv, (jstring)p));
472
+ }
473
+ (*jenv)->DeleteLocalRef(jenv, val.l);
474
+ return v;
475
+ }
476
+ static VALUE jbooleanarray2rv(JNIEnv* jenv, jvalue val)
477
+ {
478
+ jboolean* p = (*jenv)->GetBooleanArrayElements(jenv, val.l, NULL);
479
+ return call_conv(jenv, val, sizeof(jboolean), p, ba2rv,
480
+ offsetof(struct JNINativeInterface_, ReleaseBooleanArrayElements));
481
+ }
482
+
483
+ /*
484
+ * table that handles java primitive type.
485
+ * index: according to enum PrimitiveType.
486
+ */
487
+ static jprimitive_table jpcvt[] = {
488
+ { "java/lang/Integer", "intValue", "()I", "(I)V", NULL, 0, 0, jint2rv, },
489
+ { "java/lang/Long", "longValue", "()J", "(J)V", NULL, 0, 0, jlong2rv, },
490
+ { "java/lang/Double", "doubleValue", "()D", "(D)V", NULL, 0, 0, jdouble2rv, },
491
+ { "java/lang/Boolean", "booleanValue", "()Z", "(Z)Ljava/lang/Boolean;",
492
+ NULL, 0, 0, jboolean2rv, },
493
+ { "java/lang/Character", "charValue", "()C", NULL, NULL, 0, 0, jint2rv, },
494
+ { "java/lang/Short", "intValue", "()I", NULL, NULL, 0, 0, jint2rv, },
495
+ { "java/lang/Byte", "intValue", "()I", NULL, NULL, 0, 0, jint2rv, },
496
+ { "java/lang/Float", "doubleValue", "()D", NULL, NULL, 0, 0, jdouble2rv, },
497
+ };
498
+
499
+ /*
500
+ * o will be released in this function.
501
+ */
502
+ static VALUE jv2rv_withprim(JNIEnv* jenv, jobject o)
503
+ {
504
+ jvalue jv;
505
+ int i;
506
+ jclass klass = (*jenv)->GetObjectClass(jenv, o);
507
+ for (i = PRM_INT; i < PRM_LAST; i++)
508
+ {
509
+ if ((*jenv)->IsSameObject(jenv, jpcvt[i].klass, klass))
510
+ {
511
+ switch (*(jpcvt[i].to_prim_method))
512
+ {
513
+ case 'i':
514
+ jv.i = (*jenv)->CallIntMethod(jenv, o, jpcvt[i].to_prim_id);
515
+ break;
516
+ case 'b':
517
+ jv.z = (*jenv)->CallBooleanMethod(jenv, o, jpcvt[i].to_prim_id);
518
+ break;
519
+ case 'd':
520
+ jv.d = (*jenv)->CallDoubleMethod(jenv, o, jpcvt[i].to_prim_id);
521
+ break;
522
+ case 'c':
523
+ jv.c = (*jenv)->CallCharMethod(jenv, o, jpcvt[i].to_prim_id);
524
+ break;
525
+ default:
526
+ rb_raise(rb_eRuntimeError, "no convertor defined(%d)", i);
527
+ break;
528
+ }
529
+ return jpcvt[i].func(jenv, jv);
530
+ }
531
+ }
532
+ jv.l = o;
533
+ return jv2rv(jenv, jv);
534
+ }
535
+
536
+ /*
537
+ * functions convert VALUE to jvalue
538
+ */
539
+ static void rv2jv(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
540
+ {
541
+ jv->l = NULL;
542
+ }
543
+
544
+ static void rv2jbyte(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
545
+ {
546
+ if (!release)
547
+ jv->b = (jbyte)NUM2INT(val);
548
+ }
549
+ static void rv2jchar(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
550
+ {
551
+ if (!release)
552
+ jv->c = (jchar)NUM2INT(val);
553
+ }
554
+ static void rv2jdouble(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
555
+ {
556
+ if (release) return;
557
+ switch (TYPE(val))
558
+ {
559
+ case T_FIXNUM:
560
+ jv->d = NUM2INT(val);
561
+ break;
562
+ case T_FLOAT:
563
+ jv->d = NUM2DBL(val);
564
+ break;
565
+ default:
566
+ rb_raise(rb_eRuntimeError, "can't change to double");
567
+ break;
568
+ }
569
+ }
570
+ static void rv2jfloat(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
571
+ {
572
+ if (release) return;
573
+ switch (TYPE(val))
574
+ {
575
+ case T_FIXNUM:
576
+ jv->f = (float)NUM2INT(val);
577
+ break;
578
+ case T_FLOAT:
579
+ jv->f = (float)NUM2DBL(val);
580
+ break;
581
+ default:
582
+ rb_raise(rb_eRuntimeError, "can't change to float");
583
+ break;
584
+ }
585
+ }
586
+ static void rv2jint(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
587
+ {
588
+ if (!release)
589
+ jv->i = NUM2INT(val);
590
+ }
591
+ static void rv2jlong(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
592
+ {
593
+ if (release) return;
594
+ switch (TYPE(val))
595
+ {
596
+ case T_FIXNUM:
597
+ jv->j = NUM2INT(val);
598
+ break;
599
+ default:
600
+ #if HAVE_LONG_LONG
601
+ jv->j = NUM2LL(val);
602
+ #else
603
+ rb_raise(rb_eRuntimeError, "can't change to long");
604
+ #endif
605
+ break;
606
+ }
607
+ }
608
+ static void rv2jshort(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
609
+ {
610
+ if (!release)
611
+ jv->s = (short)NUM2INT(val);
612
+ }
613
+ static void rv2jboolean(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
614
+ {
615
+ if (!release)
616
+ jv->z = (val == Qnil || val == Qfalse) ? JNI_FALSE : JNI_TRUE;
617
+ }
618
+ static void rv2jstring(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
619
+ {
620
+ if (!release)
621
+ {
622
+ if (TYPE(val) == T_DATA
623
+ && (RBASIC(val)->klass == rjbi || RBASIC(val)->klass == rjb))
624
+ {
625
+ struct jvi_data* ptr;
626
+ Data_Get_Struct(val, struct jvi_data, ptr);
627
+ if ((*jenv)->IsInstanceOf(jenv, ptr->obj, j_string))
628
+ {
629
+ jv->l = ptr->obj;
630
+ }
631
+ else
632
+ {
633
+ jmethodID tostr;
634
+ jstring js;
635
+ tostr = (*jenv)->GetMethodID(jenv, ptr->klass, "toString", "()Ljava/lang/String;");
636
+ check_exception(jenv, 0);
637
+ js = (*jenv)->CallObjectMethod(jenv, ptr->obj, tostr);
638
+ check_exception(jenv, 0);
639
+ jv->l = js;
640
+ }
641
+ }
642
+ else
643
+ {
644
+ if (NIL_P(val))
645
+ {
646
+ jv->l = NULL;
647
+ }
648
+ else
649
+ {
650
+ val = exticonv_local_to_utf8(val);
651
+ jv->l = (*jenv)->NewStringUTF(jenv, StringValuePtr(val));
652
+ }
653
+ }
654
+ }
655
+ else
656
+ {
657
+ if (TYPE(val) == T_DATA)
658
+ {
659
+ if (RBASIC(val)->klass == rjbi || RBASIC(val)->klass == rjb)
660
+ {
661
+ struct jvi_data* ptr;
662
+ Data_Get_Struct(val, struct jvi_data, ptr);
663
+ if ((*jenv)->IsInstanceOf(jenv, ptr->obj, j_string))
664
+ {
665
+ return; // never delete at this time
666
+ }
667
+ }
668
+ }
669
+ (*jenv)->DeleteLocalRef(jenv, jv->l);
670
+ }
671
+ }
672
+
673
+ /*
674
+ * psig may be NULL (from proxy/array call)
675
+ */
676
+ static void rv2jobject(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
677
+ {
678
+ if (!release)
679
+ {
680
+ jv->l = NULL;
681
+ if (val == Qtrue || val == Qfalse)
682
+ {
683
+ jv->l = (*jenv)->CallStaticObjectMethod(jenv,
684
+ jpcvt[PRM_BOOLEAN].klass, jpcvt[PRM_BOOLEAN].ctr_id,
685
+ (val == Qtrue) ? JNI_TRUE : JNI_FALSE);
686
+ }
687
+ else if (NIL_P(val))
688
+ {
689
+ // no-op
690
+ }
691
+ else if (FIXNUM_P(val))
692
+ {
693
+ jvalue arg;
694
+ int idx = PRM_INT;
695
+ #if HAVE_LONG_LONG
696
+ arg.j = FIX2LONG(val);
697
+ if (arg.j < INT_MIN || arg.j > INT_MAX)
698
+ {
699
+ idx = PRM_LONG;
700
+ }
701
+ #else
702
+ arg.i = FIX2LONG(val);
703
+ #endif
704
+ jv->l = (*jenv)->NewObject(jenv, jpcvt[idx].klass,
705
+ jpcvt[idx].ctr_id, arg);
706
+ }
707
+ else
708
+ {
709
+ jvalue arg;
710
+ switch (TYPE(val))
711
+ {
712
+ case T_DATA:
713
+ if (RBASIC(val)->klass == rjbi || RBASIC(val)->klass == rjb)
714
+ {
715
+ // TODO: check instanceof (class (in psig) )
716
+ struct jvi_data* ptr;
717
+ Data_Get_Struct(val, struct jvi_data, ptr);
718
+ jv->l = ptr->obj;
719
+ }
720
+ else if (RBASIC(val)->klass == rjbb)
721
+ {
722
+ struct rj_bridge* ptr;
723
+ Data_Get_Struct(val, struct rj_bridge, ptr);
724
+ jv->l = ptr->proxy;
725
+ }
726
+ else if (rb_class_inherited(rjbc, RBASIC(val)->klass))
727
+ {
728
+ struct jv_data* ptr;
729
+ Data_Get_Struct(val, struct jv_data, ptr);
730
+ jv->l = ptr->idata.obj;
731
+ }
732
+ break;
733
+ case T_STRING:
734
+ rv2jstring(jenv, val, jv, NULL, 0);
735
+ break;
736
+ case T_FLOAT:
737
+ arg.d = NUM2DBL(val);
738
+ jv->l = (*jenv)->NewObject(jenv, jpcvt[PRM_DOUBLE].klass,
739
+ jpcvt[PRM_DOUBLE].ctr_id, arg);
740
+ break;
741
+ case T_ARRAY:
742
+ jv->l = r2objarray(jenv, val, "Ljava/lang/Object;");
743
+ break;
744
+ }
745
+ }
746
+ }
747
+ else
748
+ {
749
+ switch (TYPE(val))
750
+ {
751
+ case T_STRING:
752
+ case T_FLOAT:
753
+ case T_ARRAY:
754
+ (*jenv)->DeleteLocalRef(jenv, jv->l);
755
+ break;
756
+ }
757
+ }
758
+ }
759
+
760
+ static void check_fixnumarray(VALUE v)
761
+ {
762
+ int i;
763
+ int len = RARRAY(v)->len;
764
+ VALUE* p = RARRAY(v)->ptr;
765
+ // check all fixnum (overflow is permit)
766
+ for (i = 0; i < len; i++)
767
+ {
768
+ if (!FIXNUM_P(*p++))
769
+ {
770
+ rb_raise(rb_eRuntimeError, "array element must be a fixnum");
771
+ }
772
+ }
773
+ }
774
+
775
+ static jarray r2barray(JNIEnv* jenv, VALUE v, const char* cls)
776
+ {
777
+ jarray ary = NULL;
778
+ if (TYPE(v) == T_STRING)
779
+ {
780
+ ary = (*jenv)->NewByteArray(jenv, RSTRING(v)->len);
781
+ (*jenv)->SetByteArrayRegion(jenv, ary, 0, RSTRING(v)->len,
782
+ RSTRING(v)->ptr);
783
+ }
784
+ else if (TYPE(v) == T_ARRAY)
785
+ {
786
+ int i;
787
+ jbyte* pb;
788
+ check_fixnumarray(v);
789
+ ary = (*jenv)->NewByteArray(jenv, RARRAY(v)->len);
790
+ pb = (*jenv)->GetByteArrayElements(jenv, ary, NULL);
791
+ for (i = 0; i < RARRAY(v)->len; i++)
792
+ {
793
+ *(pb + i) = (jbyte)FIX2ULONG(RARRAY(v)->ptr[i]);
794
+ }
795
+ (*jenv)->ReleaseByteArrayElements(jenv, ary, pb, 0);
796
+ }
797
+ if (!ary)
798
+ {
799
+ rb_raise(rb_eRuntimeError, "can't coerce to byte array");
800
+ }
801
+ return ary;
802
+ }
803
+
804
+ static jarray r2carray(JNIEnv* jenv, VALUE v, const char* cls)
805
+ {
806
+ jarray ary = NULL;
807
+ if (TYPE(v) == T_ARRAY)
808
+ {
809
+ int i;
810
+ jchar* pb;
811
+ check_fixnumarray(v);
812
+ ary = (*jenv)->NewCharArray(jenv, RARRAY(v)->len);
813
+ pb = (*jenv)->GetCharArrayElements(jenv, ary, NULL);
814
+ for (i = 0; i < RARRAY(v)->len; i++)
815
+ {
816
+ *(pb + i) = (jchar)FIX2ULONG(RARRAY(v)->ptr[i]);
817
+ }
818
+ (*jenv)->ReleaseCharArrayElements(jenv, ary, pb, 0);
819
+ return ary;
820
+ }
821
+ rb_raise(rb_eRuntimeError, "can't coerce to char array");
822
+ }
823
+
824
+ static jarray r2darray(JNIEnv* jenv, VALUE v, const char* cls)
825
+ {
826
+ jarray ary = NULL;
827
+ if (TYPE(v) == T_ARRAY)
828
+ {
829
+ int i;
830
+ jdouble* pb;
831
+ ary = (*jenv)->NewDoubleArray(jenv, RARRAY(v)->len);
832
+ pb = (*jenv)->GetDoubleArrayElements(jenv, ary, NULL);
833
+ for (i = 0; i < RARRAY(v)->len; i++)
834
+ {
835
+ *(pb + i) = (jdouble)rb_num2dbl(RARRAY(v)->ptr[i]);
836
+ }
837
+ (*jenv)->ReleaseDoubleArrayElements(jenv, ary, pb, 0);
838
+ return ary;
839
+ }
840
+ rb_raise(rb_eRuntimeError, "can't coerce to double array");
841
+ }
842
+
843
+ static jarray r2farray(JNIEnv* jenv, VALUE v, const char* cls)
844
+ {
845
+ jarray ary = NULL;
846
+ if (TYPE(v) == T_ARRAY)
847
+ {
848
+ int i;
849
+ jfloat* pb;
850
+ ary = (*jenv)->NewFloatArray(jenv, RARRAY(v)->len);
851
+ pb = (*jenv)->GetFloatArrayElements(jenv, ary, NULL);
852
+ for (i = 0; i < RARRAY(v)->len; i++)
853
+ {
854
+ *(pb + i) = (jfloat)rb_num2dbl(RARRAY(v)->ptr[i]);
855
+ }
856
+ (*jenv)->ReleaseFloatArrayElements(jenv, ary, pb, 0);
857
+ return ary;
858
+ }
859
+ rb_raise(rb_eRuntimeError, "can't coerce to float array");
860
+ }
861
+
862
+ static jarray r2iarray(JNIEnv* jenv, VALUE v, const char* cls)
863
+ {
864
+ jarray ary = NULL;
865
+ if (TYPE(v) == T_ARRAY)
866
+ {
867
+ int i;
868
+ jint* pb;
869
+ check_fixnumarray(v);
870
+ ary = (*jenv)->NewIntArray(jenv, RARRAY(v)->len);
871
+ pb = (*jenv)->GetIntArrayElements(jenv, ary, NULL);
872
+ for (i = 0; i < RARRAY(v)->len; i++)
873
+ {
874
+ *(pb + i) = (jint)FIX2LONG(RARRAY(v)->ptr[i]);
875
+ }
876
+ (*jenv)->ReleaseIntArrayElements(jenv, ary, pb, 0);
877
+ return ary;
878
+ }
879
+ rb_raise(rb_eRuntimeError, "can't coerce to int array");
880
+ }
881
+
882
+ static jarray r2larray(JNIEnv* jenv, VALUE v, const char* cls)
883
+ {
884
+ jarray ary = NULL;
885
+ if (TYPE(v) == T_ARRAY)
886
+ {
887
+ int i;
888
+ jlong* pb;
889
+ ary = (*jenv)->NewLongArray(jenv, RARRAY(v)->len);
890
+ pb = (*jenv)->GetLongArrayElements(jenv, ary, NULL);
891
+ for (i = 0; i < RARRAY(v)->len; i++)
892
+ {
893
+ #if HAVE_LONG_LONG
894
+ *(pb + i) = (jlong)rb_num2ll(RARRAY(v)->ptr[i]);
895
+ #else
896
+ *(pb + i) = (jlong)FIX2LONG(RARRAY(v)->ptr[i]);
897
+ #endif
898
+ }
899
+ (*jenv)->ReleaseLongArrayElements(jenv, ary, pb, 0);
900
+ return ary;
901
+ }
902
+ rb_raise(rb_eRuntimeError, "can't coerce to long array");
903
+ }
904
+
905
+ static jarray r2sarray(JNIEnv* jenv, VALUE v, const char* cls)
906
+ {
907
+ jarray ary = NULL;
908
+ if (TYPE(v) == T_ARRAY)
909
+ {
910
+ int i;
911
+ jshort* pb;
912
+ check_fixnumarray(v);
913
+ ary = (*jenv)->NewShortArray(jenv, RARRAY(v)->len);
914
+ pb = (*jenv)->GetShortArrayElements(jenv, ary, NULL);
915
+ for (i = 0; i < RARRAY(v)->len; i++)
916
+ {
917
+ *(pb + i) = (jshort)FIX2LONG(RARRAY(v)->ptr[i]);
918
+ }
919
+ (*jenv)->ReleaseShortArrayElements(jenv, ary, pb, 0);
920
+ return ary;
921
+ }
922
+ rb_raise(rb_eRuntimeError, "can't coerce to short array");
923
+ }
924
+
925
+ static jarray r2boolarray(JNIEnv* jenv, VALUE v, const char* cls)
926
+ {
927
+ jarray ary = NULL;
928
+ if (TYPE(v) == T_ARRAY)
929
+ {
930
+ int i;
931
+ jboolean* pb;
932
+ ary = (*jenv)->NewBooleanArray(jenv, RARRAY(v)->len);
933
+ pb = (*jenv)->GetBooleanArrayElements(jenv, ary, NULL);
934
+ for (i = 0; i < RARRAY(v)->len; i++)
935
+ {
936
+ *(pb + i)
937
+ = (NIL_P(RARRAY(v)->ptr[i]) || RARRAY(v)->ptr[i] == Qfalse)
938
+ ? JNI_FALSE : JNI_TRUE;
939
+ }
940
+ (*jenv)->ReleaseBooleanArrayElements(jenv, ary, pb, 0);
941
+ return ary;
942
+ }
943
+ rb_raise(rb_eRuntimeError, "can't coerce to boolean array");
944
+ }
945
+
946
+ static jarray r2voidarray(JNIEnv* jenv, VALUE v, const char* cls)
947
+ {
948
+ rb_raise(rb_eRuntimeError, "void never arrayed");
949
+ }
950
+
951
+ static jarray r2objarray(JNIEnv* jenv, VALUE v, const char* cls)
952
+ {
953
+ jarray ary = NULL;
954
+ if (TYPE(v) == T_ARRAY)
955
+ {
956
+ int i;
957
+ ary = (*jenv)->NewObjectArray(jenv, RARRAY(v)->len, j_object, NULL);
958
+ check_exception(jenv, 0);
959
+ for (i = 0; i < RARRAY(v)->len; i++)
960
+ {
961
+ jvalue jv;
962
+ rv2jobject(jenv, RARRAY(v)->ptr[i], &jv, NULL, 0);
963
+ (*jenv)->SetObjectArrayElement(jenv, ary, i, jv.l);
964
+ }
965
+ return ary;
966
+ }
967
+ rb_raise(rb_eRuntimeError, "can't coerce to object array");
968
+ }
969
+
970
+ /*
971
+ * Type convertion tables
972
+ */
973
+ static const jconv_table jcvt[] = {
974
+ { "byte", "B", rv2jbyte, jbyte2rv,
975
+ jbytearray2rv, r2barray,
976
+ offsetof(struct JNINativeInterface_, CallByteMethodA),
977
+ offsetof(struct JNINativeInterface_, CallStaticByteMethodA), },
978
+ { "char", "C", rv2jchar, jchar2rv,
979
+ jchararray2rv, r2carray,
980
+ offsetof(struct JNINativeInterface_, CallCharMethodA),
981
+ offsetof(struct JNINativeInterface_, CallStaticCharMethodA), },
982
+ { "double", "D", rv2jdouble, jdouble2rv,
983
+ jdoublearray2rv, r2darray,
984
+ offsetof(struct JNINativeInterface_, CallDoubleMethodA),
985
+ offsetof(struct JNINativeInterface_, CallStaticDoubleMethodA), },
986
+ { "float", "F", rv2jfloat, jfloat2rv,
987
+ jfloatarray2rv, r2farray,
988
+ offsetof(struct JNINativeInterface_, CallFloatMethodA),
989
+ offsetof(struct JNINativeInterface_, CallStaticFloatMethodA), },
990
+ { "int", "I", rv2jint, jint2rv,
991
+ jintarray2rv, r2iarray,
992
+ offsetof(struct JNINativeInterface_, CallIntMethodA),
993
+ offsetof(struct JNINativeInterface_, CallStaticIntMethodA), },
994
+ { "long", "J", rv2jlong, jlong2rv,
995
+ jlongarray2rv, r2larray,
996
+ offsetof(struct JNINativeInterface_, CallLongMethodA),
997
+ offsetof(struct JNINativeInterface_, CallStaticLongMethodA), },
998
+ { "short", "S", rv2jshort, jshort2rv,
999
+ jshortarray2rv, r2sarray,
1000
+ offsetof(struct JNINativeInterface_, CallShortMethodA),
1001
+ offsetof(struct JNINativeInterface_, CallStaticShortMethodA), },
1002
+ { "boolean", "Z", rv2jboolean, jboolean2rv,
1003
+ jbooleanarray2rv, r2boolarray,
1004
+ offsetof(struct JNINativeInterface_, CallBooleanMethodA),
1005
+ offsetof(struct JNINativeInterface_, CallStaticBooleanMethodA), },
1006
+ { "void", "V", rv2jv, jvoid2rv,
1007
+ NULL, r2voidarray,
1008
+ offsetof(struct JNINativeInterface_, CallVoidMethodA),
1009
+ offsetof(struct JNINativeInterface_, CallStaticVoidMethodA), },
1010
+ { "java.lang.String", "Ljava.lang.String;", rv2jstring, jstring2rv,
1011
+ jstringarray2rv, r2objarray,
1012
+ offsetof(struct JNINativeInterface_, CallObjectMethodA),
1013
+ offsetof(struct JNINativeInterface_, CallStaticObjectMethodA), },
1014
+ };
1015
+
1016
+ static void rv2jarray(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release)
1017
+ {
1018
+ if (*psig != '[')
1019
+ {
1020
+ rb_raise(rb_eRuntimeError, "argument signature not array");
1021
+ }
1022
+ if (release)
1023
+ {
1024
+ (*jenv)->DeleteLocalRef(jenv, jv->l);
1025
+ }
1026
+ else
1027
+ {
1028
+ int i;
1029
+ jarray ja = NULL;
1030
+ if (*(psig + 1) == '[')
1031
+ {
1032
+ if (TYPE(val) != T_ARRAY) {
1033
+ rb_raise(rb_eRuntimeError, "array's rank unmatch");
1034
+ }
1035
+ ja = (*jenv)->NewObjectArray(jenv, RARRAY(val)->len, j_object, NULL);
1036
+ check_exception(jenv, 0);
1037
+ for (i = 0; i < RARRAY(val)->len; i++)
1038
+ {
1039
+ jvalue jv;
1040
+ rv2jarray(jenv, RARRAY(val)->ptr[i], &jv, psig + 1, 0);
1041
+ (*jenv)->SetObjectArrayElement(jenv, ja, i, jv.l);
1042
+ }
1043
+ }
1044
+ else
1045
+ {
1046
+ R2JARRAY r2a = r2objarray;
1047
+ for (i = 0; i < COUNTOF(jcvt); i++)
1048
+ {
1049
+ if (*(psig + 1) == jcvt[i].jntype[0])
1050
+ {
1051
+ r2a = jcvt[i].r2ja;
1052
+ break;
1053
+ }
1054
+ }
1055
+ ja = r2a(jenv, val, psig + 1);
1056
+ }
1057
+ jv->l = ja;
1058
+ }
1059
+ }
1060
+
1061
+ /*
1062
+ */
1063
+ static R2J get_r2j(JNIEnv* jenv, jobject o, int* siglen, char* sigp)
1064
+ {
1065
+ int len, i;
1066
+ const char* cname;
1067
+ R2J result = NULL;
1068
+ jstring nm = (*jenv)->CallObjectMethod(jenv, o, class_getName);
1069
+ check_exception(jenv, 0);
1070
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1071
+ if (*cname == '[')
1072
+ {
1073
+ if (siglen)
1074
+ {
1075
+ len = strlen(cname);
1076
+ *siglen += len;
1077
+ strcpy(sigp, cname);
1078
+ }
1079
+ result = rv2jarray;
1080
+ }
1081
+ else
1082
+ {
1083
+ for (i = 0; i < COUNTOF(jcvt); i++)
1084
+ {
1085
+ if (!strcmp(cname, jcvt[i].jtype))
1086
+ {
1087
+ if (siglen)
1088
+ {
1089
+ *siglen += strlen(jcvt[i].jntype);
1090
+ strcpy(sigp, jcvt[i].jntype);
1091
+ }
1092
+ result = jcvt[i].r2j;
1093
+ break;
1094
+ }
1095
+ }
1096
+ if (!result)
1097
+ {
1098
+ if (siglen)
1099
+ {
1100
+ *siglen += sprintf(sigp, "L%s;", cname);
1101
+ }
1102
+ result = rv2jobject;
1103
+ }
1104
+ }
1105
+ release_string(jenv, nm, cname);
1106
+ return result;
1107
+ }
1108
+
1109
+ static J2R get_j2r(JNIEnv* jenv, jobject cls, char* psig, char* pdepth, char* ppsig, off_t* piv, int static_method)
1110
+ {
1111
+ int i;
1112
+ J2R result = NULL;
1113
+ const char* cname;
1114
+ const char* jname = NULL;
1115
+ jstring nm = (*jenv)->CallObjectMethod(jenv, cls, class_getName);
1116
+ check_exception(jenv, 0);
1117
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1118
+
1119
+ if (*cname == '[')
1120
+ {
1121
+ int start;
1122
+ for (start = 1; *(cname + start) == '['; start++);
1123
+ *pdepth = (char)start;
1124
+ for (i = 0; i < COUNTOF(jcvt); i++)
1125
+ {
1126
+ if (*(cname + start) == jcvt[i].jntype[0])
1127
+ {
1128
+ if (jcvt[i].jntype[0] == 'L'
1129
+ && strncmp(cname + start, jcvt[i].jntype, strlen(jcvt[i].jntype)))
1130
+ {
1131
+ break;
1132
+ }
1133
+ result = jcvt[i].ja2r;
1134
+ break;
1135
+ }
1136
+ }
1137
+ if (!result)
1138
+ {
1139
+ result = jarray2rv;
1140
+ }
1141
+ jname = cname;
1142
+ }
1143
+ else
1144
+ {
1145
+ for (i = 0; i < COUNTOF(jcvt); i++)
1146
+ {
1147
+ if (!strcmp(cname, jcvt[i].jtype))
1148
+ {
1149
+ result = jcvt[i].j2r;
1150
+ *piv = (static_method) ? jcvt[i].jscall : jcvt[i].jcall;
1151
+ if (jcvt[i].jntype[0] != 'L')
1152
+ {
1153
+ *psig = jcvt[i].jntype[0];
1154
+ }
1155
+ jname = jcvt[i].jntype;
1156
+ break;
1157
+ }
1158
+ }
1159
+ }
1160
+ if (ppsig)
1161
+ {
1162
+ if (!jname)
1163
+ {
1164
+ sprintf(ppsig, "L%s;", cname);
1165
+ }
1166
+ else
1167
+ {
1168
+ strcpy(ppsig, jname);
1169
+ }
1170
+ java2jniname(ppsig);
1171
+ }
1172
+ release_string(jenv, nm, cname);
1173
+ return result;
1174
+ }
1175
+
1176
+ static void setup_j2r(JNIEnv* jenv, jobject cls, struct cls_method* pm, int static_method)
1177
+ {
1178
+ off_t iv = 0;
1179
+ J2R result = get_j2r(jenv, cls, &pm->basic.result_signature, &pm->basic.result_arraydepth, NULL, &iv, static_method);
1180
+ pm->result_convert = (result) ? result : jv2rv;
1181
+ if (iv)
1182
+ {
1183
+ pm->method = iv;
1184
+ }
1185
+ else
1186
+ {
1187
+ pm->method = (static_method)
1188
+ ? offsetof(struct JNINativeInterface_, CallStaticObjectMethodA)
1189
+ : offsetof(struct JNINativeInterface_, CallObjectMethodA);
1190
+ }
1191
+ }
1192
+
1193
+ static void fill_convert(JNIEnv* jenv, struct cls_constructor* cls, jobjectArray tp, int count)
1194
+ {
1195
+ int i, siglen;
1196
+ R2J* tbl = ALLOC_N(R2J, count);
1197
+ char** sig = (char**)ALLOCA_N(char*, count);
1198
+ char siga[256];
1199
+ cls->arg_convert = tbl;
1200
+ memset(tbl, 0, sizeof(R2J) * count);
1201
+ siglen = 0;
1202
+ for (i = 0; i < count; i++)
1203
+ {
1204
+ jobject o = (*jenv)->GetObjectArrayElement(jenv, tp, i);
1205
+ *(tbl + i) = get_r2j(jenv, o, &siglen, siga);
1206
+ *(sig + i) = ALLOCA_N(char, strlen(siga) + 1);
1207
+ strcpy(*(sig + i), siga);
1208
+ }
1209
+ cls->method_signature = ALLOC_N(char, siglen + 1);
1210
+ *(cls->method_signature) = 0;
1211
+ for (i = 0; i < count; i++)
1212
+ {
1213
+ strcat(cls->method_signature, *(sig + i));
1214
+ }
1215
+ }
1216
+
1217
+ /*
1218
+ * create method info structure
1219
+ * m = instance of Method class
1220
+ * c = instance of the class
1221
+ */
1222
+ static void setup_methodbase(JNIEnv* jenv, struct cls_constructor* pm,
1223
+ jobjectArray parama, jsize pcount)
1224
+ {
1225
+ pm->arg_count = pcount;
1226
+ pm->method_signature = NULL;
1227
+ pm->result_signature = 'O';
1228
+ pm->result_arraydepth = 0;
1229
+ pm->arg_convert = NULL;
1230
+ if (pcount)
1231
+ {
1232
+ fill_convert(jenv, pm, parama, pcount);
1233
+ }
1234
+ }
1235
+
1236
+ static void create_methodinfo(JNIEnv* jenv, st_table* tbl, jobject m, int static_method)
1237
+ {
1238
+ struct cls_method* result;
1239
+ struct cls_method* pm;
1240
+ char* param = NULL;
1241
+ const char* jname;
1242
+ jstring nm;
1243
+ jobjectArray parama;
1244
+ jobject cls;
1245
+ jsize param_count;
1246
+
1247
+ result = ALLOC(struct cls_method);
1248
+ parama = (*jenv)->CallObjectMethod(jenv, m, getParameterTypes);
1249
+ check_exception(jenv, 0);
1250
+ param_count = (*jenv)->GetArrayLength(jenv, parama);
1251
+ check_exception(jenv, 0);
1252
+ setup_methodbase(jenv, &result->basic, parama, param_count);
1253
+
1254
+ nm = (*jenv)->CallObjectMethod(jenv, m, method_getName);
1255
+ check_exception(jenv, 0);
1256
+ jname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1257
+ result->name = rb_intern(jname);
1258
+ release_string(jenv, nm, jname);
1259
+ result->basic.id = (*jenv)->FromReflectedMethod(jenv, m);
1260
+ check_exception(jenv, 0);
1261
+ cls = (*jenv)->CallObjectMethod(jenv, m, getReturnType);
1262
+ check_exception(jenv, 0);
1263
+ setup_j2r(jenv, cls, result, static_method);
1264
+ (*jenv)->DeleteLocalRef(jenv, cls);
1265
+ result->static_method = static_method;
1266
+ if (st_lookup(tbl, result->name, (st_data_t*)&pm))
1267
+ {
1268
+ result->next = pm->next;
1269
+ pm->next = result;
1270
+ }
1271
+ else
1272
+ {
1273
+ result->next = NULL;
1274
+ st_insert(tbl, result->name, (VALUE)result);
1275
+ }
1276
+ }
1277
+
1278
+ static void create_fieldinfo(JNIEnv* jenv, st_table* tbl, jobject f, int readonly, int static_field)
1279
+ {
1280
+ struct cls_field* result;
1281
+ const char* jname;
1282
+ jstring nm;
1283
+ jobject cls;
1284
+ char sigs[256];
1285
+ off_t iv = 0;
1286
+ char sig = 0;
1287
+
1288
+ result = ALLOC(struct cls_field);
1289
+ memset(result, 0, sizeof(struct cls_field));
1290
+ nm = (*jenv)->CallObjectMethod(jenv, f, field_getName);
1291
+ check_exception(jenv, 0);
1292
+ jname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1293
+ result->name = rb_intern(jname);
1294
+ release_string(jenv, nm, jname);
1295
+ result->id = (*jenv)->FromReflectedField(jenv, f);
1296
+ check_exception(jenv, 0);
1297
+ cls = (*jenv)->CallObjectMethod(jenv, f, field_getType);
1298
+ check_exception(jenv, 0);
1299
+ result->value_convert = get_j2r(jenv, cls, &result->result_signature, &result->result_arraydepth, sigs, &iv, 0);
1300
+ result->arg_convert = get_r2j(jenv, cls, NULL, NULL);
1301
+ (*jenv)->DeleteLocalRef(jenv, cls);
1302
+ result->field_signature = ALLOC_N(char, strlen(sigs) + 1);
1303
+ strcpy(result->field_signature, sigs);
1304
+ if (!result->value_convert) result->value_convert = jv2rv;
1305
+ result->readonly = readonly;
1306
+ result->static_field = static_field;
1307
+ st_insert(tbl, result->name, (VALUE)result);
1308
+ }
1309
+
1310
+ static void setup_constructors(JNIEnv* jenv, struct cls_constructor*** pptr, jobjectArray methods)
1311
+ {
1312
+ int i;
1313
+ struct cls_constructor* pc;
1314
+ jsize mcount = (*jenv)->GetArrayLength(jenv, methods);
1315
+ struct cls_constructor** tbl = ALLOC_N(struct cls_constructor*, mcount + 1);
1316
+ *pptr = tbl;
1317
+ for (i = 0; i < mcount; i++)
1318
+ {
1319
+ jobjectArray parama;
1320
+ jsize pcount;
1321
+ jobject c = (*jenv)->GetObjectArrayElement(jenv, methods, i);
1322
+ check_exception(jenv, 0);
1323
+ pc = ALLOC(struct cls_constructor);
1324
+ tbl[i] = pc;
1325
+ parama = (*jenv)->CallObjectMethod(jenv, c, ctrGetParameterTypes);
1326
+ check_exception(jenv, 0);
1327
+ pcount = (*jenv)->GetArrayLength(jenv, parama);
1328
+ check_exception(jenv, 0);
1329
+ setup_methodbase(jenv, pc, parama, pcount);
1330
+ pc->id = (*jenv)->FromReflectedMethod(jenv, c);
1331
+ (*jenv)->DeleteLocalRef(jenv, c);
1332
+ }
1333
+ tbl[mcount] = NULL;
1334
+ }
1335
+
1336
+ static void setup_methods(JNIEnv* jenv, st_table** tbl, st_table** static_tbl,
1337
+ jobjectArray methods)
1338
+ {
1339
+ int i;
1340
+ jint modifier;
1341
+ jsize mcount = (*jenv)->GetArrayLength(jenv, methods);
1342
+ *tbl = st_init_numtable_with_size(mcount);
1343
+ *static_tbl = st_init_numtable();
1344
+ for (i = 0; i < mcount; i++)
1345
+ {
1346
+ jobject m = (*jenv)->GetObjectArrayElement(jenv, methods, i);
1347
+ check_exception(jenv, 0);
1348
+ modifier = (*jenv)->CallIntMethod(jenv, m, method_getModifiers);
1349
+ if (!(modifier & ACC_STATIC))
1350
+ {
1351
+ create_methodinfo(jenv, *tbl, m, 0);
1352
+ }
1353
+ else
1354
+ {
1355
+ create_methodinfo(jenv, *static_tbl, m, 1);
1356
+ }
1357
+ (*jenv)->DeleteLocalRef(jenv, m);
1358
+ }
1359
+ }
1360
+
1361
+ static void setup_fields(JNIEnv* jenv, st_table** tbl, jobjectArray flds)
1362
+ {
1363
+ int i;
1364
+ jint modifier;
1365
+ jsize fcount = (*jenv)->GetArrayLength(jenv, flds);
1366
+ *tbl = st_init_numtable_with_size(fcount);
1367
+ for (i = 0; i < fcount; i++)
1368
+ {
1369
+ jobject f = (*jenv)->GetObjectArrayElement(jenv, flds, i);
1370
+ check_exception(jenv, 0);
1371
+ modifier = (*jenv)->CallIntMethod(jenv, f, field_getModifiers);
1372
+ create_fieldinfo(jenv, *tbl, f, modifier & ACC_FINAL, modifier & ACC_STATIC);
1373
+ (*jenv)->DeleteLocalRef(jenv, f);
1374
+ }
1375
+ }
1376
+
1377
+ static void load_constants(JNIEnv* jenv, jclass klass, VALUE self, jobjectArray flds)
1378
+ {
1379
+ int i;
1380
+ jint modifier;
1381
+ jsize fcount = (*jenv)->GetArrayLength(jenv, flds);
1382
+ for (i = 0; i < fcount; i++)
1383
+ {
1384
+ jobject f = (*jenv)->GetObjectArrayElement(jenv, flds, i);
1385
+ check_exception(jenv, 0);
1386
+ modifier = (*jenv)->CallIntMethod(jenv, f, field_getModifiers);
1387
+ check_exception(jenv, 0);
1388
+ if ((modifier & (ACC_PUBLIC | ACC_STATIC | ACC_FINAL)) == (ACC_PUBLIC | ACC_STATIC | ACC_FINAL))
1389
+ {
1390
+ jstring nm;
1391
+ const char* cname;
1392
+ jobject cls;
1393
+ char sig;
1394
+ char depth;
1395
+ off_t iv;
1396
+ J2R j2r;
1397
+ jvalue jv;
1398
+ jfieldID jfid;
1399
+ char sigs[256];
1400
+
1401
+ // constants make define directly in the ruby object
1402
+ cls = (*jenv)->CallObjectMethod(jenv, f, field_getType);
1403
+ check_exception(jenv, 0);
1404
+ iv = 0;
1405
+ sig = depth = 0;
1406
+ j2r = get_j2r(jenv, cls, &sig, &depth, sigs, &iv, 1);
1407
+ if (!j2r) j2r = jv2rv;
1408
+ (*jenv)->DeleteLocalRef(jenv, cls);
1409
+ nm = (*jenv)->CallObjectMethod(jenv, f, field_getName);
1410
+ check_exception(jenv, 0);
1411
+ cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL);
1412
+ check_exception(jenv, 0);
1413
+ jfid = (*jenv)->GetStaticFieldID(jenv, klass, cname, sigs);
1414
+ check_exception(jenv, 0);
1415
+ switch (sig)
1416
+ {
1417
+ case 'D':
1418
+ jv.d = (*jenv)->GetStaticDoubleField(jenv, klass, jfid);
1419
+ break;
1420
+ case 'Z':
1421
+ jv.z = (*jenv)->GetStaticBooleanField(jenv, klass, jfid);
1422
+ break;
1423
+ case 'B':
1424
+ jv.b = (*jenv)->GetStaticByteField(jenv, klass, jfid);
1425
+ break;
1426
+ case 'F':
1427
+ jv.f = (*jenv)->GetStaticFloatField(jenv, klass, jfid);
1428
+ break;
1429
+ case 'C':
1430
+ jv.c = (*jenv)->GetStaticCharField(jenv, klass, jfid);
1431
+ break;
1432
+ case 'S':
1433
+ jv.s = (*jenv)->GetStaticShortField(jenv, klass, jfid);
1434
+ break;
1435
+ case 'J':
1436
+ jv.j = (*jenv)->GetStaticLongField(jenv, klass, jfid);
1437
+ break;
1438
+ case 'I':
1439
+ jv.i = (*jenv)->GetStaticIntField(jenv, klass, jfid);
1440
+ break;
1441
+ default:
1442
+ jv.l = (*jenv)->GetStaticObjectField(jenv, klass, jfid);
1443
+ break;
1444
+ }
1445
+ if (!isupper(*cname))
1446
+ {
1447
+ char* p = ALLOCA_N(char, strlen(cname) + 1);
1448
+ strcpy(p, cname);
1449
+ *p = toupper(*p);
1450
+ if (isupper(*p))
1451
+ {
1452
+ rb_define_const(RBASIC(self)->klass, p, j2r(jenv, jv));
1453
+ }
1454
+ }
1455
+ else
1456
+ {
1457
+ rb_define_const(RBASIC(self)->klass, cname, j2r(jenv, jv));
1458
+ }
1459
+
1460
+ release_string(jenv, nm, cname);
1461
+ }
1462
+ (*jenv)->DeleteLocalRef(jenv, f);
1463
+ }
1464
+ }
1465
+
1466
+ static void setup_metadata(JNIEnv* jenv, VALUE self, struct jv_data* ptr, VALUE classname)
1467
+ {
1468
+ jmethodID mid;
1469
+ jobjectArray methods;
1470
+ jobjectArray flds;
1471
+
1472
+ jclass klass = (*jenv)->GetObjectClass(jenv, ptr->idata.obj);
1473
+ ptr->idata.klass = (*jenv)->NewGlobalRef(jenv, klass);
1474
+ check_exception(jenv, 0);
1475
+ mid = (*jenv)->GetMethodID(jenv, klass, "getMethods", "()[Ljava/lang/reflect/Method;");
1476
+ check_exception(jenv, 0);
1477
+ methods = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid);
1478
+ check_exception(jenv, 0);
1479
+ setup_methods(jenv, &ptr->idata.methods, &ptr->static_methods, methods);
1480
+ mid = (*jenv)->GetMethodID(jenv, klass, "getConstructors", "()[Ljava/lang/reflect/Constructor;");
1481
+ check_exception(jenv, 0);
1482
+ methods = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid);
1483
+ check_exception(jenv, 0);
1484
+ setup_constructors(jenv, &ptr->constructors, methods);
1485
+ mid = (*jenv)->GetMethodID(jenv, klass, "getFields", "()[Ljava/lang/reflect/Field;");
1486
+ check_exception(jenv, 0);
1487
+ flds = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid);
1488
+ check_exception(jenv, 0);
1489
+ setup_fields(jenv, &ptr->idata.fields, flds);
1490
+
1491
+ register_class(self, classname);
1492
+
1493
+ load_constants(jenv, ptr->idata.obj, self, flds);
1494
+ }
1495
+
1496
+ /*
1497
+ * load Java Virtual Machine
1498
+ * def load(class_path = '', vmargs = [])
1499
+ * class_path: passes for the class dir and jar name
1500
+ * vmargs: strng array of vmarg (such as -Xrs)
1501
+ *
1502
+ * change in rjb 0.1.7, omit first argument for JNI version.
1503
+ * because I misunderstood the number means (JVM but JNI).
1504
+ */
1505
+ static VALUE rjb_s_load(int argc, VALUE* argv, VALUE self)
1506
+ {
1507
+ JNIEnv* jenv;
1508
+ JavaVMInitArgs vm_args;
1509
+ jint res;
1510
+ VALUE user_path;
1511
+ VALUE vm_argv;
1512
+ char* userpath;
1513
+ int i;
1514
+ jclass jmethod;
1515
+ jclass jfield;
1516
+ jclass jconstructor;
1517
+
1518
+ if (jvm)
1519
+ {
1520
+ return Qnil;
1521
+ }
1522
+
1523
+ memset(&vm_args, 0, sizeof(vm_args));
1524
+ vm_args.version = JNI_VERSION_1_4;
1525
+ rb_scan_args(argc, argv, "02", &user_path, &vm_argv);
1526
+ if (!NIL_P(user_path))
1527
+ {
1528
+ Check_Type(user_path, T_STRING);
1529
+ userpath = StringValueCStr(user_path);
1530
+ }
1531
+ else
1532
+ {
1533
+ userpath = ".";
1534
+ }
1535
+ if (!NIL_P(vm_argv))
1536
+ {
1537
+ Check_Type(vm_argv, T_ARRAY);
1538
+ }
1539
+ jenv = NULL;
1540
+ res = create_jvm(&jenv, &vm_args, userpath, vm_argv);
1541
+ if (res < 0)
1542
+ {
1543
+ jvm = NULL;
1544
+ rb_raise(rb_eRuntimeError, "can't create Java VM");
1545
+ } else {
1546
+ main_jenv = jenv;
1547
+ }
1548
+
1549
+ jconstructor = (*jenv)->FindClass(jenv, "java/lang/reflect/Constructor");
1550
+ check_exception(jenv, 1);
1551
+ ctrGetParameterTypes = (*jenv)->GetMethodID(jenv, jconstructor, "getParameterTypes", "()[Ljava/lang/Class;");
1552
+ check_exception(jenv, 1);
1553
+ jmethod = (*jenv)->FindClass(jenv, "java/lang/reflect/Method");
1554
+ method_getModifiers = (*jenv)->GetMethodID(jenv, jmethod, "getModifiers", "()I");
1555
+ check_exception(jenv, 1);
1556
+ method_getName = (*jenv)->GetMethodID(jenv, jmethod, "getName", "()Ljava/lang/String;");
1557
+ check_exception(jenv, 1);
1558
+ getParameterTypes = (*jenv)->GetMethodID(jenv, jmethod, "getParameterTypes", "()[Ljava/lang/Class;");
1559
+ check_exception(jenv, 1);
1560
+ getReturnType = (*jenv)->GetMethodID(jenv, jmethod, "getReturnType", "()Ljava/lang/Class;");
1561
+ check_exception(jenv, 1);
1562
+
1563
+ jfield = (*jenv)->FindClass(jenv, "java/lang/reflect/Field");
1564
+ field_getModifiers = (*jenv)->GetMethodID(jenv, jfield, "getModifiers", "()I");
1565
+ check_exception(jenv, 1);
1566
+ field_getName = (*jenv)->GetMethodID(jenv, jfield, "getName", "()Ljava/lang/String;");
1567
+ check_exception(jenv, 1);
1568
+ field_getType = (*jenv)->GetMethodID(jenv, jfield, "getType", "()Ljava/lang/Class;");
1569
+ check_exception(jenv, 1);
1570
+
1571
+ j_class = (*jenv)->FindClass(jenv, "java/lang/Class");
1572
+ check_exception(jenv, 1);
1573
+ class_getName = (*jenv)->GetMethodID(jenv, j_class, "getName", "()Ljava/lang/String;");
1574
+ check_exception(jenv, 1);
1575
+ j_class = (*jenv)->NewGlobalRef(jenv, j_class);
1576
+
1577
+ j_throwable = (*jenv)->FindClass(jenv, "java/lang/Throwable");
1578
+ check_exception(jenv, 1);
1579
+ throwable_getMessage = (*jenv)->GetMethodID(jenv, j_throwable, "getMessage", "()Ljava/lang/String;");
1580
+ check_exception(jenv, 1);
1581
+
1582
+ j_string = (*jenv)->FindClass(jenv, "java/lang/String");
1583
+ check_exception(jenv, 1);
1584
+ str_tostring = (*jenv)->GetMethodID(jenv, j_string, "toString", "()Ljava/lang/String;");
1585
+ check_exception(jenv, 1);
1586
+ j_string = (*jenv)->NewGlobalRef(jenv, j_string);
1587
+
1588
+ j_object = (*jenv)->FindClass(jenv, "java/lang/Object");
1589
+ check_exception(jenv, 1);
1590
+ j_object = (*jenv)->NewGlobalRef(jenv, j_object);
1591
+
1592
+ for (i = PRM_INT; i < PRM_LAST; i++)
1593
+ {
1594
+ jclass klass = (*jenv)->FindClass(jenv, jpcvt[i].classname);
1595
+ if (i == PRM_BOOLEAN)
1596
+ {
1597
+ jpcvt[i].ctr_id = (*jenv)->GetStaticMethodID(jenv,
1598
+ klass, "valueOf", jpcvt[i].ctrsig);
1599
+ check_exception(jenv, 1);
1600
+ }
1601
+ else if (jpcvt[i].ctrsig)
1602
+ {
1603
+ jpcvt[i].ctr_id = (*jenv)->GetMethodID(jenv, klass,
1604
+ "<init>", jpcvt[i].ctrsig);
1605
+ check_exception(jenv, 1);
1606
+ }
1607
+ jpcvt[i].to_prim_id = (*jenv)->GetMethodID(jenv, klass,
1608
+ jpcvt[i].to_prim_method, jpcvt[i].prmsig);
1609
+ check_exception(jenv, 1);
1610
+ jpcvt[i].klass = (*jenv)->NewGlobalRef(jenv, klass);
1611
+ }
1612
+
1613
+ jklass = import_class(jenv, j_class, rb_str_new2("java.lang.Class"));
1614
+ rb_define_method(RBASIC(jklass)->klass, "forName", rjb_class_forname, -1);
1615
+ rb_gc_register_address(&jklass);
1616
+
1617
+ return Qnil;
1618
+ }
1619
+
1620
+ /*
1621
+ * unload Java Virtual Machine
1622
+ *
1623
+ * def unload()
1624
+ * classes.clear
1625
+ * unload(jvm)
1626
+ * end
1627
+ */
1628
+ static int clear_classes(VALUE key, VALUE val, VALUE dummy)
1629
+ {
1630
+ return ST_DELETE;
1631
+ }
1632
+ static VALUE rjb_s_unload(int argc, VALUE* argv, VALUE self)
1633
+ {
1634
+ st_foreach(RHASH(loaded_classes)->tbl, clear_classes, 0);
1635
+ if (jvm)
1636
+ {
1637
+ (*jvm)->DestroyJavaVM(jvm);
1638
+ jvm = NULL;
1639
+ }
1640
+ return Qnil;
1641
+ }
1642
+
1643
+ /*
1644
+ * return all classes that were already loaded.
1645
+ * this method simply returns the global hash,
1646
+ * but it's safe because the hash was frozen.
1647
+ */
1648
+ static VALUE rjb_s_classes(VALUE self)
1649
+ {
1650
+ return loaded_classes;
1651
+ }
1652
+
1653
+ /*
1654
+ * free java class
1655
+ */
1656
+ static void free_constructor(struct cls_constructor* p)
1657
+ {
1658
+ free(p->arg_convert);
1659
+ free(p->method_signature);
1660
+ }
1661
+ static int free_method_item(ID key, struct cls_method* pm, int dummy)
1662
+ {
1663
+ for (; pm; pm = pm->next)
1664
+ {
1665
+ free_constructor(&pm->basic);
1666
+ }
1667
+ return ST_CONTINUE;
1668
+ }
1669
+
1670
+ /*
1671
+ * finalize Object instance
1672
+ */
1673
+ static VALUE rjb_delete_ref(struct jvi_data* ptr)
1674
+ {
1675
+ JNIEnv* jenv = attach_current_thread();
1676
+ if (jenv)
1677
+ {
1678
+ (*jenv)->DeleteGlobalRef(jenv, ptr->obj);
1679
+ }
1680
+ return Qnil;
1681
+ }
1682
+
1683
+ /*
1684
+ * finalize Bridge instance
1685
+ */
1686
+ static VALUE rj_bridge_free(struct rj_bridge* ptr)
1687
+ {
1688
+ JNIEnv* jenv = attach_current_thread();
1689
+ (*jenv)->DeleteLocalRef(jenv, ptr->proxy);
1690
+ (*jenv)->DeleteLocalRef(jenv, ptr->bridge);
1691
+ return Qnil;
1692
+ }
1693
+
1694
+ /*
1695
+ * mark wrapped object in the Bridge
1696
+ */
1697
+ static void rj_bridge_mark(struct rj_bridge* ptr)
1698
+ {
1699
+ rb_gc_mark(ptr->wrapped);
1700
+ }
1701
+
1702
+ /*
1703
+ * finalize Class instance
1704
+ */
1705
+ static VALUE rjb_s_free(struct jv_data* ptr)
1706
+ {
1707
+ /* class never delete
1708
+ JNIEnv* jenv = attach_current_thread();
1709
+ struct cls_constructor** c;
1710
+
1711
+ rjb_delete_ref(&ptr->idata);
1712
+ if (ptr->constructors)
1713
+ {
1714
+ for (c = ptr->constructors; *c; c++)
1715
+ {
1716
+ free_constructor(*c);
1717
+ }
1718
+ }
1719
+ free(ptr->constructors);
1720
+ if (ptr->idata.methods)
1721
+ {
1722
+ st_foreach(ptr->idata.methods, (int(*)())free_method_item, 0);
1723
+ st_free_table(ptr->idata.methods);
1724
+ }
1725
+ (*jenv)->DeleteGlobalRef(jenv, ptr->idata.klass);
1726
+ st_delete(RHASH(loaded_classes)->tbl, clsname, NULL);
1727
+ */
1728
+ return Qnil;
1729
+ }
1730
+
1731
+ /*
1732
+ * create new instance of this class
1733
+ */
1734
+ static VALUE createinstance(JNIEnv* jenv, int argc, VALUE* argv,
1735
+ struct jvi_data* org, struct cls_constructor* pc)
1736
+ {
1737
+ int i;
1738
+ char* psig = pc->method_signature;
1739
+ jobject obj = NULL;
1740
+ VALUE result;
1741
+
1742
+ jvalue* args = (argc) ? ALLOCA_N(jvalue, argc) : NULL;
1743
+ for (i = 0; i < argc; i++)
1744
+ {
1745
+ R2J pr2j = *(pc->arg_convert + i);
1746
+ pr2j(jenv, argv[i], args + i, psig, 0);
1747
+ psig = next_sig(psig);
1748
+ }
1749
+ obj = (*jenv)->NewObjectA(jenv, org->obj, pc->id, args);
1750
+ if (!obj)
1751
+ {
1752
+ check_exception(jenv, 1);
1753
+ }
1754
+ psig = pc->method_signature;
1755
+ for (i = 0; i < argc; i++)
1756
+ {
1757
+ R2J pr2j = *(pc->arg_convert + i);
1758
+ pr2j(jenv, argv[i], args + i, psig, 1);
1759
+ psig = next_sig(psig);
1760
+ }
1761
+
1762
+ result = register_instance(jenv, org, obj);
1763
+ (*jenv)->DeleteLocalRef(jenv, obj);
1764
+ return result;
1765
+ }
1766
+
1767
+ static VALUE import_class(JNIEnv* jenv, jclass jcls, VALUE clsname)
1768
+ {
1769
+ VALUE v;
1770
+ VALUE rexp;
1771
+ struct jv_data* ptr;
1772
+ char* pclsname = StringValueCStr(clsname);
1773
+ char* nm = ALLOCA_N(char, strlen(pclsname) + 1);
1774
+ strcpy(nm, pclsname);
1775
+ *nm = toupper(*nm);
1776
+ for (pclsname = nm; *pclsname; pclsname++)
1777
+ {
1778
+ if (*pclsname == '.')
1779
+ {
1780
+ *pclsname = '_';
1781
+ }
1782
+ }
1783
+ rexp = rb_define_class_under(rjb, nm, rjbc);
1784
+ ptr = ALLOC(struct jv_data);
1785
+ memset(ptr, 0, sizeof(struct jv_data));
1786
+ v = Data_Wrap_Struct(rexp, NULL, rjb_s_free, ptr);
1787
+ ptr->idata.obj = (*jenv)->NewGlobalRef(jenv, jcls);
1788
+ setup_metadata(jenv, v, ptr, clsname);
1789
+ return v;
1790
+ }
1791
+
1792
+ static VALUE register_instance(JNIEnv* jenv, struct jvi_data* org, jobject obj)
1793
+ {
1794
+ VALUE v;
1795
+ struct jvi_data* ptr = ALLOC(struct jvi_data);
1796
+ memset(ptr, 0, sizeof(struct jvi_data));
1797
+ v = Data_Wrap_Struct(rjbi, NULL, rjb_delete_ref, ptr);
1798
+ ptr->klass = org->obj;
1799
+ ptr->obj = (*jenv)->NewGlobalRef(jenv, obj);
1800
+ ptr->methods = org->methods;
1801
+ ptr->fields = org->fields;
1802
+ return v;
1803
+ }
1804
+
1805
+ /*
1806
+ * temporary signature check
1807
+ * return !0 if found
1808
+ */
1809
+ static int check_rtype(JNIEnv* jenv, VALUE v, char* p)
1810
+ {
1811
+ char* pcls = NULL;
1812
+ if (*p == 'L')
1813
+ {
1814
+ char* pt = strchr(p, ';');
1815
+ if (pt)
1816
+ {
1817
+ int len = pt - p - 1;
1818
+ pcls = ALLOCA_N(char, len + 1);
1819
+ strncpy(pcls, p + 1, len);
1820
+ *(pcls + len) = '\0';
1821
+ }
1822
+ }
1823
+ if (pcls && !strcmp("java.lang.Object", pcls))
1824
+ {
1825
+ return 1;
1826
+ }
1827
+ switch (TYPE(v))
1828
+ {
1829
+ case T_FIXNUM:
1830
+ return (int)strchr("BCDFIJS", *p);
1831
+ case T_FLOAT:
1832
+ return (int)strchr("DF", *p);
1833
+ case T_STRING:
1834
+ return pcls && !strcmp("java.lang.String", pcls);
1835
+ case T_TRUE:
1836
+ case T_FALSE:
1837
+ return *p == 'Z';
1838
+ case T_ARRAY:
1839
+ return *p == '[';
1840
+ case T_DATA:
1841
+ if (RBASIC(v)->klass == rjbi && pcls)
1842
+ {
1843
+ // imported object
1844
+ jclass cls;
1845
+ struct jvi_data* ptr;
1846
+ int result = 0;
1847
+ if (!strcmp("java.lang.String", pcls)) return 1;
1848
+ Data_Get_Struct(v, struct jvi_data, ptr);
1849
+ cls = (*jenv)->FindClass(jenv, java2jniname(pcls));
1850
+ if (cls)
1851
+ {
1852
+ result = (cls && (*jenv)->IsInstanceOf(jenv, ptr->obj, cls));
1853
+ (*jenv)->DeleteLocalRef(jenv, cls);
1854
+ }
1855
+ return result;
1856
+ }
1857
+ // fall down to the next case
1858
+ case T_OBJECT:
1859
+ // fall down to the next case
1860
+ default:
1861
+ if (pcls)
1862
+ {
1863
+ return 1;
1864
+ }
1865
+ return 0;
1866
+ }
1867
+ }
1868
+
1869
+ /*
1870
+ * new instance with signature
1871
+ */
1872
+ static VALUE rjb_newinstance_s(int argc, VALUE* argv, VALUE self)
1873
+ {
1874
+ VALUE vsig, rest;
1875
+ char* sig;
1876
+ VALUE ret = Qnil;
1877
+ struct jv_data* ptr;
1878
+ JNIEnv* jenv = attach_current_thread();
1879
+
1880
+ rb_scan_args(argc, argv, "1*", &vsig, &rest);
1881
+ sig = StringValueCStr(vsig);
1882
+ Data_Get_Struct(self, struct jv_data, ptr);
1883
+ if (ptr->constructors)
1884
+ {
1885
+ struct cls_constructor** pc = ptr->constructors;
1886
+ for (pc = ptr->constructors; *pc; pc++)
1887
+ {
1888
+ if ((*pc)->arg_count == argc - 1
1889
+ && !strcmp(sig, (*pc)->method_signature))
1890
+ {
1891
+ ret = createinstance(jenv, argc - 1, argv + 1, &ptr->idata, *pc);
1892
+ break;
1893
+ }
1894
+ }
1895
+ }
1896
+ return ret;
1897
+ }
1898
+
1899
+ static VALUE rjb_newinstance(int argc, VALUE* argv, VALUE self)
1900
+ {
1901
+ VALUE ret = Qnil;
1902
+ struct jv_data* ptr;
1903
+ struct cls_constructor** pc;
1904
+ JNIEnv* jenv = attach_current_thread();
1905
+
1906
+ Data_Get_Struct(self, struct jv_data, ptr);
1907
+
1908
+ if (ptr->constructors)
1909
+ {
1910
+ int i, found = 0;
1911
+ char* psig;
1912
+ for (pc = ptr->constructors; *pc; pc++)
1913
+ {
1914
+ if ((*pc)->arg_count == argc)
1915
+ {
1916
+ found = 1;
1917
+ psig = (*pc)->method_signature;
1918
+ for (i = 0; i < argc; i++)
1919
+ {
1920
+ if (!check_rtype(jenv, *(argv + i), psig))
1921
+ {
1922
+ found = 0;
1923
+ break;
1924
+ }
1925
+ psig = next_sig(psig);
1926
+ }
1927
+ if (found)
1928
+ {
1929
+ ret = createinstance(jenv, argc, argv, &ptr->idata, *pc);
1930
+ break;
1931
+ }
1932
+ }
1933
+ }
1934
+ }
1935
+ return ret;
1936
+ }
1937
+
1938
+ /*
1939
+ * find java class from classname
1940
+ */
1941
+ jclass find_class(JNIEnv* jenv, VALUE name)
1942
+ {
1943
+ char* cname;
1944
+ char* jnicls;
1945
+
1946
+ cname = StringValueCStr(name);
1947
+ jnicls = ALLOCA_N(char, strlen(cname) + 1);
1948
+ strcpy(jnicls, cname);
1949
+ return (*jenv)->FindClass(jenv, java2jniname(jnicls));
1950
+ }
1951
+
1952
+ /*
1953
+ * jclass Rjb::bind(rbobj, interface_name)
1954
+ */
1955
+ static VALUE rjb_s_bind(VALUE self, VALUE rbobj, VALUE itfname)
1956
+ {
1957
+ VALUE result = Qnil;
1958
+ JNIEnv* jenv = attach_current_thread();
1959
+
1960
+ jclass itf = find_class(jenv, itfname);
1961
+ check_exception(jenv, 1);
1962
+ if (itf)
1963
+ {
1964
+ struct rj_bridge* ptr = ALLOC(struct rj_bridge);
1965
+ memset(ptr, 0, sizeof(struct rj_bridge));
1966
+ ptr->bridge = (*jenv)->NewGlobalRef(jenv,
1967
+ (*jenv)->AllocObject(jenv, rbridge));
1968
+ if (!ptr->bridge)
1969
+ {
1970
+ free(ptr);
1971
+ check_exception(jenv, 1);
1972
+ return Qnil;
1973
+ }
1974
+ ptr->proxy = (*jenv)->CallObjectMethod(jenv, ptr->bridge,
1975
+ register_bridge, itf);
1976
+ ptr->proxy = (*jenv)->NewGlobalRef(jenv, ptr->proxy);
1977
+ ptr->wrapped = rbobj;
1978
+ result = Data_Wrap_Struct(rjbb, rj_bridge_mark, rj_bridge_free, ptr);
1979
+ rb_ary_push(proxies, result);
1980
+ }
1981
+ return result;
1982
+ }
1983
+
1984
+ /*
1985
+ * Jclass Rjb::import(classname)
1986
+ */
1987
+ static VALUE rjb_s_import(VALUE self, VALUE clsname)
1988
+ {
1989
+ JNIEnv* jenv;
1990
+ jclass jcls;
1991
+ VALUE v = rb_hash_aref(loaded_classes, clsname);
1992
+ if (v != Qnil)
1993
+ {
1994
+ return v;
1995
+ }
1996
+
1997
+ if (!jvm)
1998
+ {
1999
+ /* auto-load with default setting */
2000
+ rjb_s_load(0, NULL, 0);
2001
+ }
2002
+ jenv = attach_current_thread();
2003
+ jcls = find_class(jenv, clsname);
2004
+ if (!jcls)
2005
+ {
2006
+ check_exception(jenv, 0);
2007
+ rb_raise(rb_eRuntimeError, "`%s' not found", StringValueCStr(clsname));
2008
+ }
2009
+ v = import_class(jenv, jcls, clsname);
2010
+ return v;
2011
+ }
2012
+
2013
+ static void register_class(VALUE self, VALUE clsname)
2014
+ {
2015
+ rb_define_singleton_method(self, "new", rjb_newinstance, -1);
2016
+ rb_define_singleton_method(self, "new_with_sig", rjb_newinstance_s, -1);
2017
+ /*
2018
+ * the hash was frozen, so it need to call st_ func directly.
2019
+ */
2020
+ st_insert(RHASH(loaded_classes)->tbl, clsname, self);
2021
+ }
2022
+
2023
+ /*
2024
+ * return class name
2025
+ */
2026
+ static VALUE rjb_i_class(VALUE self)
2027
+ {
2028
+ JNIEnv* jenv = attach_current_thread();
2029
+ struct jvi_data* ptr;
2030
+ jstring nm;
2031
+ Data_Get_Struct(self, struct jvi_data, ptr);
2032
+ nm = (*jenv)->CallObjectMethod(jenv, ptr->klass, class_getName);
2033
+ check_exception(jenv, 0);
2034
+ return jstring2val(jenv, nm);
2035
+ }
2036
+
2037
+ /*
2038
+ * invoker
2039
+ */
2040
+ static VALUE getter(JNIEnv* jenv, struct cls_field* pf, struct jvi_data* ptr)
2041
+ {
2042
+ jvalue jv;
2043
+ switch (pf->result_signature)
2044
+ {
2045
+ case 'D':
2046
+ if (pf->static_field)
2047
+ {
2048
+ jv.d = (*jenv)->GetStaticDoubleField(jenv, ptr->klass, pf->id);
2049
+ }
2050
+ else
2051
+ {
2052
+ jv.d = (*jenv)->GetDoubleField(jenv, ptr->obj, pf->id);
2053
+ }
2054
+ break;
2055
+ case 'Z':
2056
+ if (pf->static_field)
2057
+ {
2058
+ jv.z = (*jenv)->GetStaticBooleanField(jenv, ptr->klass, pf->id);
2059
+ }
2060
+ else
2061
+ {
2062
+ jv.z = (*jenv)->GetBooleanField(jenv, ptr->obj, pf->id);
2063
+ }
2064
+ break;
2065
+ case 'B':
2066
+ if (pf->static_field)
2067
+ {
2068
+ jv.b = (*jenv)->GetStaticByteField(jenv, ptr->klass, pf->id);
2069
+ }
2070
+ else
2071
+ {
2072
+ jv.b = (*jenv)->GetByteField(jenv, ptr->obj, pf->id);
2073
+ }
2074
+ break;
2075
+ case 'F':
2076
+ if (pf->static_field)
2077
+ {
2078
+ jv.f = (*jenv)->GetStaticFloatField(jenv, ptr->klass, pf->id);
2079
+ }
2080
+ else
2081
+ {
2082
+ jv.f = (*jenv)->GetFloatField(jenv, ptr->obj, pf->id);
2083
+ }
2084
+ break;
2085
+ case 'C':
2086
+ if (pf->static_field)
2087
+ {
2088
+ jv.c = (*jenv)->GetStaticCharField(jenv, ptr->klass, pf->id);
2089
+ }
2090
+ else
2091
+ {
2092
+ jv.c = (*jenv)->GetCharField(jenv, ptr->obj, pf->id);
2093
+ }
2094
+ break;
2095
+ case 'S':
2096
+ if (pf->static_field)
2097
+ {
2098
+ jv.s = (*jenv)->GetStaticShortField(jenv, ptr->klass, pf->id);
2099
+ }
2100
+ else
2101
+ {
2102
+ jv.s = (*jenv)->GetShortField(jenv, ptr->obj, pf->id);
2103
+ }
2104
+ break;
2105
+ case 'J':
2106
+ if (pf->static_field)
2107
+ {
2108
+ jv.j = (*jenv)->GetStaticLongField(jenv, ptr->klass, pf->id);
2109
+ }
2110
+ else
2111
+ {
2112
+ jv.j = (*jenv)->GetLongField(jenv, ptr->obj, pf->id);
2113
+ }
2114
+ break;
2115
+ case 'I':
2116
+ if (pf->static_field)
2117
+ {
2118
+ jv.i = (*jenv)->GetStaticIntField(jenv, ptr->klass, pf->id);
2119
+ }
2120
+ else
2121
+ {
2122
+ jv.i = (*jenv)->GetIntField(jenv, ptr->obj, pf->id);
2123
+ }
2124
+ break;
2125
+ default:
2126
+ if (pf->static_field)
2127
+ {
2128
+ jv.l = (*jenv)->GetStaticObjectField(jenv, ptr->klass, pf->id);
2129
+ }
2130
+ else
2131
+ {
2132
+ jv.l = (*jenv)->GetObjectField(jenv, ptr->obj, pf->id);
2133
+ }
2134
+ break;
2135
+ }
2136
+ if (pf->result_arraydepth)
2137
+ {
2138
+ return ja2r(pf->value_convert, jenv, jv, pf->result_arraydepth);
2139
+ }
2140
+ else
2141
+ {
2142
+ return pf->value_convert(jenv, jv);
2143
+ }
2144
+ }
2145
+
2146
+ static void setter(JNIEnv* jenv, struct cls_field* pf, struct jvi_data* ptr, VALUE val)
2147
+ {
2148
+ jvalue jv;
2149
+ pf->arg_convert(jenv, val, &jv, pf->field_signature, 0);
2150
+ switch (*pf->field_signature)
2151
+ {
2152
+ case 'D':
2153
+ if (pf->static_field)
2154
+ {
2155
+ (*jenv)->SetStaticDoubleField(jenv, ptr->klass, pf->id, jv.d);
2156
+ }
2157
+ else
2158
+ {
2159
+ (*jenv)->SetDoubleField(jenv, ptr->obj, pf->id, jv.d);
2160
+ }
2161
+ break;
2162
+ case 'Z':
2163
+ if (pf->static_field)
2164
+ {
2165
+ (*jenv)->SetStaticBooleanField(jenv, ptr->klass, pf->id, jv.z);
2166
+ }
2167
+ else
2168
+ {
2169
+ (*jenv)->SetBooleanField(jenv, ptr->obj, pf->id, jv.z);
2170
+ }
2171
+ break;
2172
+ case 'B':
2173
+ if (pf->static_field)
2174
+ {
2175
+ (*jenv)->SetStaticByteField(jenv, ptr->klass, pf->id, jv.b);
2176
+ }
2177
+ else
2178
+ {
2179
+ (*jenv)->SetByteField(jenv, ptr->obj, pf->id, jv.b);
2180
+ }
2181
+ break;
2182
+ case 'F':
2183
+ if (pf->static_field)
2184
+ {
2185
+ (*jenv)->SetStaticFloatField(jenv, ptr->klass, pf->id, jv.f);
2186
+ }
2187
+ else
2188
+ {
2189
+ (*jenv)->SetFloatField(jenv, ptr->obj, pf->id, jv.f);
2190
+ }
2191
+ break;
2192
+ case 'C':
2193
+ if (pf->static_field)
2194
+ {
2195
+ (*jenv)->SetStaticCharField(jenv, ptr->klass, pf->id, jv.c);
2196
+ }
2197
+ else
2198
+ {
2199
+ (*jenv)->SetCharField(jenv, ptr->obj, pf->id, jv.c);
2200
+ }
2201
+ break;
2202
+ case 'S':
2203
+ if (pf->static_field)
2204
+ {
2205
+ (*jenv)->SetStaticShortField(jenv, ptr->klass, pf->id, jv.s);
2206
+ }
2207
+ else
2208
+ {
2209
+ (*jenv)->SetShortField(jenv, ptr->obj, pf->id, jv.s);
2210
+ }
2211
+ break;
2212
+ case 'J':
2213
+ if (pf->static_field)
2214
+ {
2215
+ (*jenv)->SetStaticLongField(jenv, ptr->klass, pf->id, jv.j);
2216
+ }
2217
+ else
2218
+ {
2219
+ (*jenv)->SetLongField(jenv, ptr->obj, pf->id, jv.j);
2220
+ }
2221
+ break;
2222
+ case 'I':
2223
+ if (pf->static_field)
2224
+ {
2225
+ (*jenv)->SetStaticIntField(jenv, ptr->klass, pf->id, jv.i);
2226
+ }
2227
+ else
2228
+ {
2229
+ (*jenv)->SetIntField(jenv, ptr->obj, pf->id, jv.i);
2230
+ }
2231
+ break;
2232
+ default:
2233
+ if (pf->static_field)
2234
+ {
2235
+ (*jenv)->SetStaticObjectField(jenv, ptr->klass, pf->id, jv.l);
2236
+ }
2237
+ else
2238
+ {
2239
+ (*jenv)->SetObjectField(jenv, ptr->obj, pf->id, jv.l);
2240
+ }
2241
+ break;
2242
+ }
2243
+ pf->arg_convert(jenv, val, &jv, pf->field_signature, 1);
2244
+ }
2245
+
2246
+ static VALUE invoke(JNIEnv* jenv, struct cls_method* pm, struct jvi_data* ptr,
2247
+ int argc, VALUE* argv, const char* sig)
2248
+ {
2249
+ int i, found;
2250
+ jvalue jv;
2251
+ jvalue* args;
2252
+ char* psig;
2253
+ struct cls_method* orgpm = pm;
2254
+
2255
+ for (found = 0; pm; pm = pm->next)
2256
+ {
2257
+ if (argc == pm->basic.arg_count)
2258
+ {
2259
+ if (sig)
2260
+ {
2261
+ if (!strcmp(sig, pm->basic.method_signature))
2262
+ {
2263
+ found = 1;
2264
+ break;
2265
+ }
2266
+ }
2267
+ else
2268
+ {
2269
+ psig = pm->basic.method_signature;
2270
+ found = 1;
2271
+ for (i = 0; i < argc; i++)
2272
+ {
2273
+ if (!check_rtype(jenv, *(argv + i), psig))
2274
+ {
2275
+ found = 0;
2276
+ break;
2277
+ }
2278
+ psig = next_sig(psig);
2279
+ }
2280
+ if (found) break;
2281
+ }
2282
+ }
2283
+ }
2284
+ if (!found)
2285
+ {
2286
+ char* tname = rb_id2name(orgpm->name);
2287
+ if (sig)
2288
+ {
2289
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s(\'%s\')'", tname, sig);
2290
+ }
2291
+ else
2292
+ {
2293
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname);
2294
+ }
2295
+ }
2296
+ args = (argc) ? ALLOCA_N(jvalue, argc) : NULL;
2297
+ psig = pm->basic.method_signature;
2298
+ for (i = 0; i < argc; i++)
2299
+ {
2300
+ R2J pr2j = *(pm->basic.arg_convert + i);
2301
+ pr2j(jenv, argv[i], args + i, psig, 0);
2302
+ psig = next_sig(psig);
2303
+ }
2304
+ switch (pm->basic.result_signature)
2305
+ {
2306
+ case 'D':
2307
+ {
2308
+ INVOKEAD voked = *(INVOKEAD*)(((char*)*jenv) + pm->method);
2309
+ jv.d = voked(jenv, ptr->obj, pm->basic.id, args);
2310
+ }
2311
+ break;
2312
+ case 'Z':
2313
+ case 'B':
2314
+ {
2315
+ INVOKEAZ vokez = *(INVOKEAZ*)(((char*)*jenv) + pm->method);
2316
+ jv.z = vokez(jenv, ptr->obj, pm->basic.id, args);
2317
+ }
2318
+ break;
2319
+ case 'F':
2320
+ {
2321
+ INVOKEAF vokef = *(INVOKEAF*)(((char*)*jenv) + pm->method);
2322
+ jv.f = vokef(jenv, ptr->obj, pm->basic.id, args);
2323
+ }
2324
+ break;
2325
+ case 'C':
2326
+ case 'S':
2327
+ {
2328
+ INVOKEAS vokes = *(INVOKEAS*)(((char*)*jenv) + pm->method);
2329
+ jv.s = vokes(jenv, ptr->obj, pm->basic.id, args);
2330
+ }
2331
+ break;
2332
+ #if HAVE_LONG_LONG
2333
+ case 'J':
2334
+ {
2335
+ INVOKEAL vokel = *(INVOKEAL*)(((char*)*jenv) + pm->method);
2336
+ jv.j = vokel(jenv, ptr->obj, pm->basic.id, args);
2337
+ }
2338
+ break;
2339
+ #endif
2340
+ default:
2341
+ {
2342
+ INVOKEA voke = *(INVOKEA*)(((char*)*jenv) + pm->method);
2343
+ jv.l = voke(jenv, ptr->obj, pm->basic.id, args);
2344
+ }
2345
+ break;
2346
+ }
2347
+ check_exception(jenv, 1);
2348
+ psig = pm->basic.method_signature;
2349
+ for (i = 0; i < argc; i++)
2350
+ {
2351
+ R2J pr2j = *(pm->basic.arg_convert + i);
2352
+ pr2j(jenv, argv[i], args + i, psig, 1);
2353
+ psig = next_sig(psig);
2354
+ }
2355
+ if (pm->basic.result_arraydepth)
2356
+ {
2357
+ return ja2r(pm->result_convert, jenv, jv, pm->basic.result_arraydepth);
2358
+ }
2359
+ else
2360
+ {
2361
+ return pm->result_convert(jenv, jv);
2362
+ }
2363
+ }
2364
+
2365
+ /*
2366
+ * Object invocation
2367
+ */
2368
+ static VALUE invoke_by_instance(ID rmid, int argc, VALUE* argv,
2369
+ struct jvi_data* ptr, char* sig)
2370
+ {
2371
+ VALUE ret = Qnil;
2372
+ JNIEnv* jenv = attach_current_thread();
2373
+ struct cls_field* pf;
2374
+ struct cls_method* pm;
2375
+ char* tname = rb_id2name(rmid);
2376
+
2377
+ if (argc == 0 && st_lookup(ptr->fields, rmid, (st_data_t*)&pf))
2378
+ {
2379
+ ret = getter(jenv, pf, ptr);
2380
+ }
2381
+ else if (argc == 1 && *(tname + strlen(tname) - 1) == '=')
2382
+ {
2383
+ char* fname = ALLOCA_N(char, strlen(tname) + 1);
2384
+ strcpy(fname, tname);
2385
+ fname[strlen(tname) - 1] = '\0';
2386
+ if (st_lookup(ptr->fields, rb_intern(fname), (st_data_t*)&pf))
2387
+ {
2388
+ setter(jenv, pf, ptr, *argv);
2389
+ }
2390
+ else
2391
+ {
2392
+ rb_raise(rb_eRuntimeError, "Fail: unknown field name `%s'", fname);
2393
+ }
2394
+ }
2395
+ else if (st_lookup(ptr->methods, rmid, (st_data_t*)&pm))
2396
+ {
2397
+ ret = invoke(jenv, pm, ptr, argc, argv, sig);
2398
+ }
2399
+ else
2400
+ {
2401
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname);
2402
+ }
2403
+ return ret;
2404
+ }
2405
+
2406
+ static VALUE rjb_i_invoke(int argc, VALUE* argv, VALUE self)
2407
+ {
2408
+ VALUE vsig, rmid, rest;
2409
+ char* sig;
2410
+ struct jvi_data* ptr;
2411
+
2412
+ rb_scan_args(argc, argv, "2*", &rmid, &vsig, &rest);
2413
+ rmid = rb_to_id(rmid);
2414
+ sig = StringValueCStr(vsig);
2415
+ Data_Get_Struct(self, struct jvi_data, ptr);
2416
+
2417
+ return invoke_by_instance(rmid, argc -2, argv + 2, ptr, sig);
2418
+ }
2419
+
2420
+ static VALUE rjb_i_missing(int argc, VALUE* argv, VALUE self)
2421
+ {
2422
+ struct jvi_data* ptr;
2423
+ ID rmid = rb_to_id(argv[0]);
2424
+
2425
+ Data_Get_Struct(self, struct jvi_data, ptr);
2426
+
2427
+ return invoke_by_instance(rmid, argc -1, argv + 1, ptr, NULL);
2428
+ }
2429
+
2430
+ /*
2431
+ * Class invocation (first static method, then instance method)
2432
+ */
2433
+ static VALUE invoke_by_class(ID rmid, int argc, VALUE* argv,
2434
+ struct jv_data* ptr, char* sig)
2435
+ {
2436
+ VALUE ret = Qnil;
2437
+ struct jv_data* clsptr;
2438
+ struct cls_field* pf;
2439
+ struct cls_method* pm;
2440
+ char* tname = rb_id2name(rmid);
2441
+ JNIEnv* jenv = attach_current_thread();
2442
+
2443
+ Data_Get_Struct(jklass, struct jv_data, clsptr);
2444
+ if (argc == 0 && st_lookup(ptr->idata.fields, rmid, (st_data_t*)&pf))
2445
+ {
2446
+ if (!pf->static_field)
2447
+ {
2448
+ rb_raise(rb_eRuntimeError, "instance field `%s' for class", tname);
2449
+ }
2450
+ ret = getter(jenv, pf, &ptr->idata);
2451
+ }
2452
+ else if (argc == 1 && *(tname + strlen(tname) - 1) == '=')
2453
+ {
2454
+ char* fname = ALLOCA_N(char, strlen(tname) + 1);
2455
+ strcpy(fname, tname);
2456
+ fname[strlen(tname) - 1] = '\0';
2457
+ if (st_lookup(ptr->idata.fields, rb_intern(fname), (st_data_t*)&pf))
2458
+ {
2459
+ if (!pf->static_field)
2460
+ {
2461
+ rb_raise(rb_eRuntimeError, "instance field `%s' for class", fname);
2462
+ }
2463
+ setter(jenv, pf, &ptr->idata, *argv);
2464
+ }
2465
+ else
2466
+ {
2467
+ rb_raise(rb_eRuntimeError, "Fail: unknown field name `%s'", fname);
2468
+ }
2469
+ }
2470
+ else if (st_lookup(ptr->static_methods, rmid, (st_data_t*)&pm))
2471
+ {
2472
+ ret = invoke(jenv, pm, &ptr->idata, argc, argv, sig);
2473
+ }
2474
+ else if (st_lookup(clsptr->idata.methods, rmid, (st_data_t*)&pm))
2475
+ {
2476
+ ret = invoke(jenv, pm, &ptr->idata, argc, argv, sig);
2477
+ }
2478
+ else
2479
+ {
2480
+ if (st_lookup(ptr->idata.methods, rmid, (st_data_t*)&pm))
2481
+ {
2482
+ rb_raise(rb_eRuntimeError, "instance method `%s' for class", tname);
2483
+ }
2484
+ else
2485
+ {
2486
+ rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname);
2487
+ }
2488
+ }
2489
+
2490
+ return ret;
2491
+ }
2492
+
2493
+ static VALUE rjb_invoke(int argc, VALUE* argv, VALUE self)
2494
+ {
2495
+ VALUE vsig, rmid, rest;
2496
+ char* sig;
2497
+ struct jv_data* ptr;
2498
+
2499
+ rb_scan_args(argc, argv, "2*", &rmid, &vsig, &rest);
2500
+ rmid = rb_to_id(rmid);
2501
+ sig = StringValueCStr(vsig);
2502
+ Data_Get_Struct(self, struct jv_data, ptr);
2503
+
2504
+ return invoke_by_class(rmid, argc - 2, argv + 2, ptr, sig);
2505
+ }
2506
+
2507
+ static VALUE find_const(VALUE pv)
2508
+ {
2509
+ VALUE* p = (VALUE*)pv;
2510
+ return rb_const_get(*p, (ID)*(p + 1));
2511
+ }
2512
+
2513
+ static VALUE rjb_missing(int argc, VALUE* argv, VALUE self)
2514
+ {
2515
+ struct jv_data* ptr;
2516
+ ID rmid = rb_to_id(argv[0]);
2517
+ char* rmname = rb_id2name(rmid);
2518
+ if (isupper(*rmname))
2519
+ {
2520
+ VALUE r, args[2];
2521
+ int state = 0;
2522
+ args[0] = RBASIC(self)->klass;
2523
+ args[1] = rmid;
2524
+ r = rb_protect(find_const, (VALUE)args, &state);
2525
+ if (!state)
2526
+ {
2527
+ return r;
2528
+ }
2529
+ }
2530
+
2531
+ Data_Get_Struct(self, struct jv_data, ptr);
2532
+ return invoke_by_class(rmid, argc - 1, argv + 1, ptr, NULL);
2533
+ }
2534
+
2535
+ /*
2536
+ * Class#forName entry.
2537
+ */
2538
+ static VALUE rjb_class_forname(int argc, VALUE* argv, VALUE self)
2539
+ {
2540
+ if (argc == 1)
2541
+ {
2542
+ return rjb_s_import(self, *argv);
2543
+ }
2544
+ else
2545
+ {
2546
+ struct jv_data* ptr;
2547
+ ID rmid = rb_intern("forName");
2548
+ Data_Get_Struct(self, struct jv_data, ptr);
2549
+ return invoke_by_class(rmid, argc, argv, ptr, NULL);
2550
+ }
2551
+ }
2552
+
2553
+ /*
2554
+ * Class initializer called by Ruby while requiring this library
2555
+ */
2556
+ void Init_rjbcore()
2557
+ {
2558
+ rb_protect((VALUE(*)(VALUE))rb_require, (VALUE)"iconv", NULL);
2559
+
2560
+ loaded_classes = rb_hash_new();
2561
+ OBJ_FREEZE(loaded_classes);
2562
+ rb_global_variable(&loaded_classes);
2563
+ proxies = rb_ary_new();
2564
+ rb_global_variable(&proxies);
2565
+
2566
+ rjb = rb_define_module("Rjb");
2567
+ rb_define_module_function(rjb, "load", rjb_s_load, -1);
2568
+ rb_define_module_function(rjb, "unload", rjb_s_unload, -1);
2569
+ rb_define_module_function(rjb, "import", rjb_s_import, 1);
2570
+ rb_define_module_function(rjb, "bind", rjb_s_bind, 2);
2571
+ rb_define_module_function(rjb, "classes", rjb_s_classes, 0);
2572
+ rb_define_module_function(rjb, "throw", rjb_s_throw, -1);
2573
+ rb_define_const(rjb, "VERSION", rb_str_new2(RJB_VERSION));
2574
+
2575
+ /* Java class object */
2576
+ rjbc = rb_class_new(rb_cObject);
2577
+ rb_gc_register_address(&rjbc);
2578
+ rb_define_method(rjbc, "method_missing", rjb_missing, -1);
2579
+ rb_define_method(rjbc, "_invoke", rjb_invoke, -1);
2580
+ rb_define_method(rjbc, "_classname", rjb_i_class, 0);
2581
+
2582
+ /* Java instance object */
2583
+ rjbi = rb_class_new(rb_cObject);
2584
+ rb_gc_register_address(&rjbi);
2585
+ rb_define_method(rjbi, "method_missing", rjb_i_missing, -1);
2586
+ rb_define_method(rjbi, "_invoke", rjb_i_invoke, -1);
2587
+ rb_define_method(rjbi, "_classname", rjb_i_class, 0);
2588
+
2589
+ /* Ruby-Java Bridge object */
2590
+ rjbb = rb_class_new(rb_cObject);
2591
+ rb_gc_register_address(&rjbb);
2592
+ }
2593
+
2594
+ static VALUE safe_funcall(VALUE args)
2595
+ {
2596
+ VALUE* argp = (VALUE*)args;
2597
+ return rb_funcall2(*argp, *(argp + 1), *(argp + 2), argp + 3);
2598
+ }
2599
+
2600
+ /**
2601
+ Entry point from JavaVM through java.reflect.Proxy
2602
+ */
2603
+ JNIEXPORT jobject JNICALL Java_jp_co_infoseek_hp_arton_rjb_RBridge_call
2604
+ (JNIEnv * jenv, jobject bridge, jstring name, jobject proxy, jobjectArray args)
2605
+ {
2606
+ int i;
2607
+ jvalue j;
2608
+ memset(&j, 0, sizeof(j));
2609
+
2610
+ for (i = 0; i < RARRAY(proxies)->len; i++)
2611
+ {
2612
+ struct rj_bridge* ptr;
2613
+ VALUE val = RARRAY(proxies)->ptr[i];
2614
+ Data_Get_Struct(val, struct rj_bridge, ptr);
2615
+ if ((*jenv)->IsSameObject(jenv, proxy, ptr->proxy))
2616
+ {
2617
+ int sstat;
2618
+ VALUE result;
2619
+ VALUE* argv = NULL;
2620
+ int argc = 3;
2621
+ ID id = rb_to_id(jstring2val(jenv, name));
2622
+ if (args)
2623
+ {
2624
+ int i;
2625
+ jsize js = (*jenv)->GetArrayLength(jenv, args);
2626
+ argc += (int)js;
2627
+ argv = ALLOCA_N(VALUE, argc);
2628
+ memset(argv, 0, sizeof(VALUE*) * argc);
2629
+ for (i = 3; i < argc; i++)
2630
+ {
2631
+ jobject f = (*jenv)->GetObjectArrayElement(jenv, args, i - 3);
2632
+ /* f will be release in jv2rv_withprim */
2633
+ *(argv + i) = jv2rv_withprim(jenv, f);
2634
+ }
2635
+ }
2636
+ else
2637
+ {
2638
+ argv = ALLOCA_N(VALUE, argc + 1);
2639
+ memset(argv, 0, sizeof(VALUE*) * (argc + 1));
2640
+ }
2641
+ *argv = ptr->wrapped;
2642
+ *(argv + 1) = id;
2643
+ *(argv + 2) = argc - 3;
2644
+ result = rb_protect(safe_funcall, (VALUE)argv, &sstat);
2645
+ rv2jobject(jenv, result, &j, NULL, 0);
2646
+ // I can't delete this object...
2647
+ break;
2648
+ }
2649
+ }
2650
+ return j.l;
2651
+ }