• 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 #include "JavaInstanceV8.h"
30 #include "JavaNPObjectV8.h"
31 #include "npruntime_impl.h"
32 
33 namespace JSC {
34 
35 namespace Bindings {
36 
convertNPVariantToJValue(NPVariant value,JNIType jniType,const char * javaClassName)37 jvalue convertNPVariantToJValue(NPVariant value, JNIType jniType, const char* javaClassName)
38 {
39     jvalue result;
40     NPVariantType type = value.type;
41 
42     switch (jniType) {
43     case array_type:
44         {
45             JNIEnv* env = getJNIEnv();
46             jobject javaArray;
47             NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0;
48             NPVariant npvLength;
49             bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength);
50             if (!success) {
51                 // No length property so we don't know how many elements to put into the array.
52                 // Treat this as an error.
53 #ifdef EMULATE_JSC_BINDINGS
54                 // JSC sends null for an array that is not an array of strings or basic types,
55                 // do this also in the unknown length case.
56                 memset(&result, 0, sizeof(jvalue));
57 #else
58                 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
59                 // for the length of the array it was passed). Here we send a 0 length array.
60                 jclass objectClass = env->FindClass("java/lang/Object");
61                 javaArray = env->NewObjectArray(0, objectClass, 0);
62                 env->DeleteLocalRef(objectClass);
63 #endif
64                 break;
65             }
66 
67             jsize length = static_cast<jsize>(NPVARIANT_TO_INT32(npvLength));
68 
69             if (!strcmp(javaClassName, "[Ljava.lang.String;")) {
70                 // Match JSC behavior by only allowing Object arrays if they are Strings.
71                 jclass stringClass = env->FindClass("java/lang/String");
72                 javaArray = env->NewObjectArray(length, stringClass, 0);
73                 for (jsize i = 0; i < length; i++) {
74                     NPVariant npvValue;
75                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
76                     if(NPVARIANT_IS_STRING(npvValue)) {
77                         NPString str = NPVARIANT_TO_STRING(npvValue);
78                         env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters));
79                     }
80                 }
81 
82                 env->DeleteLocalRef(stringClass);
83             } else if (!strcmp(javaClassName, "[B")) {
84                 // array of bytes
85                 javaArray = env->NewByteArray(length);
86                 // Now iterate over each element and add to the array.
87                 for (jsize i = 0; i < length; i++) {
88                     NPVariant npvValue;
89                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
90                     if (NPVARIANT_IS_INT32(npvValue)) {
91                         jbyte bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue));
92                         env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal);
93                     }
94                 }
95              } else if (!strcmp(javaClassName, "[C")) {
96                 // array of chars
97                 javaArray = env->NewCharArray(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                     jchar cVal = 0;
103                     if (NPVARIANT_IS_INT32(npvValue)) {
104                         cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue));
105                     } else if (NPVARIANT_IS_STRING(npvValue)) {
106                         NPString str = NPVARIANT_TO_STRING(npvValue);
107                         cVal = str.UTF8Characters[0];
108                     }
109                     env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal);
110                 }
111              } else if (!strcmp(javaClassName, "[D")) {
112                 // array of doubles
113                 javaArray = env->NewDoubleArray(length);
114                 // Now iterate over each element and add to the array.
115                 for (jsize i = 0; i < length; i++) {
116                     NPVariant npvValue;
117                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
118                     if (NPVARIANT_IS_DOUBLE(npvValue)) {
119                         jdouble dVal = NPVARIANT_TO_DOUBLE(npvValue);
120                         env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray), i, 1, &dVal);
121                     }
122                 }
123              } else if (!strcmp(javaClassName, "[F")) {
124                 // array of floats
125                 javaArray = env->NewFloatArray(length);
126                 // Now iterate over each element and add to the array.
127                 for (jsize i = 0; i < length; i++) {
128                     NPVariant npvValue;
129                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
130                     if (NPVARIANT_IS_DOUBLE(npvValue)) {
131                         jfloat fVal = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(npvValue));
132                         env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray), i, 1, &fVal);
133                     }
134                 }
135              } else if (!strcmp(javaClassName, "[I")) {
136                 // array of ints
137                 javaArray = env->NewIntArray(length);
138                 // Now iterate over each element and add to the array.
139                 for (jsize i = 0; i < length; i++) {
140                     NPVariant npvValue;
141                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
142                     if (NPVARIANT_IS_INT32(npvValue)) {
143                         jint iVal = NPVARIANT_TO_INT32(npvValue);
144                         env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal);
145                     }
146                 }
147              } else if (!strcmp(javaClassName, "[J")) {
148                 // array of longs
149                 javaArray = env->NewLongArray(length);
150                 // Now iterate over each element and add to the array.
151                 for (jsize i = 0; i < length; i++) {
152                     NPVariant npvValue;
153                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
154                     if (NPVARIANT_IS_INT32(npvValue)) {
155                         jlong jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue));
156                         env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal);
157                     }
158                 }
159              } else if (!strcmp(javaClassName, "[S")) {
160                 // array of shorts
161                 javaArray = env->NewShortArray(length);
162                 // Now iterate over each element and add to the array.
163                 for (jsize i = 0; i < length; i++) {
164                     NPVariant npvValue;
165                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
166                     if (NPVARIANT_IS_INT32(npvValue)) {
167                         jshort sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue));
168                         env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal);
169                     }
170                 }
171              } else if (!strcmp(javaClassName, "[Z")) {
172                 // array of booleans
173                 javaArray = env->NewBooleanArray(length);
174                 // Now iterate over each element and add to the array.
175                 for (jsize i = 0; i < length; i++) {
176                     NPVariant npvValue;
177                     _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
178                     if (NPVARIANT_IS_BOOLEAN(npvValue)) {
179                         jboolean zVal = NPVARIANT_TO_BOOLEAN(npvValue);
180                         env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray), i, 1, &zVal);
181                     }
182                 }
183             } else {
184 #ifdef EMULATE_JSC_BINDINGS
185                 // JSC sends null for an array that is not an array of strings or basic types.
186                 memset(&result, 0, sizeof(jvalue));
187                 break;
188 #else
189                 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
190                 // for the length of the array it was passed). Here we send a 0 length array.
191                 jclass objectClass = env->FindClass("java/lang/Object");
192                 javaArray = env->NewObjectArray(0, objectClass, 0);
193                 env->DeleteLocalRef(objectClass);
194 #endif
195             }
196 
197             result.l = javaArray;
198         }
199         break;
200 
201     case object_type:
202         {
203             JNIEnv* env = getJNIEnv();
204             result.l = static_cast<jobject>(0);
205             jobject javaString;
206 
207             // First see if we have a Java instance.
208             if (type == NPVariantType_Object) {
209                 NPObject* objectImp = NPVARIANT_TO_OBJECT(value);
210                 if (JavaInstance* instance = ExtractJavaInstance(objectImp))
211                     result.l = instance->javaInstance();
212             }
213 
214             // Now convert value to a string if the target type is a java.lang.string, and we're not
215             // converting from a Null.
216             if (!result.l && !strcmp(javaClassName, "java.lang.String")) {
217 #ifdef CONVERT_NULL_TO_EMPTY_STRING
218                 if (type == NPVariantType_Null) {
219                     jchar buf[2];
220                     jobject javaString = env->functions->NewString(env, buf, 0);
221                     result.l = javaString;
222                 } else
223 #else
224                 if (type == NPVariantType_String)
225 #endif
226                 {
227                     NPString src = NPVARIANT_TO_STRING(value);
228                     javaString = env->NewStringUTF(src.UTF8Characters);
229                     result.l = javaString;
230                 } else if (type == NPVariantType_Int32) {
231                     jint src = NPVARIANT_TO_INT32(value);
232                     jclass integerClass = env->FindClass("java/lang/Integer");
233                     jmethodID toString = env->GetStaticMethodID(integerClass, "toString", "(I)Ljava/lang/String;");
234                     javaString = env->CallStaticObjectMethod(integerClass, toString, src);
235                     result.l = javaString;
236                     env->DeleteLocalRef(integerClass);
237                 } else if (type == NPVariantType_Bool) {
238                     jboolean src = NPVARIANT_TO_BOOLEAN(value);
239                     jclass booleanClass = env->FindClass("java/lang/Boolean");
240                     jmethodID toString = env->GetStaticMethodID(booleanClass, "toString", "(Z)Ljava/lang/String;");
241                     javaString = env->CallStaticObjectMethod(booleanClass, toString, src);
242                     result.l = javaString;
243                     env->DeleteLocalRef(booleanClass);
244                 } else if (type == NPVariantType_Double) {
245                     jdouble src = NPVARIANT_TO_DOUBLE(value);
246                     jclass doubleClass = env->FindClass("java/lang/Double");
247                     jmethodID toString = env->GetStaticMethodID(doubleClass, "toString", "(D)Ljava/lang/String;");
248                     javaString = env->CallStaticObjectMethod(doubleClass, toString, src);
249                     result.l = javaString;
250                     env->DeleteLocalRef(doubleClass);
251                 }
252 #ifdef EMULATE_JSC_BINDINGS
253                 // For the undefined value, JSC sends the String "undefined". Feels to me like we
254                 // should send null in this case.
255                 else if (!NPVARIANT_IS_NULL(value)) {
256                   javaString = env->NewStringUTF("undefined");
257                   result.l = javaString;
258                 }
259 #endif
260             } else if (!result.l)
261                 memset(&result, 0, sizeof(jvalue)); // Handle it the same as a void case
262         }
263         break;
264 
265     case boolean_type:
266         {
267             if (type == NPVariantType_Bool)
268                 result.z = NPVARIANT_TO_BOOLEAN(value);
269             else
270                 memset(&result, 0, sizeof(jvalue)); // as void case
271         }
272         break;
273 
274     case byte_type:
275         {
276             if (type == NPVariantType_Int32)
277                 result.b = static_cast<char>(NPVARIANT_TO_INT32(value));
278             else
279                 memset(&result, 0, sizeof(jvalue));
280         }
281         break;
282 
283     case char_type:
284         {
285             if (type == NPVariantType_Int32)
286                 result.c = static_cast<char>(NPVARIANT_TO_INT32(value));
287 #ifndef EMULATE_JSC_BINDINGS
288             // There is no char type in JavaScript - just strings 1 character
289             // long. So just converting it to an int above doesn't work. Again,
290             // we emulate the behavior for now for maximum compatability.
291             else if (type == NPVariantType_String) {
292                 NPString str = NPVARIANT_TO_STRING(value);
293                 result.c = str.UTF8Characters[0];
294             }
295 #endif
296             else
297                 memset(&result, 0, sizeof(jvalue));
298         }
299         break;
300 
301     case short_type:
302         {
303             if (type == NPVariantType_Int32)
304                 result.s = static_cast<jshort>(NPVARIANT_TO_INT32(value));
305             else
306                 memset(&result, 0, sizeof(jvalue));
307         }
308         break;
309 
310     case int_type:
311         {
312             if (type == NPVariantType_Int32)
313                 result.i = static_cast<jint>(NPVARIANT_TO_INT32(value));
314             else
315                 memset(&result, 0, sizeof(jvalue));
316         }
317         break;
318 
319     case long_type:
320         {
321             if (type == NPVariantType_Int32)
322                 result.j = static_cast<jlong>(NPVARIANT_TO_INT32(value));
323             else if (type == NPVariantType_Double)
324                 result.j = static_cast<jlong>(NPVARIANT_TO_DOUBLE(value));
325             else
326                 memset(&result, 0, sizeof(jvalue));
327         }
328         break;
329 
330     case float_type:
331         {
332             if (type == NPVariantType_Int32)
333                 result.f = static_cast<jfloat>(NPVARIANT_TO_INT32(value));
334             else if (type == NPVariantType_Double)
335                 result.f = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(value));
336             else
337                 memset(&result, 0, sizeof(jvalue));
338         }
339         break;
340 
341     case double_type:
342         {
343             if (type == NPVariantType_Int32)
344                 result.d = static_cast<jdouble>(NPVARIANT_TO_INT32(value));
345             else if (type == NPVariantType_Double)
346                 result.d = static_cast<jdouble>(NPVARIANT_TO_DOUBLE(value));
347             else
348                 memset(&result, 0, sizeof(jvalue));
349         }
350         break;
351 
352     case invalid_type:
353     default:
354     case void_type:
355         {
356             memset(&result, 0, sizeof(jvalue));
357         }
358         break;
359     }
360     return result;
361 }
362 
363 
convertJValueToNPVariant(jvalue value,JNIType jniType,const char * javaTypeName,NPVariant * result)364 void convertJValueToNPVariant(jvalue value, JNIType jniType, const char* javaTypeName, NPVariant* result)
365 {
366     switch (jniType) {
367     case void_type:
368         {
369             VOID_TO_NPVARIANT(*result);
370         }
371         break;
372 
373     case object_type:
374         {
375             if (value.l) {
376                 if (!strcmp(javaTypeName, "java.lang.String")) {
377                     const char* v = getCharactersFromJString(static_cast<jstring>(value.l));
378                     // s is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
379                     const char* s = strdup(v);
380                     releaseCharactersForJString(static_cast<jstring>(value.l), v);
381                     STRINGZ_TO_NPVARIANT(s, *result);
382                 } else
383                     OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(new JavaInstance(value.l)), *result);
384             } else
385                 VOID_TO_NPVARIANT(*result);
386         }
387         break;
388 
389     case boolean_type:
390         {
391             BOOLEAN_TO_NPVARIANT(value.z, *result);
392         }
393         break;
394 
395     case byte_type:
396         {
397             INT32_TO_NPVARIANT(value.b, *result);
398         }
399         break;
400 
401     case char_type:
402         {
403 #ifndef EMULATE_JSC_BINDINGS
404             // There is no char type in JavaScript - just strings 1 character
405             // long. So just converting it to an int above doesn't work. Again,
406             // we emulate the behavior for now for maximum compatability.
407             if (!strcmp(javaTypeName, "char")) {
408                 const char c = value.c;
409                 const char* v = strndup(&c, 1);
410                 STRINGZ_TO_NPVARIANT(v, *result);
411             } else
412 #endif
413                 INT32_TO_NPVARIANT(value.c, *result);
414         }
415         break;
416 
417     case short_type:
418         {
419             INT32_TO_NPVARIANT(value.s, *result);
420         }
421         break;
422 
423     case int_type:
424         {
425             INT32_TO_NPVARIANT(value.i, *result);
426         }
427         break;
428 
429         // TODO: Check if cast to double is needed.
430     case long_type:
431         {
432             DOUBLE_TO_NPVARIANT(value.j, *result);
433         }
434         break;
435 
436     case float_type:
437         {
438             DOUBLE_TO_NPVARIANT(value.f, *result);
439         }
440         break;
441 
442     case double_type:
443         {
444             DOUBLE_TO_NPVARIANT(value.d, *result);
445         }
446         break;
447 
448     case invalid_type:
449     default:
450         {
451             VOID_TO_NPVARIANT(*result);
452         }
453         break;
454     }
455 }
456 
457 } // end of namespace Bindings
458 
459 } // end of namespace JSC
460