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