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