Home | History | Annotate | Download | only in jsc
      1 /*
      2  * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
      3  * Copyright 2009, The Android Open Source Project
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "JNIUtilityPrivate.h"
     29 
     30 #if ENABLE(MAC_JAVA_BRIDGE)
     31 
     32 #include "JNIBridgeJSC.h"
     33 #include "runtime_array.h"
     34 #include "runtime_object.h"
     35 #include <runtime/JSArray.h>
     36 #include <runtime/JSLock.h>
     37 
     38 namespace JSC {
     39 
     40 namespace Bindings {
     41 
     42 static jobject convertArrayInstanceToJavaArray(ExecState* exec, JSArray* jsArray, const char* javaClassName)
     43 {
     44     JNIEnv* env = getJNIEnv();
     45     // As JS Arrays can contain a mixture of objects, assume we can convert to
     46     // the requested Java Array type requested, unless the array type is some object array
     47     // other than a string.
     48     unsigned length = jsArray->length();
     49     jobjectArray jarray = 0;
     50 
     51     // Build the correct array type
     52     switch (JNITypeFromPrimitiveType(javaClassName[1])) {
     53     case object_type:
     54             {
     55             // Only support string object types
     56             if (!strcmp("[Ljava.lang.String;", javaClassName)) {
     57                 jarray = (jobjectArray)env->NewObjectArray(length,
     58                     env->FindClass("java/lang/String"),
     59                     env->NewStringUTF(""));
     60                 for (unsigned i = 0; i < length; i++) {
     61                     JSValue item = jsArray->get(exec, i);
     62                     UString stringValue = item.toString(exec);
     63                     env->SetObjectArrayElement(jarray, i,
     64                         env->functions->NewString(env, (const jchar *)stringValue.data(), stringValue.size()));
     65                 }
     66             }
     67             break;
     68         }
     69 
     70     case boolean_type:
     71         {
     72             jarray = (jobjectArray)env->NewBooleanArray(length);
     73             for (unsigned i = 0; i < length; i++) {
     74                 JSValue item = jsArray->get(exec, i);
     75                 jboolean value = (jboolean)item.toNumber(exec);
     76                 env->SetBooleanArrayRegion((jbooleanArray)jarray, (jsize)i, (jsize)1, &value);
     77             }
     78             break;
     79         }
     80 
     81     case byte_type:
     82         {
     83             jarray = (jobjectArray)env->NewByteArray(length);
     84             for (unsigned i = 0; i < length; i++) {
     85                 JSValue item = jsArray->get(exec, i);
     86                 jbyte value = (jbyte)item.toNumber(exec);
     87                 env->SetByteArrayRegion((jbyteArray)jarray, (jsize)i, (jsize)1, &value);
     88             }
     89             break;
     90         }
     91 
     92     case char_type:
     93         {
     94             jarray = (jobjectArray)env->NewCharArray(length);
     95             for (unsigned i = 0; i < length; i++) {
     96                 JSValue item = jsArray->get(exec, i);
     97                 UString stringValue = item.toString(exec);
     98                 jchar value = 0;
     99                 if (stringValue.size() > 0)
    100                     value = ((const jchar*)stringValue.data())[0];
    101                 env->SetCharArrayRegion((jcharArray)jarray, (jsize)i, (jsize)1, &value);
    102             }
    103             break;
    104         }
    105 
    106     case short_type:
    107         {
    108             jarray = (jobjectArray)env->NewShortArray(length);
    109             for (unsigned i = 0; i < length; i++) {
    110                 JSValue item = jsArray->get(exec, i);
    111                 jshort value = (jshort)item.toNumber(exec);
    112                 env->SetShortArrayRegion((jshortArray)jarray, (jsize)i, (jsize)1, &value);
    113             }
    114             break;
    115         }
    116 
    117     case int_type:
    118         {
    119             jarray = (jobjectArray)env->NewIntArray(length);
    120             for (unsigned i = 0; i < length; i++) {
    121                 JSValue item = jsArray->get(exec, i);
    122                 jint value = (jint)item.toNumber(exec);
    123                 env->SetIntArrayRegion((jintArray)jarray, (jsize)i, (jsize)1, &value);
    124             }
    125             break;
    126         }
    127 
    128     case long_type:
    129         {
    130             jarray = (jobjectArray)env->NewLongArray(length);
    131             for (unsigned i = 0; i < length; i++) {
    132                 JSValue item = jsArray->get(exec, i);
    133                 jlong value = (jlong)item.toNumber(exec);
    134                 env->SetLongArrayRegion((jlongArray)jarray, (jsize)i, (jsize)1, &value);
    135             }
    136             break;
    137         }
    138 
    139     case float_type:
    140         {
    141             jarray = (jobjectArray)env->NewFloatArray(length);
    142             for (unsigned i = 0; i < length; i++) {
    143                 JSValue item = jsArray->get(exec, i);
    144                 jfloat value = (jfloat)item.toNumber(exec);
    145                 env->SetFloatArrayRegion((jfloatArray)jarray, (jsize)i, (jsize)1, &value);
    146             }
    147             break;
    148         }
    149 
    150     case double_type:
    151         {
    152             jarray = (jobjectArray)env->NewDoubleArray(length);
    153             for (unsigned i = 0; i < length; i++) {
    154                 JSValue item = jsArray->get(exec, i);
    155                 jdouble value = (jdouble)item.toNumber(exec);
    156                 env->SetDoubleArrayRegion((jdoubleArray)jarray, (jsize)i, (jsize)1, &value);
    157             }
    158             break;
    159         }
    160 
    161     case array_type: // don't handle embedded arrays
    162     case void_type: // Don't expect arrays of void objects
    163     case invalid_type: // Array of unknown objects
    164         break;
    165     }
    166 
    167     // if it was not one of the cases handled, then null is returned
    168     return jarray;
    169 }
    170 
    171 jvalue convertValueToJValue(ExecState* exec, JSValue value, JNIType jniType, const char* javaClassName)
    172 {
    173     JSLock lock(SilenceAssertionsOnly);
    174 
    175     jvalue result;
    176 
    177     switch (jniType) {
    178     case array_type:
    179     case object_type:
    180         {
    181             result.l = (jobject)0;
    182 
    183             // First see if we have a Java instance.
    184             if (value.isObject()) {
    185                 JSObject* objectImp = asObject(value);
    186                 if (objectImp->classInfo() == &RuntimeObjectImp::s_info) {
    187                     RuntimeObjectImp* imp = static_cast<RuntimeObjectImp*>(objectImp);
    188                     JavaInstance* instance = static_cast<JavaInstance*>(imp->getInternalInstance());
    189                     if (instance)
    190                         result.l = instance->javaInstance();
    191                 } else if (objectImp->classInfo() == &RuntimeArray::s_info) {
    192                     // Input is a JavaScript Array that was originally created from a Java Array
    193                     RuntimeArray* imp = static_cast<RuntimeArray*>(objectImp);
    194                     JavaArray* array = static_cast<JavaArray*>(imp->getConcreteArray());
    195                     result.l = array->javaArray();
    196                 } else if (objectImp->classInfo() == &JSArray::info) {
    197                     // Input is a Javascript Array. We need to create it to a Java Array.
    198                     result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName);
    199                 }
    200             }
    201 
    202             // Now convert value to a string if the target type is a java.lang.string, and we're not
    203             // converting from a Null.
    204             if (!result.l && !strcmp(javaClassName, "java.lang.String")) {
    205 #ifdef CONVERT_NULL_TO_EMPTY_STRING
    206                 if (value->isNull()) {
    207                     JNIEnv* env = getJNIEnv();
    208                     jchar buf[2];
    209                     jobject javaString = env->functions->NewString(env, buf, 0);
    210                     result.l = javaString;
    211                 } else
    212 #else
    213                 if (!value.isNull())
    214 #endif
    215                 {
    216                     UString stringValue = value.toString(exec);
    217                     JNIEnv* env = getJNIEnv();
    218                     jobject javaString = env->functions->NewString(env, (const jchar *)stringValue.data(), stringValue.size());
    219                     result.l = javaString;
    220                 }
    221             } else if (!result.l)
    222                 // ANDROID
    223                 memset(&result, 0, sizeof(jvalue)); // Handle it the same as a void case
    224         }
    225         break;
    226 
    227     case boolean_type:
    228         {
    229             result.z = (jboolean)value.toNumber(exec);
    230         }
    231         break;
    232 
    233     case byte_type:
    234         {
    235             result.b = (jbyte)value.toNumber(exec);
    236         }
    237         break;
    238 
    239     case char_type:
    240         {
    241             result.c = (jchar)value.toNumber(exec);
    242         }
    243         break;
    244 
    245     case short_type:
    246         {
    247             result.s = (jshort)value.toNumber(exec);
    248         }
    249         break;
    250 
    251     case int_type:
    252         {
    253             result.i = (jint)value.toNumber(exec);
    254         }
    255         break;
    256 
    257     case long_type:
    258         {
    259             result.j = (jlong)value.toNumber(exec);
    260         }
    261         break;
    262 
    263     case float_type:
    264         {
    265             result.f = (jfloat)value.toNumber(exec);
    266         }
    267         break;
    268 
    269     case double_type:
    270         {
    271             result.d = (jdouble)value.toNumber(exec);
    272         }
    273         break;
    274 
    275         break;
    276 
    277     case invalid_type:
    278     default:
    279     case void_type:
    280         {
    281             // ANDROID
    282             memset(&result, 0, sizeof(jvalue));
    283         }
    284         break;
    285     }
    286     return result;
    287 }
    288 
    289 } // end of namespace Bindings
    290 
    291 } // end of namespace JSC
    292 
    293 #endif // ENABLE(MAC_JAVA_BRIDGE)
    294