Home | History | Annotate | Download | only in v8
      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 
     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 
    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 
    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 
    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