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 #include "JavaInstanceV8.h"
     30 #include "JavaNPObjectV8.h"
     31 #include "npruntime_impl.h"
     32 
     33 namespace JSC {
     34 
     35 namespace Bindings {
     36 
     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 
    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