• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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