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 #if ENABLE(JAVA_BRIDGE) 30 31 #include "JavaInstanceJobjectV8.h" 32 #include "JavaNPObjectV8.h" 33 #if PLATFORM(ANDROID) 34 #include "npruntime_impl.h" 35 #endif // PLATFORM(ANDROID) 36 #include "JavaValueV8.h" 37 #include <wtf/text/CString.h> 38 39 namespace JSC { 40 41 namespace Bindings { 42 43 JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) 44 { 45 CString javaClassName = javaClass.utf8(); 46 JavaType javaType = javaTypeFromClassName(javaClassName.data()); 47 JavaValue result; 48 result.m_type = javaType; 49 NPVariantType type = value.type; 50 51 switch (javaType) { 52 case JavaTypeArray: 53 #if PLATFORM(ANDROID) 54 // If we're converting to an array, see if the NPVariant has a length 55 // property. If so, create a JNI array of the relevant length and to get 56 // the elements of the NPVariant. When we interpret the JavaValue later, 57 // we know that the array is represented as a JNI array. 58 // 59 // FIXME: This is a hack. We should not be using JNI here. We should 60 // represent the JavaValue without JNI. 61 { 62 JNIEnv* env = getJNIEnv(); 63 jobject javaArray; 64 NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0; 65 NPVariant npvLength; 66 bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength); 67 if (!success) { 68 // No length property so we don't know how many elements to put into the array. 69 // Treat this as an error. 70 // JSC sends null for an array that is not an array of strings or basic types, 71 // do this also in the unknown length case. 72 break; 73 } 74 75 jsize length = 0; 76 if (NPVARIANT_IS_INT32(npvLength)) 77 length = static_cast<jsize>(NPVARIANT_TO_INT32(npvLength)); 78 else if (NPVARIANT_IS_DOUBLE(npvLength)) 79 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(npvLength)); 80 81 if (!strcmp(javaClassName.data(), "[Ljava.lang.String;")) { 82 // Match JSC behavior by only allowing Object arrays if they are Strings. 83 jclass stringClass = env->FindClass("java/lang/String"); 84 javaArray = env->NewObjectArray(length, stringClass, 0); 85 for (jsize i = 0; i < length; i++) { 86 NPVariant npvValue; 87 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 88 if(NPVARIANT_IS_STRING(npvValue)) { 89 NPString str = NPVARIANT_TO_STRING(npvValue); 90 env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters)); 91 } 92 } 93 94 env->DeleteLocalRef(stringClass); 95 } else if (!strcmp(javaClassName.data(), "[B")) { 96 // array of bytes 97 javaArray = env->NewByteArray(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 jbyte bVal = 0; 103 if (NPVARIANT_IS_INT32(npvValue)) { 104 bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue)); 105 } else if (NPVARIANT_IS_DOUBLE(npvValue)) { 106 bVal = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(npvValue)); 107 } 108 env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal); 109 } 110 } else if (!strcmp(javaClassName.data(), "[C")) { 111 // array of chars 112 javaArray = env->NewCharArray(length); 113 // Now iterate over each element and add to the array. 114 for (jsize i = 0; i < length; i++) { 115 NPVariant npvValue; 116 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 117 jchar cVal = 0; 118 if (NPVARIANT_IS_INT32(npvValue)) { 119 cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue)); 120 } else if (NPVARIANT_IS_STRING(npvValue)) { 121 NPString str = NPVARIANT_TO_STRING(npvValue); 122 cVal = str.UTF8Characters[0]; 123 } 124 env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal); 125 } 126 } else if (!strcmp(javaClassName.data(), "[D")) { 127 // array of doubles 128 javaArray = env->NewDoubleArray(length); 129 // Now iterate over each element and add to the array. 130 for (jsize i = 0; i < length; i++) { 131 NPVariant npvValue; 132 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 133 if (NPVARIANT_IS_DOUBLE(npvValue)) { 134 jdouble dVal = NPVARIANT_TO_DOUBLE(npvValue); 135 env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray), i, 1, &dVal); 136 } 137 } 138 } else if (!strcmp(javaClassName.data(), "[F")) { 139 // array of floats 140 javaArray = env->NewFloatArray(length); 141 // Now iterate over each element and add to the array. 142 for (jsize i = 0; i < length; i++) { 143 NPVariant npvValue; 144 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 145 if (NPVARIANT_IS_DOUBLE(npvValue)) { 146 jfloat fVal = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(npvValue)); 147 env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray), i, 1, &fVal); 148 } 149 } 150 } else if (!strcmp(javaClassName.data(), "[I")) { 151 // array of ints 152 javaArray = env->NewIntArray(length); 153 // Now iterate over each element and add to the array. 154 for (jsize i = 0; i < length; i++) { 155 NPVariant npvValue; 156 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 157 jint iVal = 0; 158 if (NPVARIANT_IS_INT32(npvValue)) { 159 iVal = NPVARIANT_TO_INT32(npvValue); 160 } else if (NPVARIANT_IS_DOUBLE(npvValue)) { 161 iVal = static_cast<jint>(NPVARIANT_TO_DOUBLE(npvValue)); 162 } 163 env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal); 164 } 165 } else if (!strcmp(javaClassName.data(), "[J")) { 166 // array of longs 167 javaArray = env->NewLongArray(length); 168 // Now iterate over each element and add to the array. 169 for (jsize i = 0; i < length; i++) { 170 NPVariant npvValue; 171 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 172 jlong jVal = 0; 173 if (NPVARIANT_IS_INT32(npvValue)) { 174 jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue)); 175 } else if (NPVARIANT_IS_DOUBLE(npvValue)) { 176 jVal = static_cast<jlong>(NPVARIANT_TO_DOUBLE(npvValue)); 177 } 178 env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal); 179 } 180 } else if (!strcmp(javaClassName.data(), "[S")) { 181 // array of shorts 182 javaArray = env->NewShortArray(length); 183 // Now iterate over each element and add to the array. 184 for (jsize i = 0; i < length; i++) { 185 NPVariant npvValue; 186 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 187 jshort sVal = 0; 188 if (NPVARIANT_IS_INT32(npvValue)) { 189 sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue)); 190 } else if (NPVARIANT_IS_DOUBLE(npvValue)) { 191 sVal = static_cast<jshort>(NPVARIANT_TO_DOUBLE(npvValue)); 192 } 193 env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal); 194 } 195 } else if (!strcmp(javaClassName.data(), "[Z")) { 196 // array of booleans 197 javaArray = env->NewBooleanArray(length); 198 // Now iterate over each element and add to the array. 199 for (jsize i = 0; i < length; i++) { 200 NPVariant npvValue; 201 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); 202 if (NPVARIANT_IS_BOOLEAN(npvValue)) { 203 jboolean zVal = NPVARIANT_TO_BOOLEAN(npvValue); 204 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray), i, 1, &zVal); 205 } 206 } 207 } else { 208 // JSC sends null for an array that is not an array of strings or basic types. 209 break; 210 } 211 212 result.m_objectValue = adoptRef(new JavaInstanceJobject(javaArray)); 213 env->DeleteLocalRef(javaArray); 214 } 215 break; 216 #endif // PLATFORM(ANDROID) 217 218 case JavaTypeObject: 219 { 220 // See if we have a Java instance. 221 if (type == NPVariantType_Object) { 222 NPObject* objectImp = NPVARIANT_TO_OBJECT(value); 223 result.m_objectValue = ExtractJavaInstance(objectImp); 224 } 225 } 226 break; 227 228 case JavaTypeString: 229 { 230 #ifdef CONVERT_NULL_TO_EMPTY_STRING 231 if (type == NPVariantType_Null) { 232 result.m_type = JavaTypeString; 233 result.m_stringValue = String::fromUTF8(""); 234 } else 235 #else 236 if (type == NPVariantType_String) 237 #endif 238 { 239 NPString src = NPVARIANT_TO_STRING(value); 240 result.m_type = JavaTypeString; 241 result.m_stringValue = String::fromUTF8(src.UTF8Characters); 242 } 243 #if PLATFORM(ANDROID) 244 else if (type == NPVariantType_Int32) { 245 result.m_type = JavaTypeString; 246 result.m_stringValue = String::number(NPVARIANT_TO_INT32(value)); 247 } else if (type == NPVariantType_Bool) { 248 result.m_type = JavaTypeString; 249 result.m_stringValue = NPVARIANT_TO_BOOLEAN(value) ? "true" : "false"; 250 } else if (type == NPVariantType_Double) { 251 result.m_type = JavaTypeString; 252 result.m_stringValue = String::number(NPVARIANT_TO_DOUBLE(value)); 253 } else if (!NPVARIANT_IS_NULL(value)) { 254 result.m_type = JavaTypeString; 255 result.m_stringValue = "undefined"; 256 } 257 #endif // PLATFORM(ANDROID) 258 } 259 break; 260 261 case JavaTypeBoolean: 262 { 263 if (type == NPVariantType_Bool) 264 result.m_booleanValue = NPVARIANT_TO_BOOLEAN(value); 265 } 266 break; 267 268 case JavaTypeByte: 269 { 270 if (type == NPVariantType_Int32) 271 result.m_byteValue = static_cast<signed char>(NPVARIANT_TO_INT32(value)); 272 else if (type == NPVariantType_Double) 273 result.m_byteValue = static_cast<signed char>(NPVARIANT_TO_DOUBLE(value)); 274 } 275 break; 276 277 case JavaTypeChar: 278 { 279 if (type == NPVariantType_Int32) 280 result.m_charValue = static_cast<unsigned short>(NPVARIANT_TO_INT32(value)); 281 } 282 break; 283 284 case JavaTypeShort: 285 { 286 if (type == NPVariantType_Int32) 287 result.m_shortValue = static_cast<short>(NPVARIANT_TO_INT32(value)); 288 else if (type == NPVariantType_Double) 289 result.m_shortValue = static_cast<short>(NPVARIANT_TO_DOUBLE(value)); 290 } 291 break; 292 293 case JavaTypeInt: 294 { 295 if (type == NPVariantType_Int32) 296 result.m_intValue = static_cast<int>(NPVARIANT_TO_INT32(value)); 297 else if (type == NPVariantType_Double) 298 result.m_intValue = static_cast<int>(NPVARIANT_TO_DOUBLE(value)); 299 } 300 break; 301 302 case JavaTypeLong: 303 { 304 if (type == NPVariantType_Int32) 305 result.m_longValue = static_cast<long long>(NPVARIANT_TO_INT32(value)); 306 else if (type == NPVariantType_Double) 307 result.m_longValue = static_cast<long long>(NPVARIANT_TO_DOUBLE(value)); 308 } 309 break; 310 311 case JavaTypeFloat: 312 { 313 if (type == NPVariantType_Int32) 314 result.m_floatValue = static_cast<float>(NPVARIANT_TO_INT32(value)); 315 else if (type == NPVariantType_Double) 316 result.m_floatValue = static_cast<float>(NPVARIANT_TO_DOUBLE(value)); 317 } 318 break; 319 320 case JavaTypeDouble: 321 { 322 if (type == NPVariantType_Int32) 323 result.m_doubleValue = static_cast<double>(NPVARIANT_TO_INT32(value)); 324 else if (type == NPVariantType_Double) 325 result.m_doubleValue = static_cast<double>(NPVARIANT_TO_DOUBLE(value)); 326 } 327 break; 328 default: 329 break; 330 } 331 return result; 332 } 333 334 335 void convertJavaValueToNPVariant(JavaValue value, NPVariant* result) 336 { 337 switch (value.m_type) { 338 case JavaTypeVoid: 339 { 340 VOID_TO_NPVARIANT(*result); 341 } 342 break; 343 344 case JavaTypeObject: 345 { 346 // If the JavaValue is a String object, it should have type JavaTypeString. 347 if (value.m_objectValue) 348 OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(value.m_objectValue.get()), *result); 349 else 350 VOID_TO_NPVARIANT(*result); 351 } 352 break; 353 354 case JavaTypeString: 355 { 356 #if PLATFORM(ANDROID) 357 // This entire file will likely be removed usptream soon. 358 if (value.m_stringValue.isNull()) { 359 VOID_TO_NPVARIANT(*result); 360 break; 361 } 362 #endif 363 const char* utf8String = strdup(value.m_stringValue.utf8().data()); 364 // The copied string is freed in NPN_ReleaseVariantValue (see npruntime.cpp) 365 STRINGZ_TO_NPVARIANT(utf8String, *result); 366 } 367 break; 368 369 case JavaTypeBoolean: 370 { 371 BOOLEAN_TO_NPVARIANT(value.m_booleanValue, *result); 372 } 373 break; 374 375 case JavaTypeByte: 376 { 377 INT32_TO_NPVARIANT(value.m_byteValue, *result); 378 } 379 break; 380 381 case JavaTypeChar: 382 { 383 INT32_TO_NPVARIANT(value.m_charValue, *result); 384 } 385 break; 386 387 case JavaTypeShort: 388 { 389 INT32_TO_NPVARIANT(value.m_shortValue, *result); 390 } 391 break; 392 393 case JavaTypeInt: 394 { 395 INT32_TO_NPVARIANT(value.m_intValue, *result); 396 } 397 break; 398 399 // TODO: Check if cast to double is needed. 400 case JavaTypeLong: 401 { 402 DOUBLE_TO_NPVARIANT(value.m_longValue, *result); 403 } 404 break; 405 406 case JavaTypeFloat: 407 { 408 DOUBLE_TO_NPVARIANT(value.m_floatValue, *result); 409 } 410 break; 411 412 case JavaTypeDouble: 413 { 414 DOUBLE_TO_NPVARIANT(value.m_doubleValue, *result); 415 } 416 break; 417 418 case JavaTypeInvalid: 419 default: 420 { 421 VOID_TO_NPVARIANT(*result); 422 } 423 break; 424 } 425 } 426 427 JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type) 428 { 429 JavaValue result; 430 result.m_type = type; 431 switch (result.m_type) { 432 case JavaTypeVoid: 433 break; 434 case JavaTypeObject: 435 result.m_objectValue = new JavaInstanceJobject(value.l); 436 break; 437 case JavaTypeString: 438 { 439 jstring javaString = static_cast<jstring>(value.l); 440 if (!javaString) { 441 // result.m_stringValue is null by default 442 break; 443 } 444 const UChar* characters = getUCharactersFromJStringInEnv(getJNIEnv(), javaString); 445 // We take a copy to allow the Java String to be released. 446 result.m_stringValue = String(characters, getJNIEnv()->GetStringLength(javaString)); 447 releaseUCharactersForJStringInEnv(getJNIEnv(), javaString, characters); 448 } 449 break; 450 case JavaTypeBoolean: 451 result.m_booleanValue = value.z == JNI_FALSE ? false : true; 452 break; 453 case JavaTypeByte: 454 result.m_byteValue = value.b; 455 break; 456 case JavaTypeChar: 457 result.m_charValue = value.c; 458 break; 459 case JavaTypeShort: 460 result.m_shortValue = value.s; 461 break; 462 case JavaTypeInt: 463 result.m_intValue = value.i; 464 break; 465 case JavaTypeLong: 466 result.m_longValue = value.j; 467 break; 468 case JavaTypeFloat: 469 result.m_floatValue = value.f; 470 break; 471 case JavaTypeDouble: 472 result.m_doubleValue = value.d; 473 break; 474 default: 475 ASSERT(false); 476 } 477 return result; 478 } 479 480 jvalue javaValueToJvalue(const JavaValue& value) 481 { 482 jvalue result; 483 memset(&result, 0, sizeof(jvalue)); 484 switch (value.m_type) { 485 case JavaTypeVoid: 486 break; 487 #if PLATFORM(ANDROID) 488 case JavaTypeArray: 489 #endif 490 case JavaTypeObject: 491 if (value.m_objectValue) { 492 // This method is used only by JavaInstanceJobject, so we know the 493 // derived type of the object. 494 result.l = static_cast<JavaInstanceJobject*>(value.m_objectValue.get())->javaInstance(); 495 } 496 break; 497 case JavaTypeString: 498 // This creates a local reference to a new String object, which will 499 // be released when the call stack returns to Java. Note that this 500 // may cause leaks if invoked from a native message loop, as is the 501 // case in workers. 502 if (value.m_stringValue.isNull()) { 503 // result.l is null by default. 504 break; 505 } 506 result.l = getJNIEnv()->NewString(value.m_stringValue.characters(), value.m_stringValue.length()); 507 break; 508 case JavaTypeBoolean: 509 result.z = value.m_booleanValue ? JNI_TRUE : JNI_FALSE; 510 break; 511 case JavaTypeByte: 512 result.b = value.m_byteValue; 513 break; 514 case JavaTypeChar: 515 result.c = value.m_charValue; 516 break; 517 case JavaTypeShort: 518 result.s = value.m_shortValue; 519 break; 520 case JavaTypeInt: 521 result.i = value.m_intValue; 522 break; 523 case JavaTypeLong: 524 result.j = value.m_longValue; 525 break; 526 case JavaTypeFloat: 527 result.f = value.m_floatValue; 528 break; 529 case JavaTypeDouble: 530 result.d = value.m_doubleValue; 531 break; 532 default: 533 ASSERT(false); 534 } 535 return result; 536 } 537 538 } // namespace Bindings 539 540 } // namespace JSC 541 542 #endif // ENABLE(JAVA_BRIDGE) 543