rjb 1.0.0-mswin32

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }