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