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