JNIUtilityPrivate.cpp revision 698a253f5568db010beb93b2255697997d180406
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
39namespace JSC {
40
41namespace Bindings {
42
43JavaValue 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
335void 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            const char* utf8String = strdup(value.m_stringValue.utf8().data());
357            // The copied string is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
358            STRINGZ_TO_NPVARIANT(utf8String, *result);
359        }
360        break;
361
362    case JavaTypeBoolean:
363        {
364            BOOLEAN_TO_NPVARIANT(value.m_booleanValue, *result);
365        }
366        break;
367
368    case JavaTypeByte:
369        {
370            INT32_TO_NPVARIANT(value.m_byteValue, *result);
371        }
372        break;
373
374    case JavaTypeChar:
375        {
376            INT32_TO_NPVARIANT(value.m_charValue, *result);
377        }
378        break;
379
380    case JavaTypeShort:
381        {
382            INT32_TO_NPVARIANT(value.m_shortValue, *result);
383        }
384        break;
385
386    case JavaTypeInt:
387        {
388            INT32_TO_NPVARIANT(value.m_intValue, *result);
389        }
390        break;
391
392        // TODO: Check if cast to double is needed.
393    case JavaTypeLong:
394        {
395            DOUBLE_TO_NPVARIANT(value.m_longValue, *result);
396        }
397        break;
398
399    case JavaTypeFloat:
400        {
401            DOUBLE_TO_NPVARIANT(value.m_floatValue, *result);
402        }
403        break;
404
405    case JavaTypeDouble:
406        {
407            DOUBLE_TO_NPVARIANT(value.m_doubleValue, *result);
408        }
409        break;
410
411    case JavaTypeInvalid:
412    default:
413        {
414            VOID_TO_NPVARIANT(*result);
415        }
416        break;
417    }
418}
419
420JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type)
421{
422    JavaValue result;
423    result.m_type = type;
424    switch (result.m_type) {
425    case JavaTypeVoid:
426        break;
427    case JavaTypeObject:
428        result.m_objectValue = new JavaInstanceJobject(value.l);
429        break;
430    case JavaTypeString:
431        {
432            jstring javaString = static_cast<jstring>(value.l);
433            const UChar* characters = getUCharactersFromJStringInEnv(getJNIEnv(), javaString);
434            // We take a copy to allow the Java String to be released.
435            result.m_stringValue = String(characters, getJNIEnv()->GetStringLength(javaString));
436            releaseUCharactersForJStringInEnv(getJNIEnv(), javaString, characters);
437        }
438        break;
439    case JavaTypeBoolean:
440        result.m_booleanValue = value.z == JNI_FALSE ? false : true;
441        break;
442    case JavaTypeByte:
443        result.m_byteValue = value.b;
444        break;
445    case JavaTypeChar:
446        result.m_charValue = value.c;
447        break;
448    case JavaTypeShort:
449        result.m_shortValue = value.s;
450        break;
451    case JavaTypeInt:
452        result.m_intValue = value.i;
453        break;
454    case JavaTypeLong:
455        result.m_longValue = value.j;
456        break;
457    case JavaTypeFloat:
458        result.m_floatValue = value.f;
459        break;
460    case JavaTypeDouble:
461        result.m_doubleValue = value.d;
462        break;
463    default:
464        ASSERT(false);
465    }
466    return result;
467}
468
469jvalue javaValueToJvalue(const JavaValue& value)
470{
471    jvalue result;
472    memset(&result, 0, sizeof(jvalue));
473    switch (value.m_type) {
474    case JavaTypeVoid:
475        break;
476#if PLATFORM(ANDROID)
477    case JavaTypeArray:
478#endif
479    case JavaTypeObject:
480        if (value.m_objectValue) {
481            // This method is used only by JavaInstanceJobject, so we know the
482            // derived type of the object.
483            result.l = static_cast<JavaInstanceJobject*>(value.m_objectValue.get())->javaInstance();
484        }
485        break;
486    case JavaTypeString:
487        // This creates a local reference to a new String object, which will
488        // be released when the call stack returns to Java. Note that this
489        // may cause leaks if invoked from a native message loop, as is the
490        // case in workers.
491        result.l = getJNIEnv()->NewString(value.m_stringValue.characters(), value.m_stringValue.length());
492        break;
493    case JavaTypeBoolean:
494        result.z = value.m_booleanValue ? JNI_TRUE : JNI_FALSE;
495        break;
496    case JavaTypeByte:
497        result.b = value.m_byteValue;
498        break;
499    case JavaTypeChar:
500        result.c = value.m_charValue;
501        break;
502    case JavaTypeShort:
503        result.s = value.m_shortValue;
504        break;
505    case JavaTypeInt:
506        result.i = value.m_intValue;
507        break;
508    case JavaTypeLong:
509        result.j = value.m_longValue;
510        break;
511    case JavaTypeFloat:
512        result.f = value.m_floatValue;
513        break;
514    case JavaTypeDouble:
515        result.d = value.m_doubleValue;
516        break;
517    default:
518        ASSERT(false);
519    }
520    return result;
521}
522
523} // namespace Bindings
524
525} // namespace JSC
526
527#endif // ENABLE(JAVA_BRIDGE)
528