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 // Convert to null if the length property is not a number.
76 if (!NPVARIANT_IS_INT32(npvLength) && !NPVARIANT_IS_DOUBLE(npvLength))
77 break;
78
79 // Convert to null if the length property is out of bounds.
80 double doubleLength = NPVARIANT_IS_INT32(npvLength) ? NPVARIANT_TO_INT32(npvLength) : NPVARIANT_TO_DOUBLE(npvLength);
81 if (doubleLength < 0.0 || doubleLength > INT32_MAX)
82 break;
83
84 jsize length = static_cast<jsize>(doubleLength);
85
86 if (!strcmp(javaClassName.data(), "[Ljava.lang.String;")) {
87 // Match JSC behavior by only allowing Object arrays if they are Strings.
88 jclass stringClass = env->FindClass("java/lang/String");
89 javaArray = env->NewObjectArray(length, stringClass, 0);
90 for (jsize i = 0; i < length; i++) {
91 NPVariant npvValue;
92 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
93 if (NPVARIANT_IS_STRING(npvValue)) {
94 NPString str = NPVARIANT_TO_STRING(npvValue);
95 env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters));
96 }
97 }
98
99 env->DeleteLocalRef(stringClass);
100 } else if (!strcmp(javaClassName.data(), "[B")) {
101 // array of bytes
102 javaArray = env->NewByteArray(length);
103 // Now iterate over each element and add to the array.
104 for (jsize i = 0; i < length; i++) {
105 NPVariant npvValue;
106 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
107 jbyte bVal = 0;
108 if (NPVARIANT_IS_INT32(npvValue))
109 bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue));
110 else if (NPVARIANT_IS_DOUBLE(npvValue))
111 bVal = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(npvValue));
112 env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal);
113 }
114 } else if (!strcmp(javaClassName.data(), "[C")) {
115 // array of chars
116 javaArray = env->NewCharArray(length);
117 // Now iterate over each element and add to the array.
118 for (jsize i = 0; i < length; i++) {
119 NPVariant npvValue;
120 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
121 jchar cVal = 0;
122 if (NPVARIANT_IS_INT32(npvValue))
123 cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue));
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 env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal);
163 }
164 } else if (!strcmp(javaClassName.data(), "[J")) {
165 // array of longs
166 javaArray = env->NewLongArray(length);
167 // Now iterate over each element and add to the array.
168 for (jsize i = 0; i < length; i++) {
169 NPVariant npvValue;
170 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
171 jlong jVal = 0;
172 if (NPVARIANT_IS_INT32(npvValue))
173 jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue));
174 else if (NPVARIANT_IS_DOUBLE(npvValue))
175 jVal = static_cast<jlong>(NPVARIANT_TO_DOUBLE(npvValue));
176 env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal);
177 }
178 } else if (!strcmp(javaClassName.data(), "[S")) {
179 // array of shorts
180 javaArray = env->NewShortArray(length);
181 // Now iterate over each element and add to the array.
182 for (jsize i = 0; i < length; i++) {
183 NPVariant npvValue;
184 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
185 jshort sVal = 0;
186 if (NPVARIANT_IS_INT32(npvValue))
187 sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue));
188 else if (NPVARIANT_IS_DOUBLE(npvValue))
189 sVal = static_cast<jshort>(NPVARIANT_TO_DOUBLE(npvValue));
190 env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal);
191 }
192 } else if (!strcmp(javaClassName.data(), "[Z")) {
193 // array of booleans
194 javaArray = env->NewBooleanArray(length);
195 // Now iterate over each element and add to the array.
196 for (jsize i = 0; i < length; i++) {
197 NPVariant npvValue;
198 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
199 if (NPVARIANT_IS_BOOLEAN(npvValue)) {
200 jboolean zVal = NPVARIANT_TO_BOOLEAN(npvValue);
201 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray), i, 1, &zVal);
202 }
203 }
204 } else {
205 // JSC sends null for an array that is not an array of strings or basic types.
206 break;
207 }
208
209 result.m_objectValue = adoptRef(new JavaInstanceJobject(javaArray, false));
210 env->DeleteLocalRef(javaArray);
211 }
212 break;
213 #endif // PLATFORM(ANDROID)
214
215 case JavaTypeObject:
216 {
217 // See if we have a Java instance.
218 if (type == NPVariantType_Object) {
219 NPObject* objectImp = NPVARIANT_TO_OBJECT(value);
220 result.m_objectValue = ExtractJavaInstance(objectImp);
221 }
222 }
223 break;
224
225 case JavaTypeString:
226 {
227 #ifdef CONVERT_NULL_TO_EMPTY_STRING
228 if (type == NPVariantType_Null) {
229 result.m_type = JavaTypeString;
230 result.m_stringValue = String::fromUTF8("");
231 } else
232 #else
233 if (type == NPVariantType_String)
234 #endif
235 {
236 NPString src = NPVARIANT_TO_STRING(value);
237 result.m_type = JavaTypeString;
238 result.m_stringValue = String::fromUTF8(src.UTF8Characters);
239 }
240 #if PLATFORM(ANDROID)
241 else if (type == NPVariantType_Int32) {
242 result.m_type = JavaTypeString;
243 result.m_stringValue = String::number(NPVARIANT_TO_INT32(value));
244 } else if (type == NPVariantType_Bool) {
245 result.m_type = JavaTypeString;
246 result.m_stringValue = NPVARIANT_TO_BOOLEAN(value) ? "true" : "false";
247 } else if (type == NPVariantType_Double) {
248 result.m_type = JavaTypeString;
249 result.m_stringValue = String::number(NPVARIANT_TO_DOUBLE(value));
250 } else if (!NPVARIANT_IS_NULL(value)) {
251 result.m_type = JavaTypeString;
252 result.m_stringValue = "undefined";
253 }
254 #endif // PLATFORM(ANDROID)
255 }
256 break;
257
258 case JavaTypeBoolean:
259 {
260 if (type == NPVariantType_Bool)
261 result.m_booleanValue = NPVARIANT_TO_BOOLEAN(value);
262 }
263 break;
264
265 case JavaTypeByte:
266 {
267 if (type == NPVariantType_Int32)
268 result.m_byteValue = static_cast<signed char>(NPVARIANT_TO_INT32(value));
269 else if (type == NPVariantType_Double)
270 result.m_byteValue = static_cast<signed char>(NPVARIANT_TO_DOUBLE(value));
271 }
272 break;
273
274 case JavaTypeChar:
275 {
276 if (type == NPVariantType_Int32)
277 result.m_charValue = static_cast<unsigned short>(NPVARIANT_TO_INT32(value));
278 }
279 break;
280
281 case JavaTypeShort:
282 {
283 if (type == NPVariantType_Int32)
284 result.m_shortValue = static_cast<short>(NPVARIANT_TO_INT32(value));
285 else if (type == NPVariantType_Double)
286 result.m_shortValue = static_cast<short>(NPVARIANT_TO_DOUBLE(value));
287 }
288 break;
289
290 case JavaTypeInt:
291 {
292 if (type == NPVariantType_Int32)
293 result.m_intValue = static_cast<int>(NPVARIANT_TO_INT32(value));
294 else if (type == NPVariantType_Double)
295 result.m_intValue = static_cast<int>(NPVARIANT_TO_DOUBLE(value));
296 }
297 break;
298
299 case JavaTypeLong:
300 {
301 if (type == NPVariantType_Int32)
302 result.m_longValue = static_cast<long long>(NPVARIANT_TO_INT32(value));
303 else if (type == NPVariantType_Double)
304 result.m_longValue = static_cast<long long>(NPVARIANT_TO_DOUBLE(value));
305 }
306 break;
307
308 case JavaTypeFloat:
309 {
310 if (type == NPVariantType_Int32)
311 result.m_floatValue = static_cast<float>(NPVARIANT_TO_INT32(value));
312 else if (type == NPVariantType_Double)
313 result.m_floatValue = static_cast<float>(NPVARIANT_TO_DOUBLE(value));
314 }
315 break;
316
317 case JavaTypeDouble:
318 {
319 if (type == NPVariantType_Int32)
320 result.m_doubleValue = static_cast<double>(NPVARIANT_TO_INT32(value));
321 else if (type == NPVariantType_Double)
322 result.m_doubleValue = static_cast<double>(NPVARIANT_TO_DOUBLE(value));
323 }
324 break;
325 default:
326 break;
327 }
328 return result;
329 }
330
331
convertJavaValueToNPVariant(JavaValue value,NPVariant * result)332 void convertJavaValueToNPVariant(JavaValue value, NPVariant* result)
333 {
334 switch (value.m_type) {
335 case JavaTypeVoid:
336 {
337 VOID_TO_NPVARIANT(*result);
338 }
339 break;
340
341 case JavaTypeObject:
342 {
343 // If the JavaValue is a String object, it should have type JavaTypeString.
344 if (value.m_objectValue)
345 OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(value.m_objectValue.get()), *result);
346 else
347 VOID_TO_NPVARIANT(*result);
348 }
349 break;
350
351 case JavaTypeString:
352 {
353 #if PLATFORM(ANDROID)
354 // This entire file will likely be removed usptream soon.
355 if (value.m_stringValue.isNull()) {
356 VOID_TO_NPVARIANT(*result);
357 break;
358 }
359 #endif
360 const char* utf8String = strdup(value.m_stringValue.utf8().data());
361 // The copied string is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
362 STRINGZ_TO_NPVARIANT(utf8String, *result);
363 }
364 break;
365
366 case JavaTypeBoolean:
367 {
368 BOOLEAN_TO_NPVARIANT(value.m_booleanValue, *result);
369 }
370 break;
371
372 case JavaTypeByte:
373 {
374 INT32_TO_NPVARIANT(value.m_byteValue, *result);
375 }
376 break;
377
378 case JavaTypeChar:
379 {
380 INT32_TO_NPVARIANT(value.m_charValue, *result);
381 }
382 break;
383
384 case JavaTypeShort:
385 {
386 INT32_TO_NPVARIANT(value.m_shortValue, *result);
387 }
388 break;
389
390 case JavaTypeInt:
391 {
392 INT32_TO_NPVARIANT(value.m_intValue, *result);
393 }
394 break;
395
396 // TODO: Check if cast to double is needed.
397 case JavaTypeLong:
398 {
399 DOUBLE_TO_NPVARIANT(value.m_longValue, *result);
400 }
401 break;
402
403 case JavaTypeFloat:
404 {
405 DOUBLE_TO_NPVARIANT(value.m_floatValue, *result);
406 }
407 break;
408
409 case JavaTypeDouble:
410 {
411 DOUBLE_TO_NPVARIANT(value.m_doubleValue, *result);
412 }
413 break;
414
415 case JavaTypeInvalid:
416 default:
417 {
418 VOID_TO_NPVARIANT(*result);
419 }
420 break;
421 }
422 }
423
424 #if PLATFORM(ANDROID)
jvalueToJavaValue(const jvalue & value,const JavaType & type,bool requireAnnotation)425 JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type, bool requireAnnotation)
426 #else
427 JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type)
428 #endif
429 {
430 JavaValue result;
431 result.m_type = type;
432 switch (result.m_type) {
433 case JavaTypeVoid:
434 break;
435 case JavaTypeObject:
436 #if PLATFORM(ANDROID)
437 result.m_objectValue = new JavaInstanceJobject(value.l, requireAnnotation);
438 #else
439 result.m_objectValue = new JavaInstanceJobject(value.l);
440 #endif
441 break;
442 case JavaTypeString:
443 {
444 jstring javaString = static_cast<jstring>(value.l);
445 if (!javaString) {
446 // result.m_stringValue is null by default
447 break;
448 }
449 const UChar* characters = getUCharactersFromJStringInEnv(getJNIEnv(), javaString);
450 // We take a copy to allow the Java String to be released.
451 result.m_stringValue = String(characters, getJNIEnv()->GetStringLength(javaString));
452 releaseUCharactersForJStringInEnv(getJNIEnv(), javaString, characters);
453 }
454 break;
455 case JavaTypeBoolean:
456 result.m_booleanValue = value.z == JNI_FALSE ? false : true;
457 break;
458 case JavaTypeByte:
459 result.m_byteValue = value.b;
460 break;
461 case JavaTypeChar:
462 result.m_charValue = value.c;
463 break;
464 case JavaTypeShort:
465 result.m_shortValue = value.s;
466 break;
467 case JavaTypeInt:
468 result.m_intValue = value.i;
469 break;
470 case JavaTypeLong:
471 result.m_longValue = value.j;
472 break;
473 case JavaTypeFloat:
474 result.m_floatValue = value.f;
475 break;
476 case JavaTypeDouble:
477 result.m_doubleValue = value.d;
478 break;
479 default:
480 ASSERT(false);
481 }
482 return result;
483 }
484
javaValueToJvalue(const JavaValue & value)485 jvalue javaValueToJvalue(const JavaValue& value)
486 {
487 jvalue result;
488 memset(&result, 0, sizeof(jvalue));
489 switch (value.m_type) {
490 case JavaTypeVoid:
491 break;
492 #if PLATFORM(ANDROID)
493 case JavaTypeArray:
494 #endif
495 case JavaTypeObject:
496 if (value.m_objectValue) {
497 // This method is used only by JavaInstanceJobject, so we know the
498 // derived type of the object.
499 result.l = static_cast<JavaInstanceJobject*>(value.m_objectValue.get())->javaInstance();
500 }
501 break;
502 case JavaTypeString:
503 // This creates a local reference to a new String object, which will
504 // be released when the call stack returns to Java. Note that this
505 // may cause leaks if invoked from a native message loop, as is the
506 // case in workers.
507 if (value.m_stringValue.isNull()) {
508 // result.l is null by default.
509 break;
510 }
511 result.l = getJNIEnv()->NewString(value.m_stringValue.characters(), value.m_stringValue.length());
512 break;
513 case JavaTypeBoolean:
514 result.z = value.m_booleanValue ? JNI_TRUE : JNI_FALSE;
515 break;
516 case JavaTypeByte:
517 result.b = value.m_byteValue;
518 break;
519 case JavaTypeChar:
520 result.c = value.m_charValue;
521 break;
522 case JavaTypeShort:
523 result.s = value.m_shortValue;
524 break;
525 case JavaTypeInt:
526 result.i = value.m_intValue;
527 break;
528 case JavaTypeLong:
529 result.j = value.m_longValue;
530 break;
531 case JavaTypeFloat:
532 result.f = value.m_floatValue;
533 break;
534 case JavaTypeDouble:
535 result.d = value.m_doubleValue;
536 break;
537 default:
538 ASSERT(false);
539 }
540 return result;
541 }
542
543 } // namespace Bindings
544
545 } // namespace JSC
546
547 #endif // ENABLE(JAVA_BRIDGE)
548