• 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             // 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