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