1 /*
2 * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "jni_utility.h"
28
29 #if ENABLE(MAC_JAVA_BRIDGE)
30
31 #include "jni_runtime.h"
32 #include "runtime_array.h"
33 #include "runtime_object.h"
34 #include <runtime/JSArray.h>
35 #include <runtime/JSLock.h>
36 #include <dlfcn.h>
37
38 namespace JSC {
39
40 namespace Bindings {
41
KJS_GetCreatedJavaVMs(JavaVM ** vmBuf,jsize bufLen,jsize * nVMs)42 static jint KJS_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
43 {
44 static void* javaVMFramework = 0;
45 if (!javaVMFramework)
46 javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY);
47 if (!javaVMFramework)
48 return JNI_ERR;
49
50 static jint(*functionPointer)(JavaVM**, jsize, jsize *) = 0;
51 if (!functionPointer)
52 functionPointer = (jint(*)(JavaVM**, jsize, jsize *))dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs");
53 if (!functionPointer)
54 return JNI_ERR;
55 return functionPointer(vmBuf, bufLen, nVMs);
56 }
57
58 static JavaVM *jvm = 0;
59
60 // Provide the ability for an outside component to specify the JavaVM to use
61 // If the jvm value is set, the getJavaVM function below will just return.
62 // In getJNIEnv(), if AttachCurrentThread is called to a VM that is already
63 // attached, the result is a no-op.
setJavaVM(JavaVM * javaVM)64 void setJavaVM(JavaVM *javaVM)
65 {
66 jvm = javaVM;
67 }
68
getJavaVM()69 JavaVM *getJavaVM()
70 {
71 if (jvm)
72 return jvm;
73
74 JavaVM *jvmArray[1];
75 jsize bufLen = 1;
76 jsize nJVMs = 0;
77 jint jniError = 0;
78
79 // Assumes JVM is already running ..., one per process
80 jniError = KJS_GetCreatedJavaVMs(jvmArray, bufLen, &nJVMs);
81 if ( jniError == JNI_OK && nJVMs > 0 ) {
82 jvm = jvmArray[0];
83 }
84 else
85 fprintf(stderr, "%s: JNI_GetCreatedJavaVMs failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError);
86
87 return jvm;
88 }
89
getJNIEnv()90 JNIEnv* getJNIEnv()
91 {
92 union {
93 JNIEnv* env;
94 void* dummy;
95 } u;
96 jint jniError = 0;
97
98 jniError = (getJavaVM())->AttachCurrentThread(&u.dummy, NULL);
99 if (jniError == JNI_OK)
100 return u.env;
101 else
102 fprintf(stderr, "%s: AttachCurrentThread failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError);
103 return NULL;
104 }
105
getMethodID(jobject obj,const char * name,const char * sig)106 jmethodID getMethodID (jobject obj, const char *name, const char *sig)
107 {
108 JNIEnv *env = getJNIEnv();
109 jmethodID mid = 0;
110
111 if ( env != NULL) {
112 jclass cls = env->GetObjectClass(obj);
113 if ( cls != NULL ) {
114 mid = env->GetMethodID(cls, name, sig);
115 if (!mid) {
116 env->ExceptionClear();
117 mid = env->GetStaticMethodID(cls, name, sig);
118 if (!mid) {
119 env->ExceptionClear();
120 }
121 }
122 }
123 env->DeleteLocalRef(cls);
124 }
125 return mid;
126 }
127
getCharactersFromJString(jstring aJString)128 const char *getCharactersFromJString (jstring aJString)
129 {
130 return getCharactersFromJStringInEnv (getJNIEnv(), aJString);
131 }
132
releaseCharactersForJString(jstring aJString,const char * s)133 void releaseCharactersForJString (jstring aJString, const char *s)
134 {
135 releaseCharactersForJStringInEnv (getJNIEnv(), aJString, s);
136 }
137
getCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)138 const char *getCharactersFromJStringInEnv (JNIEnv *env, jstring aJString)
139 {
140 jboolean isCopy;
141 const char *s = env->GetStringUTFChars((jstring)aJString, &isCopy);
142 if (!s) {
143 env->ExceptionDescribe();
144 env->ExceptionClear();
145 fprintf (stderr, "\n");
146 }
147 return s;
148 }
149
releaseCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const char * s)150 void releaseCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const char *s)
151 {
152 env->ReleaseStringUTFChars (aJString, s);
153 }
154
getUCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)155 const jchar *getUCharactersFromJStringInEnv (JNIEnv *env, jstring aJString)
156 {
157 jboolean isCopy;
158 const jchar *s = env->GetStringChars((jstring)aJString, &isCopy);
159 if (!s) {
160 env->ExceptionDescribe();
161 env->ExceptionClear();
162 fprintf (stderr, "\n");
163 }
164 return s;
165 }
166
releaseUCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const jchar * s)167 void releaseUCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const jchar *s)
168 {
169 env->ReleaseStringChars (aJString, s);
170 }
171
JNITypeFromClassName(const char * name)172 JNIType JNITypeFromClassName(const char *name)
173 {
174 JNIType type;
175
176 if (strcmp("byte",name) == 0)
177 type = byte_type;
178 else if (strcmp("short",name) == 0)
179 type = short_type;
180 else if (strcmp("int",name) == 0)
181 type = int_type;
182 else if (strcmp("long",name) == 0)
183 type = long_type;
184 else if (strcmp("float",name) == 0)
185 type = float_type;
186 else if (strcmp("double",name) == 0)
187 type = double_type;
188 else if (strcmp("char",name) == 0)
189 type = char_type;
190 else if (strcmp("boolean",name) == 0)
191 type = boolean_type;
192 else if (strcmp("void",name) == 0)
193 type = void_type;
194 else if ('[' == name[0])
195 type = array_type;
196 else
197 type = object_type;
198
199 return type;
200 }
201
signatureFromPrimitiveType(JNIType type)202 const char *signatureFromPrimitiveType(JNIType type)
203 {
204 switch (type){
205 case void_type:
206 return "V";
207
208 case array_type:
209 return "[";
210
211 case object_type:
212 return "L";
213
214 case boolean_type:
215 return "Z";
216
217 case byte_type:
218 return "B";
219
220 case char_type:
221 return "C";
222
223 case short_type:
224 return "S";
225
226 case int_type:
227 return "I";
228
229 case long_type:
230 return "J";
231
232 case float_type:
233 return "F";
234
235 case double_type:
236 return "D";
237
238 case invalid_type:
239 default:
240 break;
241 }
242 return "";
243 }
244
JNITypeFromPrimitiveType(char type)245 JNIType JNITypeFromPrimitiveType(char type)
246 {
247 switch (type){
248 case 'V':
249 return void_type;
250
251 case 'L':
252 return object_type;
253
254 case '[':
255 return array_type;
256
257 case 'Z':
258 return boolean_type;
259
260 case 'B':
261 return byte_type;
262
263 case 'C':
264 return char_type;
265
266 case 'S':
267 return short_type;
268
269 case 'I':
270 return int_type;
271
272 case 'J':
273 return long_type;
274
275 case 'F':
276 return float_type;
277
278 case 'D':
279 return double_type;
280
281 default:
282 break;
283 }
284 return invalid_type;
285 }
286
getJNIField(jobject obj,JNIType type,const char * name,const char * signature)287 jvalue getJNIField( jobject obj, JNIType type, const char *name, const char *signature)
288 {
289 JavaVM *jvm = getJavaVM();
290 JNIEnv *env = getJNIEnv();
291 jvalue result;
292
293 bzero (&result, sizeof(jvalue));
294 if ( obj != NULL && jvm != NULL && env != NULL) {
295 jclass cls = env->GetObjectClass(obj);
296 if ( cls != NULL ) {
297 jfieldID field = env->GetFieldID(cls, name, signature);
298 if ( field != NULL ) {
299 switch (type) {
300 case array_type:
301 case object_type:
302 result.l = env->functions->GetObjectField(env, obj, field);
303 break;
304 case boolean_type:
305 result.z = env->functions->GetBooleanField(env, obj, field);
306 break;
307 case byte_type:
308 result.b = env->functions->GetByteField(env, obj, field);
309 break;
310 case char_type:
311 result.c = env->functions->GetCharField(env, obj, field);
312 break;
313 case short_type:
314 result.s = env->functions->GetShortField(env, obj, field);
315 break;
316 case int_type:
317 result.i = env->functions->GetIntField(env, obj, field);
318 break;
319 case long_type:
320 result.j = env->functions->GetLongField(env, obj, field);
321 break;
322 case float_type:
323 result.f = env->functions->GetFloatField(env, obj, field);
324 break;
325 case double_type:
326 result.d = env->functions->GetDoubleField(env, obj, field);
327 break;
328 default:
329 fprintf(stderr, "%s: invalid field type (%d)\n", __PRETTY_FUNCTION__, (int)type);
330 }
331 }
332 else
333 {
334 fprintf(stderr, "%s: Could not find field: %s\n", __PRETTY_FUNCTION__, name);
335 env->ExceptionDescribe();
336 env->ExceptionClear();
337 fprintf (stderr, "\n");
338 }
339
340 env->DeleteLocalRef(cls);
341 }
342 else {
343 fprintf(stderr, "%s: Could not find class for object\n", __PRETTY_FUNCTION__);
344 }
345 }
346
347 return result;
348 }
349
convertArrayInstanceToJavaArray(ExecState * exec,JSArray * jsArray,const char * javaClassName)350 static jobject convertArrayInstanceToJavaArray(ExecState* exec, JSArray* jsArray, const char* javaClassName)
351 {
352 JNIEnv *env = getJNIEnv();
353 // As JS Arrays can contain a mixture of objects, assume we can convert to
354 // the requested Java Array type requested, unless the array type is some object array
355 // other than a string.
356 unsigned length = jsArray->length();
357 jobjectArray jarray = 0;
358
359 // Build the correct array type
360 switch (JNITypeFromPrimitiveType(javaClassName[1])) {
361 case object_type: {
362 // Only support string object types
363 if (0 == strcmp("[Ljava.lang.String;", javaClassName)) {
364 jarray = (jobjectArray)env->NewObjectArray(length,
365 env->FindClass("java/lang/String"),
366 env->NewStringUTF(""));
367 for(unsigned i = 0; i < length; i++) {
368 JSValuePtr item = jsArray->get(exec, i);
369 UString stringValue = item.toString(exec);
370 env->SetObjectArrayElement(jarray,i,
371 env->functions->NewString(env, (const jchar *)stringValue.data(), stringValue.size()));
372 }
373 }
374 break;
375 }
376
377 case boolean_type: {
378 jarray = (jobjectArray)env->NewBooleanArray(length);
379 for(unsigned i = 0; i < length; i++) {
380 JSValuePtr item = jsArray->get(exec, i);
381 jboolean value = (jboolean)item.toNumber(exec);
382 env->SetBooleanArrayRegion((jbooleanArray)jarray, (jsize)i, (jsize)1, &value);
383 }
384 break;
385 }
386
387 case byte_type: {
388 jarray = (jobjectArray)env->NewByteArray(length);
389 for(unsigned i = 0; i < length; i++) {
390 JSValuePtr item = jsArray->get(exec, i);
391 jbyte value = (jbyte)item.toNumber(exec);
392 env->SetByteArrayRegion((jbyteArray)jarray, (jsize)i, (jsize)1, &value);
393 }
394 break;
395 }
396
397 case char_type: {
398 jarray = (jobjectArray)env->NewCharArray(length);
399 for(unsigned i = 0; i < length; i++) {
400 JSValuePtr item = jsArray->get(exec, i);
401 UString stringValue = item.toString(exec);
402 jchar value = 0;
403 if (stringValue.size() > 0)
404 value = ((const jchar*)stringValue.data())[0];
405 env->SetCharArrayRegion((jcharArray)jarray, (jsize)i, (jsize)1, &value);
406 }
407 break;
408 }
409
410 case short_type: {
411 jarray = (jobjectArray)env->NewShortArray(length);
412 for(unsigned i = 0; i < length; i++) {
413 JSValuePtr item = jsArray->get(exec, i);
414 jshort value = (jshort)item.toNumber(exec);
415 env->SetShortArrayRegion((jshortArray)jarray, (jsize)i, (jsize)1, &value);
416 }
417 break;
418 }
419
420 case int_type: {
421 jarray = (jobjectArray)env->NewIntArray(length);
422 for(unsigned i = 0; i < length; i++) {
423 JSValuePtr item = jsArray->get(exec, i);
424 jint value = (jint)item.toNumber(exec);
425 env->SetIntArrayRegion((jintArray)jarray, (jsize)i, (jsize)1, &value);
426 }
427 break;
428 }
429
430 case long_type: {
431 jarray = (jobjectArray)env->NewLongArray(length);
432 for(unsigned i = 0; i < length; i++) {
433 JSValuePtr item = jsArray->get(exec, i);
434 jlong value = (jlong)item.toNumber(exec);
435 env->SetLongArrayRegion((jlongArray)jarray, (jsize)i, (jsize)1, &value);
436 }
437 break;
438 }
439
440 case float_type: {
441 jarray = (jobjectArray)env->NewFloatArray(length);
442 for(unsigned i = 0; i < length; i++) {
443 JSValuePtr item = jsArray->get(exec, i);
444 jfloat value = (jfloat)item.toNumber(exec);
445 env->SetFloatArrayRegion((jfloatArray)jarray, (jsize)i, (jsize)1, &value);
446 }
447 break;
448 }
449
450 case double_type: {
451 jarray = (jobjectArray)env->NewDoubleArray(length);
452 for(unsigned i = 0; i < length; i++) {
453 JSValuePtr item = jsArray->get(exec, i);
454 jdouble value = (jdouble)item.toNumber(exec);
455 env->SetDoubleArrayRegion((jdoubleArray)jarray, (jsize)i, (jsize)1, &value);
456 }
457 break;
458 }
459
460 case array_type: // don't handle embedded arrays
461 case void_type: // Don't expect arrays of void objects
462 case invalid_type: // Array of unknown objects
463 break;
464 }
465
466 // if it was not one of the cases handled, then null is returned
467 return jarray;
468 }
469
470
convertValueToJValue(ExecState * exec,JSValuePtr value,JNIType _JNIType,const char * javaClassName)471 jvalue convertValueToJValue(ExecState* exec, JSValuePtr value, JNIType _JNIType, const char* javaClassName)
472 {
473 JSLock lock(false);
474
475 jvalue result;
476
477 switch (_JNIType){
478 case array_type:
479 case object_type: {
480 result.l = (jobject)0;
481
482 // First see if we have a Java instance.
483 if (value.isObject()){
484 JSObject* objectImp = asObject(value);
485 if (objectImp->classInfo() == &RuntimeObjectImp::s_info) {
486 RuntimeObjectImp* imp = static_cast<RuntimeObjectImp*>(objectImp);
487 JavaInstance *instance = static_cast<JavaInstance*>(imp->getInternalInstance());
488 if (instance)
489 result.l = instance->javaInstance();
490 }
491 else if (objectImp->classInfo() == &RuntimeArray::s_info) {
492 // Input is a JavaScript Array that was originally created from a Java Array
493 RuntimeArray* imp = static_cast<RuntimeArray*>(objectImp);
494 JavaArray *array = static_cast<JavaArray*>(imp->getConcreteArray());
495 result.l = array->javaArray();
496 }
497 else if (objectImp->classInfo() == &JSArray::info) {
498 // Input is a Javascript Array. We need to create it to a Java Array.
499 result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName);
500 }
501 }
502
503 // Now convert value to a string if the target type is a java.lang.string, and we're not
504 // converting from a Null.
505 if (result.l == 0 && strcmp(javaClassName, "java.lang.String") == 0) {
506 #ifdef CONVERT_NULL_TO_EMPTY_STRING
507 if (value->isNull()) {
508 JNIEnv *env = getJNIEnv();
509 jchar buf[2];
510 jobject javaString = env->functions->NewString (env, buf, 0);
511 result.l = javaString;
512 }
513 else
514 #else
515 if (!value.isNull())
516 #endif
517 {
518 UString stringValue = value.toString(exec);
519 JNIEnv *env = getJNIEnv();
520 jobject javaString = env->functions->NewString (env, (const jchar *)stringValue.data(), stringValue.size());
521 result.l = javaString;
522 }
523 } else if (result.l == 0)
524 bzero (&result, sizeof(jvalue)); // Handle it the same as a void case
525 }
526 break;
527
528 case boolean_type: {
529 result.z = (jboolean)value.toNumber(exec);
530 }
531 break;
532
533 case byte_type: {
534 result.b = (jbyte)value.toNumber(exec);
535 }
536 break;
537
538 case char_type: {
539 result.c = (jchar)value.toNumber(exec);
540 }
541 break;
542
543 case short_type: {
544 result.s = (jshort)value.toNumber(exec);
545 }
546 break;
547
548 case int_type: {
549 result.i = (jint)value.toNumber(exec);
550 }
551 break;
552
553 case long_type: {
554 result.j = (jlong)value.toNumber(exec);
555 }
556 break;
557
558 case float_type: {
559 result.f = (jfloat)value.toNumber(exec);
560 }
561 break;
562
563 case double_type: {
564 result.d = (jdouble)value.toNumber(exec);
565 }
566 break;
567
568 break;
569
570 case invalid_type:
571 default:
572 case void_type: {
573 bzero (&result, sizeof(jvalue));
574 }
575 break;
576 }
577 return result;
578 }
579
580 } // end of namespace Bindings
581
582 } // end of namespace JSC
583
584 #endif // ENABLE(MAC_JAVA_BRIDGE)
585