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