1 /*
   2  * Copyright (C) 2003, 2010 Apple, 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(JAVA_BRIDGE)
  31 
  32 #include "JavaRuntimeObject.h"
  33 #include "JNIBridgeJSC.h"
  34 #include "jni_jsobject.h"
  35 #include "runtime_array.h"
  36 #include "runtime_object.h"
  37 #include <runtime/JSArray.h>
  38 #include <runtime/JSLock.h>
  39 
  40 namespace JSC {
  41 
  42 namespace Bindings {
  43 
  44 static jobject convertArrayInstanceToJavaArray(ExecState* exec, JSArray* jsArray, const char* javaClassName)
  45 {
  46     JNIEnv* env = getJNIEnv();
  47     // As JS Arrays can contain a mixture of objects, assume we can convert to
  48     // the requested Java Array type requested, unless the array type is some object array
  49     // other than a string.
  50     unsigned length = jsArray->length();
  51     jobjectArray jarray = 0;
  52 
  53     // Build the correct array type
  54     switch (JNITypeFromPrimitiveType(javaClassName[1])) {
  55     case object_type:
  56             {
  57             // Only support string object types
  58             if (!strcmp("[Ljava.lang.String;", javaClassName)) {
  59                 jarray = (jobjectArray)env->NewObjectArray(length,
  60                     env->FindClass("java/lang/String"),
  61                     env->NewStringUTF(""));
  62                 for (unsigned i = 0; i < length; i++) {
  63                     JSValue item = jsArray->get(exec, i);
  64                     UString stringValue = item.toString(exec);
  65                     env->SetObjectArrayElement(jarray, i,
  66                         env->functions->NewString(env, (const jchar *)stringValue.data(), stringValue.size()));
  67                 }
  68             }
  69             break;
  70         }
  71 
  72     case boolean_type:
  73         {
  74             jarray = (jobjectArray)env->NewBooleanArray(length);
  75             for (unsigned i = 0; i < length; i++) {
  76                 JSValue item = jsArray->get(exec, i);
  77                 jboolean value = (jboolean)item.toNumber(exec);
  78                 env->SetBooleanArrayRegion((jbooleanArray)jarray, (jsize)i, (jsize)1, &value);
  79             }
  80             break;
  81         }
  82 
  83     case byte_type:
  84         {
  85             jarray = (jobjectArray)env->NewByteArray(length);
  86             for (unsigned i = 0; i < length; i++) {
  87                 JSValue item = jsArray->get(exec, i);
  88                 jbyte value = (jbyte)item.toNumber(exec);
  89                 env->SetByteArrayRegion((jbyteArray)jarray, (jsize)i, (jsize)1, &value);
  90             }
  91             break;
  92         }
  93 
  94     case char_type:
  95         {
  96             jarray = (jobjectArray)env->NewCharArray(length);
  97             for (unsigned i = 0; i < length; i++) {
  98                 JSValue item = jsArray->get(exec, i);
  99                 UString stringValue = item.toString(exec);
 100                 jchar value = 0;
 101                 if (stringValue.size() > 0)
 102                     value = ((const jchar*)stringValue.data())[0];
 103                 env->SetCharArrayRegion((jcharArray)jarray, (jsize)i, (jsize)1, &value);
 104             }
 105             break;
 106         }
 107 
 108     case short_type:
 109         {
 110             jarray = (jobjectArray)env->NewShortArray(length);
 111             for (unsigned i = 0; i < length; i++) {
 112                 JSValue item = jsArray->get(exec, i);
 113                 jshort value = (jshort)item.toNumber(exec);
 114                 env->SetShortArrayRegion((jshortArray)jarray, (jsize)i, (jsize)1, &value);
 115             }
 116             break;
 117         }
 118 
 119     case int_type:
 120         {
 121             jarray = (jobjectArray)env->NewIntArray(length);
 122             for (unsigned i = 0; i < length; i++) {
 123                 JSValue item = jsArray->get(exec, i);
 124                 jint value = (jint)item.toNumber(exec);
 125                 env->SetIntArrayRegion((jintArray)jarray, (jsize)i, (jsize)1, &value);
 126             }
 127             break;
 128         }
 129 
 130     case long_type:
 131         {
 132             jarray = (jobjectArray)env->NewLongArray(length);
 133             for (unsigned i = 0; i < length; i++) {
 134                 JSValue item = jsArray->get(exec, i);
 135                 jlong value = (jlong)item.toNumber(exec);
 136                 env->SetLongArrayRegion((jlongArray)jarray, (jsize)i, (jsize)1, &value);
 137             }
 138             break;
 139         }
 140 
 141     case float_type:
 142         {
 143             jarray = (jobjectArray)env->NewFloatArray(length);
 144             for (unsigned i = 0; i < length; i++) {
 145                 JSValue item = jsArray->get(exec, i);
 146                 jfloat value = (jfloat)item.toNumber(exec);
 147                 env->SetFloatArrayRegion((jfloatArray)jarray, (jsize)i, (jsize)1, &value);
 148             }
 149             break;
 150         }
 151 
 152     case double_type:
 153         {
 154             jarray = (jobjectArray)env->NewDoubleArray(length);
 155             for (unsigned i = 0; i < length; i++) {
 156                 JSValue item = jsArray->get(exec, i);
 157                 jdouble value = (jdouble)item.toNumber(exec);
 158                 env->SetDoubleArrayRegion((jdoubleArray)jarray, (jsize)i, (jsize)1, &value);
 159             }
 160             break;
 161         }
 162 
 163     case array_type: // don't handle embedded arrays
 164     case void_type: // Don't expect arrays of void objects
 165     case invalid_type: // Array of unknown objects
 166         break;
 167     }
 168 
 169     // if it was not one of the cases handled, then null is returned
 170     return jarray;
 171 }
 172 
 173 jvalue convertValueToJValue(ExecState* exec, RootObject* rootObject, JSValue value, JNIType jniType, const char* javaClassName)
 174 {
 175     JSLock lock(SilenceAssertionsOnly);
 176 
 177     jvalue result;
 178     memset(&result, 0, sizeof(jvalue));
 179 
 180     switch (jniType) {
 181     case array_type:
 182     case object_type:
 183         {
 184             // FIXME: JavaJSObject::convertValueToJObject functionality is almost exactly the same,
 185             // these functions should use common code.
 186 
 187             if (value.isObject()) {
 188                 JSObject* object = asObject(value);
 189                 if (object->inherits(&JavaRuntimeObject::s_info)) {
 190                     // Unwrap a Java instance.
 191                     JavaRuntimeObject* runtimeObject = static_cast<JavaRuntimeObject*>(object);
 192                     JavaInstance* instance = runtimeObject->getInternalJavaInstance();
 193                     if (instance)
 194                         result.l = instance->javaInstance();
 195 #if 0
 196                 } else if (object->classInfo() == &RuntimeArray::s_info) {
 197                     // Input is a JavaScript Array that was originally created from a Java Array
 198                     RuntimeArray* imp = static_cast<RuntimeArray*>(object);
 199                     JavaArray* array = static_cast<JavaArray*>(imp->getConcreteArray());
 200                     result.l = array->javaArray();
 201                 } else if (object->classInfo() == &JSArray::info) {
 202                     // Input is a Javascript Array. We need to create it to a Java Array.
 203                     result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName);
 204 #endif
 205                 } else if (!result.l && (!strcmp(javaClassName, "java.lang.Object")) || (!strcmp(javaClassName, "netscape.javascript.JSObject"))) {
 206                     // Wrap objects in JSObject instances.
 207                     JNIEnv* env = getJNIEnv();
 208                     //                    jclass jsObjectClass = env->FindClass("sun/plugin/javascript/webkit/JSObject");
 209                     jclass jsObjectClass = env->FindClass("com/sun/webpane/platform/JSObject");
 210                     jmethodID constructorID = env->GetMethodID(jsObjectClass, "<init>", "(J)V");
 211                     if (constructorID) {
 212                         jlong nativeHandle = ptr_to_jlong(object);
 213                         if (rootObject) // ??? FIXME
 214                           rootObject->gcProtect(object);
 215                         result.l = env->NewObject(jsObjectClass, constructorID, nativeHandle);
 216                     }
 217                 }
 218             }
 219 
 220             // Create an appropriate Java object if target type is java.lang.Object.
 221             if (!result.l && !strcmp(javaClassName, "java.lang.Object")) {
 222                 if (value.isString()) {
 223                     UString stringValue = asString(value)->value(exec);
 224                     JNIEnv* env = getJNIEnv();
 225                     jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.data(), stringValue.size());
 226                     result.l = javaString;
 227                 } else if (value.isNumber()) {
 228                     double doubleValue = value.uncheckedGetNumber();
 229                     JNIEnv* env = getJNIEnv();
 230                     jclass clazz = env->FindClass("java/lang/Double");
 231                     jmethodID constructor = env->GetMethodID(clazz, "<init>", "(D)V");
 232                     jobject javaDouble = env->functions->NewObject(env, clazz, constructor, doubleValue);
 233                     result.l = javaDouble;
 234                 } else if (value.isBoolean()) {
 235                     bool boolValue = value.getBoolean();
 236                     JNIEnv* env = getJNIEnv();
 237                     jclass clazz = env->FindClass("java/lang/Boolean");
 238                     jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Z)V");
 239                     jobject javaBoolean = env->functions->NewObject(env, clazz, constructor, boolValue);
 240                     result.l = javaBoolean;
 241                 } else if (value.isUndefined()) {
 242                     UString stringValue = "undefined";
 243                     JNIEnv* env = getJNIEnv();
 244                     jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.data(), stringValue.size());
 245                     result.l = javaString;
 246                 }
 247             }
 248 
 249             // Convert value to a string if the target type is a java.lang.String, and we're not
 250             // converting from a null.
 251             if (!result.l && !strcmp(javaClassName, "java.lang.String")) {
 252                 if (!value.isNull()) {
 253                     UString stringValue = value.toString(exec);
 254                     JNIEnv* env = getJNIEnv();
 255                     jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.data(), stringValue.size());
 256                     result.l = javaString;
 257                 }
 258             }
 259         }
 260         break;
 261 
 262     case boolean_type:
 263         {
 264             result.z = (jboolean)value.toNumber(exec);
 265         }
 266         break;
 267 
 268     case byte_type:
 269         {
 270             result.b = (jbyte)value.toNumber(exec);
 271         }
 272         break;
 273 
 274     case char_type:
 275         {
 276             result.c = (jchar)value.toNumber(exec);
 277         }
 278         break;
 279 
 280     case short_type:
 281         {
 282             result.s = (jshort)value.toNumber(exec);
 283         }
 284         break;
 285 
 286     case int_type:
 287         {
 288             result.i = (jint)value.toNumber(exec);
 289         }
 290         break;
 291 
 292     case long_type:
 293         {
 294             result.j = (jlong)value.toNumber(exec);
 295         }
 296         break;
 297 
 298     case float_type:
 299         {
 300             result.f = (jfloat)value.toNumber(exec);
 301         }
 302         break;
 303 
 304     case double_type:
 305         {
 306             result.d = (jdouble)value.toNumber(exec);
 307         }
 308         break;
 309 
 310     case invalid_type:
 311     case void_type:
 312         break;
 313     }
 314     return result;
 315 }
 316 
 317 } // end of namespace Bindings
 318 
 319 } // end of namespace JSC
 320 
 321 #endif // ENABLE(JAVA_BRIDGE)
--- EOF ---