1 /*
2 * Copyright 2010, The Android Open Source Project
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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 "JNIUtilityPrivate.h"
28
29 #if ENABLE(JAVA_BRIDGE)
30
31 #include "JavaInstanceJobjectV8.h"
32 #include "JavaNPObjectV8.h"
33 #if PLATFORM(ANDROID)
34 #include "npruntime_impl.h"
35 #endif // PLATFORM(ANDROID)
36 #include "JavaValueV8.h"
37 #include <wtf/text/CString.h>
38
39 namespace JSC {
40
41 namespace Bindings {
42
convertNPVariantToJavaValue(NPVariant value,const String & javaClass)43 JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
44 {
45 CString javaClassName = javaClass.utf8();
46 JavaType javaType = javaTypeFromClassName(javaClassName.data());
47 JavaValue result;
48 result.m_type = javaType;
49 NPVariantType type = value.type;
50
51 switch (javaType) {
52 case JavaTypeArray:
53 #if PLATFORM(ANDROID)
54 // If we're converting to an array, see if the NPVariant has a length
55 // property. If so, create a JNI array of the relevant length and to get
56 // the elements of the NPVariant. When we interpret the JavaValue later,
57 // we know that the array is represented as a JNI array.
58 //
59 // FIXME: This is a hack. We should not be using JNI here. We should
60 // represent the JavaValue without JNI.
61 {
62 JNIEnv* env = getJNIEnv();
63 jobject javaArray;
64 NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0;
65 NPVariant npvLength;
66 bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength);
67 if (!success) {
68 // No length property so we don't know how many elements to put into the array.
69 // Treat this as an error.
70 // JSC sends null for an array that is not an array of strings or basic types,
71 // do this also in the unknown length case.
72 break;
73 }
74
75 jsize length = 0;
76 if (NPVARIANT_IS_INT32(npvLength))
77 length = static_cast<jsize>(NPVARIANT_TO_INT32(npvLength));
78 else if (NPVARIANT_IS_DOUBLE(npvLength))
79 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(npvLength));
80
81 if (!strcmp(javaClassName.data(), "[Ljava.lang.String;")) {
82 // Match JSC behavior by only allowing Object arrays if they are Strings.
83 jclass stringClass = env->FindClass("java/lang/String");
84 javaArray = env->NewObjectArray(length, stringClass, 0);
85 for (jsize i = 0; i < length; i++) {
86 NPVariant npvValue;
87 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
88 if(NPVARIANT_IS_STRING(npvValue)) {
89 NPString str = NPVARIANT_TO_STRING(npvValue);
90 env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters));
91 }
92 }
93
94 env->DeleteLocalRef(stringClass);
95 } else if (!strcmp(javaClassName.data(), "[B")) {
96 // array of bytes
97 javaArray = env->NewByteArray(length);
98 // Now iterate over each element and add to the array.
99 for (jsize i = 0; i < length; i++) {
100 NPVariant npvValue;
101 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
102 jbyte bVal = 0;
103 if (NPVARIANT_IS_INT32(npvValue)) {
104 bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue));
105 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
106 bVal = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(npvValue));
107 }
108 env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal);
109 }
110 } else if (!strcmp(javaClassName.data(), "[C")) {
111 // array of chars
112 javaArray = env->NewCharArray(length);
113 // Now iterate over each element and add to the array.
114 for (jsize i = 0; i < length; i++) {
115 NPVariant npvValue;
116 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
117 jchar cVal = 0;
118 if (NPVARIANT_IS_INT32(npvValue)) {
119 cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue));
120 } else if (NPVARIANT_IS_STRING(npvValue)) {
121 NPString str = NPVARIANT_TO_STRING(npvValue);
122 cVal = str.UTF8Characters[0];
123 }
124 env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal);
125 }
126 } else if (!strcmp(javaClassName.data(), "[D")) {
127 // array of doubles
128 javaArray = env->NewDoubleArray(length);
129 // Now iterate over each element and add to the array.
130 for (jsize i = 0; i < length; i++) {
131 NPVariant npvValue;
132 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
133 if (NPVARIANT_IS_DOUBLE(npvValue)) {
134 jdouble dVal = NPVARIANT_TO_DOUBLE(npvValue);
135 env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray), i, 1, &dVal);
136 }
137 }
138 } else if (!strcmp(javaClassName.data(), "[F")) {
139 // array of floats
140 javaArray = env->NewFloatArray(length);
141 // Now iterate over each element and add to the array.
142 for (jsize i = 0; i < length; i++) {
143 NPVariant npvValue;
144 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
145 if (NPVARIANT_IS_DOUBLE(npvValue)) {
146 jfloat fVal = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(npvValue));
147 env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray), i, 1, &fVal);
148 }
149 }
150 } else if (!strcmp(javaClassName.data(), "[I")) {
151 // array of ints
152 javaArray = env->NewIntArray(length);
153 // Now iterate over each element and add to the array.
154 for (jsize i = 0; i < length; i++) {
155 NPVariant npvValue;
156 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
157 jint iVal = 0;
158 if (NPVARIANT_IS_INT32(npvValue)) {
159 iVal = NPVARIANT_TO_INT32(npvValue);
160 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
161 iVal = static_cast<jint>(NPVARIANT_TO_DOUBLE(npvValue));
162 }
163 env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal);
164 }
165 } else if (!strcmp(javaClassName.data(), "[J")) {
166 // array of longs
167 javaArray = env->NewLongArray(length);
168 // Now iterate over each element and add to the array.
169 for (jsize i = 0; i < length; i++) {
170 NPVariant npvValue;
171 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
172 jlong jVal = 0;
173 if (NPVARIANT_IS_INT32(npvValue)) {
174 jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue));
175 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
176 jVal = static_cast<jlong>(NPVARIANT_TO_DOUBLE(npvValue));
177 }
178 env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal);
179 }
180 } else if (!strcmp(javaClassName.data(), "[S")) {
181 // array of shorts
182 javaArray = env->NewShortArray(length);
183 // Now iterate over each element and add to the array.
184 for (jsize i = 0; i < length; i++) {
185 NPVariant npvValue;
186 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
187 jshort sVal = 0;
188 if (NPVARIANT_IS_INT32(npvValue)) {
189 sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue));
190 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
191 sVal = static_cast<jshort>(NPVARIANT_TO_DOUBLE(npvValue));
192 }
193 env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal);
194 }
195 } else if (!strcmp(javaClassName.data(), "[Z")) {
196 // array of booleans
197 javaArray = env->NewBooleanArray(length);
198 // Now iterate over each element and add to the array.
199 for (jsize i = 0; i < length; i++) {
200 NPVariant npvValue;
201 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
202 if (NPVARIANT_IS_BOOLEAN(npvValue)) {
203 jboolean zVal = NPVARIANT_TO_BOOLEAN(npvValue);
204 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray), i, 1, &zVal);
205 }
206 }
207 } else {
208 // JSC sends null for an array that is not an array of strings or basic types.
209 break;
210 }
211
212 result.m_objectValue = adoptRef(new JavaInstanceJobject(javaArray));
213 env->DeleteLocalRef(javaArray);
214 }
215 break;
216 #endif // PLATFORM(ANDROID)
217
218 case JavaTypeObject:
219 {
220 // See if we have a Java instance.
221 if (type == NPVariantType_Object) {
222 NPObject* objectImp = NPVARIANT_TO_OBJECT(value);
223 result.m_objectValue = ExtractJavaInstance(objectImp);
224 }
225 }
226 break;
227
228 case JavaTypeString:
229 {
230 #ifdef CONVERT_NULL_TO_EMPTY_STRING
231 if (type == NPVariantType_Null) {
232 result.m_type = JavaTypeString;
233 result.m_stringValue = String::fromUTF8("");
234 } else
235 #else
236 if (type == NPVariantType_String)
237 #endif
238 {
239 NPString src = NPVARIANT_TO_STRING(value);
240 result.m_type = JavaTypeString;
241 result.m_stringValue = String::fromUTF8(src.UTF8Characters);
242 }
243 #if PLATFORM(ANDROID)
244 else if (type == NPVariantType_Int32) {
245 result.m_type = JavaTypeString;
246 result.m_stringValue = String::number(NPVARIANT_TO_INT32(value));
247 } else if (type == NPVariantType_Bool) {
248 result.m_type = JavaTypeString;
249 result.m_stringValue = NPVARIANT_TO_BOOLEAN(value) ? "true" : "false";
250 } else if (type == NPVariantType_Double) {
251 result.m_type = JavaTypeString;
252 result.m_stringValue = String::number(NPVARIANT_TO_DOUBLE(value));
253 } else if (!NPVARIANT_IS_NULL(value)) {
254 result.m_type = JavaTypeString;
255 result.m_stringValue = "undefined";
256 }
257 #endif // PLATFORM(ANDROID)
258 }
259 break;
260
261 case JavaTypeBoolean:
262 {
263 if (type == NPVariantType_Bool)
264 result.m_booleanValue = NPVARIANT_TO_BOOLEAN(value);
265 }
266 break;
267
268 case JavaTypeByte:
269 {
270 if (type == NPVariantType_Int32)
271 result.m_byteValue = static_cast<signed char>(NPVARIANT_TO_INT32(value));
272 else if (type == NPVariantType_Double)
273 result.m_byteValue = static_cast<signed char>(NPVARIANT_TO_DOUBLE(value));
274 }
275 break;
276
277 case JavaTypeChar:
278 {
279 if (type == NPVariantType_Int32)
280 result.m_charValue = static_cast<unsigned short>(NPVARIANT_TO_INT32(value));
281 }
282 break;
283
284 case JavaTypeShort:
285 {
286 if (type == NPVariantType_Int32)
287 result.m_shortValue = static_cast<short>(NPVARIANT_TO_INT32(value));
288 else if (type == NPVariantType_Double)
289 result.m_shortValue = static_cast<short>(NPVARIANT_TO_DOUBLE(value));
290 }
291 break;
292
293 case JavaTypeInt:
294 {
295 if (type == NPVariantType_Int32)
296 result.m_intValue = static_cast<int>(NPVARIANT_TO_INT32(value));
297 else if (type == NPVariantType_Double)
298 result.m_intValue = static_cast<int>(NPVARIANT_TO_DOUBLE(value));
299 }
300 break;
301
302 case JavaTypeLong:
303 {
304 if (type == NPVariantType_Int32)
305 result.m_longValue = static_cast<long long>(NPVARIANT_TO_INT32(value));
306 else if (type == NPVariantType_Double)
307 result.m_longValue = static_cast<long long>(NPVARIANT_TO_DOUBLE(value));
308 }
309 break;
310
311 case JavaTypeFloat:
312 {
313 if (type == NPVariantType_Int32)
314 result.m_floatValue = static_cast<float>(NPVARIANT_TO_INT32(value));
315 else if (type == NPVariantType_Double)
316 result.m_floatValue = static_cast<float>(NPVARIANT_TO_DOUBLE(value));
317 }
318 break;
319
320 case JavaTypeDouble:
321 {
322 if (type == NPVariantType_Int32)
323 result.m_doubleValue = static_cast<double>(NPVARIANT_TO_INT32(value));
324 else if (type == NPVariantType_Double)
325 result.m_doubleValue = static_cast<double>(NPVARIANT_TO_DOUBLE(value));
326 }
327 break;
328 default:
329 break;
330 }
331 return result;
332 }
333
334
convertJavaValueToNPVariant(JavaValue value,NPVariant * result)335 void convertJavaValueToNPVariant(JavaValue value, NPVariant* result)
336 {
337 switch (value.m_type) {
338 case JavaTypeVoid:
339 {
340 VOID_TO_NPVARIANT(*result);
341 }
342 break;
343
344 case JavaTypeObject:
345 {
346 // If the JavaValue is a String object, it should have type JavaTypeString.
347 if (value.m_objectValue)
348 OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(value.m_objectValue.get()), *result);
349 else
350 VOID_TO_NPVARIANT(*result);
351 }
352 break;
353
354 case JavaTypeString:
355 {
356 #if PLATFORM(ANDROID)
357 // This entire file will likely be removed usptream soon.
358 if (value.m_stringValue.isNull()) {
359 VOID_TO_NPVARIANT(*result);
360 break;
361 }
362 #endif
363 const char* utf8String = strdup(value.m_stringValue.utf8().data());
364 // The copied string is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
365 STRINGZ_TO_NPVARIANT(utf8String, *result);
366 }
367 break;
368
369 case JavaTypeBoolean:
370 {
371 BOOLEAN_TO_NPVARIANT(value.m_booleanValue, *result);
372 }
373 break;
374
375 case JavaTypeByte:
376 {
377 INT32_TO_NPVARIANT(value.m_byteValue, *result);
378 }
379 break;
380
381 case JavaTypeChar:
382 {
383 INT32_TO_NPVARIANT(value.m_charValue, *result);
384 }
385 break;
386
387 case JavaTypeShort:
388 {
389 INT32_TO_NPVARIANT(value.m_shortValue, *result);
390 }
391 break;
392
393 case JavaTypeInt:
394 {
395 INT32_TO_NPVARIANT(value.m_intValue, *result);
396 }
397 break;
398
399 // TODO: Check if cast to double is needed.
400 case JavaTypeLong:
401 {
402 DOUBLE_TO_NPVARIANT(value.m_longValue, *result);
403 }
404 break;
405
406 case JavaTypeFloat:
407 {
408 DOUBLE_TO_NPVARIANT(value.m_floatValue, *result);
409 }
410 break;
411
412 case JavaTypeDouble:
413 {
414 DOUBLE_TO_NPVARIANT(value.m_doubleValue, *result);
415 }
416 break;
417
418 case JavaTypeInvalid:
419 default:
420 {
421 VOID_TO_NPVARIANT(*result);
422 }
423 break;
424 }
425 }
426
jvalueToJavaValue(const jvalue & value,const JavaType & type)427 JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type)
428 {
429 JavaValue result;
430 result.m_type = type;
431 switch (result.m_type) {
432 case JavaTypeVoid:
433 break;
434 case JavaTypeObject:
435 result.m_objectValue = new JavaInstanceJobject(value.l);
436 break;
437 case JavaTypeString:
438 {
439 jstring javaString = static_cast<jstring>(value.l);
440 if (!javaString) {
441 // result.m_stringValue is null by default
442 break;
443 }
444 const UChar* characters = getUCharactersFromJStringInEnv(getJNIEnv(), javaString);
445 // We take a copy to allow the Java String to be released.
446 result.m_stringValue = String(characters, getJNIEnv()->GetStringLength(javaString));
447 releaseUCharactersForJStringInEnv(getJNIEnv(), javaString, characters);
448 }
449 break;
450 case JavaTypeBoolean:
451 result.m_booleanValue = value.z == JNI_FALSE ? false : true;
452 break;
453 case JavaTypeByte:
454 result.m_byteValue = value.b;
455 break;
456 case JavaTypeChar:
457 result.m_charValue = value.c;
458 break;
459 case JavaTypeShort:
460 result.m_shortValue = value.s;
461 break;
462 case JavaTypeInt:
463 result.m_intValue = value.i;
464 break;
465 case JavaTypeLong:
466 result.m_longValue = value.j;
467 break;
468 case JavaTypeFloat:
469 result.m_floatValue = value.f;
470 break;
471 case JavaTypeDouble:
472 result.m_doubleValue = value.d;
473 break;
474 default:
475 ASSERT(false);
476 }
477 return result;
478 }
479
javaValueToJvalue(const JavaValue & value)480 jvalue javaValueToJvalue(const JavaValue& value)
481 {
482 jvalue result;
483 memset(&result, 0, sizeof(jvalue));
484 switch (value.m_type) {
485 case JavaTypeVoid:
486 break;
487 #if PLATFORM(ANDROID)
488 case JavaTypeArray:
489 #endif
490 case JavaTypeObject:
491 if (value.m_objectValue) {
492 // This method is used only by JavaInstanceJobject, so we know the
493 // derived type of the object.
494 result.l = static_cast<JavaInstanceJobject*>(value.m_objectValue.get())->javaInstance();
495 }
496 break;
497 case JavaTypeString:
498 // This creates a local reference to a new String object, which will
499 // be released when the call stack returns to Java. Note that this
500 // may cause leaks if invoked from a native message loop, as is the
501 // case in workers.
502 if (value.m_stringValue.isNull()) {
503 // result.l is null by default.
504 break;
505 }
506 result.l = getJNIEnv()->NewString(value.m_stringValue.characters(), value.m_stringValue.length());
507 break;
508 case JavaTypeBoolean:
509 result.z = value.m_booleanValue ? JNI_TRUE : JNI_FALSE;
510 break;
511 case JavaTypeByte:
512 result.b = value.m_byteValue;
513 break;
514 case JavaTypeChar:
515 result.c = value.m_charValue;
516 break;
517 case JavaTypeShort:
518 result.s = value.m_shortValue;
519 break;
520 case JavaTypeInt:
521 result.i = value.m_intValue;
522 break;
523 case JavaTypeLong:
524 result.j = value.m_longValue;
525 break;
526 case JavaTypeFloat:
527 result.f = value.m_floatValue;
528 break;
529 case JavaTypeDouble:
530 result.d = value.m_doubleValue;
531 break;
532 default:
533 ASSERT(false);
534 }
535 return result;
536 }
537
538 } // namespace Bindings
539
540 } // namespace JSC
541
542 #endif // ENABLE(JAVA_BRIDGE)
543