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