rjb 1.4.7-x86-mswin32-100

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