JNIUtilityPrivate.cpp revision 81bc750723a18f21cd17d1b173cd2a4dda9cea6e
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 "JavaInstanceV8.h"
32#include "JavaNPObjectV8.h"
33<<<<<<< HEAD
34#include "npruntime_impl.h"
35=======
36#include <wtf/text/CString.h>
37>>>>>>> WebKit at r80534
38
39namespace JSC {
40
41namespace Bindings {
42
43jvalue convertNPVariantToJValue(NPVariant value, const WTF::String& javaType)
44{
45    CString javaClassName = javaType.utf8();
46    JNIType jniType = JNITypeFromClassName(javaClassName.data());
47    jvalue result;
48    NPVariantType type = value.type;
49
50    switch (jniType) {
51    case array_type:
52        {
53            JNIEnv* env = getJNIEnv();
54            jobject javaArray;
55            NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0;
56            NPVariant npvLength;
57            bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength);
58            if (!success) {
59                // No length property so we don't know how many elements to put into the array.
60                // Treat this as an error.
61#ifdef EMULATE_JSC_BINDINGS
62                // JSC sends null for an array that is not an array of strings or basic types,
63                // do this also in the unknown length case.
64                memset(&result, 0, sizeof(jvalue));
65#else
66                // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
67                // for the length of the array it was passed). Here we send a 0 length array.
68                jclass objectClass = env->FindClass("java/lang/Object");
69                javaArray = env->NewObjectArray(0, objectClass, 0);
70                env->DeleteLocalRef(objectClass);
71#endif
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, "[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, "[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, "[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, "[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, "[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, "[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, "[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, "[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, "[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#ifdef EMULATE_JSC_BINDINGS
209                // JSC sends null for an array that is not an array of strings or basic types.
210                memset(&result, 0, sizeof(jvalue));
211                break;
212#else
213                // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
214                // for the length of the array it was passed). Here we send a 0 length array.
215                jclass objectClass = env->FindClass("java/lang/Object");
216                javaArray = env->NewObjectArray(0, objectClass, 0);
217                env->DeleteLocalRef(objectClass);
218#endif
219            }
220
221            result.l = javaArray;
222        }
223        break;
224
225    case object_type:
226        {
227            JNIEnv* env = getJNIEnv();
228            result.l = static_cast<jobject>(0);
229            jobject javaString;
230
231            // First see if we have a Java instance.
232            if (type == NPVariantType_Object) {
233                NPObject* objectImp = NPVARIANT_TO_OBJECT(value);
234                if (JavaInstance* instance = ExtractJavaInstance(objectImp))
235                    result.l = instance->javaInstance();
236            }
237
238            // Now convert value to a string if the target type is a java.lang.string, and we're not
239            // converting from a Null.
240            if (!result.l && !strcmp(javaClassName.data(), "java.lang.String")) {
241#ifdef CONVERT_NULL_TO_EMPTY_STRING
242                if (type == NPVariantType_Null) {
243                    jchar buf[2];
244                    jobject javaString = env->functions->NewString(env, buf, 0);
245                    result.l = javaString;
246                } else
247#else
248                if (type == NPVariantType_String)
249#endif
250                {
251                    NPString src = NPVARIANT_TO_STRING(value);
252                    javaString = env->NewStringUTF(src.UTF8Characters);
253                    result.l = javaString;
254                } else if (type == NPVariantType_Int32) {
255                    jint src = NPVARIANT_TO_INT32(value);
256                    jclass integerClass = env->FindClass("java/lang/Integer");
257                    jmethodID toString = env->GetStaticMethodID(integerClass, "toString", "(I)Ljava/lang/String;");
258                    javaString = env->CallStaticObjectMethod(integerClass, toString, src);
259                    result.l = javaString;
260                    env->DeleteLocalRef(integerClass);
261                } else if (type == NPVariantType_Bool) {
262                    jboolean src = NPVARIANT_TO_BOOLEAN(value);
263                    jclass booleanClass = env->FindClass("java/lang/Boolean");
264                    jmethodID toString = env->GetStaticMethodID(booleanClass, "toString", "(Z)Ljava/lang/String;");
265                    javaString = env->CallStaticObjectMethod(booleanClass, toString, src);
266                    result.l = javaString;
267                    env->DeleteLocalRef(booleanClass);
268                } else if (type == NPVariantType_Double) {
269                    jdouble src = NPVARIANT_TO_DOUBLE(value);
270                    jclass doubleClass = env->FindClass("java/lang/Double");
271                    jmethodID toString = env->GetStaticMethodID(doubleClass, "toString", "(D)Ljava/lang/String;");
272                    javaString = env->CallStaticObjectMethod(doubleClass, toString, src);
273                    result.l = javaString;
274                    env->DeleteLocalRef(doubleClass);
275                }
276#ifdef EMULATE_JSC_BINDINGS
277                // For the undefined value, JSC sends the String "undefined". Feels to me like we
278                // should send null in this case.
279                else if (!NPVARIANT_IS_NULL(value)) {
280                  javaString = env->NewStringUTF("undefined");
281                  result.l = javaString;
282                }
283#endif
284            } else if (!result.l)
285                memset(&result, 0, sizeof(jvalue)); // Handle it the same as a void case
286        }
287        break;
288
289    case boolean_type:
290        {
291            if (type == NPVariantType_Bool)
292                result.z = NPVARIANT_TO_BOOLEAN(value);
293            else
294                memset(&result, 0, sizeof(jvalue)); // as void case
295        }
296        break;
297
298    case byte_type:
299        {
300            if (type == NPVariantType_Int32)
301                result.b = static_cast<jbyte>(NPVARIANT_TO_INT32(value));
302            else if (type == NPVariantType_Double)
303                result.b = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(value));
304            else
305                memset(&result, 0, sizeof(jvalue));
306        }
307        break;
308
309    case char_type:
310        {
311            if (type == NPVariantType_Int32)
312                result.c = static_cast<char>(NPVARIANT_TO_INT32(value));
313#ifndef EMULATE_JSC_BINDINGS
314            // There is no char type in JavaScript - just strings 1 character
315            // long. So just converting it to an int above doesn't work. Again,
316            // we emulate the behavior for now for maximum compatability.
317            else if (type == NPVariantType_String) {
318                NPString str = NPVARIANT_TO_STRING(value);
319                result.c = str.UTF8Characters[0];
320            }
321#endif
322            else
323                memset(&result, 0, sizeof(jvalue));
324        }
325        break;
326
327    case short_type:
328        {
329            if (type == NPVariantType_Int32)
330                result.s = static_cast<jshort>(NPVARIANT_TO_INT32(value));
331            else if (type == NPVariantType_Double)
332                result.s = static_cast<jshort>(NPVARIANT_TO_DOUBLE(value));
333            else
334                memset(&result, 0, sizeof(jvalue));
335        }
336        break;
337
338    case int_type:
339        {
340            if (type == NPVariantType_Int32)
341                result.i = static_cast<jint>(NPVARIANT_TO_INT32(value));
342            else if (type == NPVariantType_Double)
343                result.i = static_cast<jint>(NPVARIANT_TO_DOUBLE(value));
344            else
345                memset(&result, 0, sizeof(jvalue));
346        }
347        break;
348
349    case long_type:
350        {
351            if (type == NPVariantType_Int32)
352                result.j = static_cast<jlong>(NPVARIANT_TO_INT32(value));
353            else if (type == NPVariantType_Double)
354                result.j = static_cast<jlong>(NPVARIANT_TO_DOUBLE(value));
355            else
356                memset(&result, 0, sizeof(jvalue));
357        }
358        break;
359
360    case float_type:
361        {
362            if (type == NPVariantType_Int32)
363                result.f = static_cast<jfloat>(NPVARIANT_TO_INT32(value));
364            else if (type == NPVariantType_Double)
365                result.f = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(value));
366            else
367                memset(&result, 0, sizeof(jvalue));
368        }
369        break;
370
371    case double_type:
372        {
373            if (type == NPVariantType_Int32)
374                result.d = static_cast<jdouble>(NPVARIANT_TO_INT32(value));
375            else if (type == NPVariantType_Double)
376                result.d = static_cast<jdouble>(NPVARIANT_TO_DOUBLE(value));
377            else
378                memset(&result, 0, sizeof(jvalue));
379        }
380        break;
381
382    case invalid_type:
383    default:
384    case void_type:
385        {
386            memset(&result, 0, sizeof(jvalue));
387        }
388        break;
389    }
390    return result;
391}
392
393
394void convertJValueToNPVariant(jvalue value, JNIType jniType, const char* javaTypeName, NPVariant* result)
395{
396    switch (jniType) {
397    case void_type:
398        {
399            VOID_TO_NPVARIANT(*result);
400        }
401        break;
402
403    case object_type:
404        {
405            if (value.l) {
406                if (!strcmp(javaTypeName, "java.lang.String")) {
407                    const char* v = getCharactersFromJString(static_cast<jstring>(value.l));
408                    // s is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
409                    const char* s = strdup(v);
410                    releaseCharactersForJString(static_cast<jstring>(value.l), v);
411                    STRINGZ_TO_NPVARIANT(s, *result);
412                } else
413                    OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(new JavaInstance(value.l)), *result);
414            } else
415                VOID_TO_NPVARIANT(*result);
416        }
417        break;
418
419    case boolean_type:
420        {
421            BOOLEAN_TO_NPVARIANT(value.z, *result);
422        }
423        break;
424
425    case byte_type:
426        {
427            INT32_TO_NPVARIANT(value.b, *result);
428        }
429        break;
430
431    case char_type:
432        {
433#ifndef EMULATE_JSC_BINDINGS
434            // There is no char type in JavaScript - just strings 1 character
435            // long. So just converting it to an int above doesn't work. Again,
436            // we emulate the behavior for now for maximum compatability.
437            if (!strcmp(javaTypeName, "char")) {
438                const char c = value.c;
439                const char* v = strndup(&c, 1);
440                STRINGZ_TO_NPVARIANT(v, *result);
441            } else
442#endif
443                INT32_TO_NPVARIANT(value.c, *result);
444        }
445        break;
446
447    case short_type:
448        {
449            INT32_TO_NPVARIANT(value.s, *result);
450        }
451        break;
452
453    case int_type:
454        {
455            INT32_TO_NPVARIANT(value.i, *result);
456        }
457        break;
458
459        // TODO: Check if cast to double is needed.
460    case long_type:
461        {
462            DOUBLE_TO_NPVARIANT(value.j, *result);
463        }
464        break;
465
466    case float_type:
467        {
468            DOUBLE_TO_NPVARIANT(value.f, *result);
469        }
470        break;
471
472    case double_type:
473        {
474            DOUBLE_TO_NPVARIANT(value.d, *result);
475        }
476        break;
477
478    case invalid_type:
479    default:
480        {
481            VOID_TO_NPVARIANT(*result);
482        }
483        break;
484    }
485}
486
487} // namespace Bindings
488
489} // namespace JSC
490
491#endif // ENABLE(JAVA_BRIDGE)
492