JNIUtilityPrivate.cpp revision 698a253f5568db010beb93b2255697997d180406
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 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 335void 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 const char* utf8String = strdup(value.m_stringValue.utf8().data()); 357 // The copied string is freed in NPN_ReleaseVariantValue (see npruntime.cpp) 358 STRINGZ_TO_NPVARIANT(utf8String, *result); 359 } 360 break; 361 362 case JavaTypeBoolean: 363 { 364 BOOLEAN_TO_NPVARIANT(value.m_booleanValue, *result); 365 } 366 break; 367 368 case JavaTypeByte: 369 { 370 INT32_TO_NPVARIANT(value.m_byteValue, *result); 371 } 372 break; 373 374 case JavaTypeChar: 375 { 376 INT32_TO_NPVARIANT(value.m_charValue, *result); 377 } 378 break; 379 380 case JavaTypeShort: 381 { 382 INT32_TO_NPVARIANT(value.m_shortValue, *result); 383 } 384 break; 385 386 case JavaTypeInt: 387 { 388 INT32_TO_NPVARIANT(value.m_intValue, *result); 389 } 390 break; 391 392 // TODO: Check if cast to double is needed. 393 case JavaTypeLong: 394 { 395 DOUBLE_TO_NPVARIANT(value.m_longValue, *result); 396 } 397 break; 398 399 case JavaTypeFloat: 400 { 401 DOUBLE_TO_NPVARIANT(value.m_floatValue, *result); 402 } 403 break; 404 405 case JavaTypeDouble: 406 { 407 DOUBLE_TO_NPVARIANT(value.m_doubleValue, *result); 408 } 409 break; 410 411 case JavaTypeInvalid: 412 default: 413 { 414 VOID_TO_NPVARIANT(*result); 415 } 416 break; 417 } 418} 419 420JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type) 421{ 422 JavaValue result; 423 result.m_type = type; 424 switch (result.m_type) { 425 case JavaTypeVoid: 426 break; 427 case JavaTypeObject: 428 result.m_objectValue = new JavaInstanceJobject(value.l); 429 break; 430 case JavaTypeString: 431 { 432 jstring javaString = static_cast<jstring>(value.l); 433 const UChar* characters = getUCharactersFromJStringInEnv(getJNIEnv(), javaString); 434 // We take a copy to allow the Java String to be released. 435 result.m_stringValue = String(characters, getJNIEnv()->GetStringLength(javaString)); 436 releaseUCharactersForJStringInEnv(getJNIEnv(), javaString, characters); 437 } 438 break; 439 case JavaTypeBoolean: 440 result.m_booleanValue = value.z == JNI_FALSE ? false : true; 441 break; 442 case JavaTypeByte: 443 result.m_byteValue = value.b; 444 break; 445 case JavaTypeChar: 446 result.m_charValue = value.c; 447 break; 448 case JavaTypeShort: 449 result.m_shortValue = value.s; 450 break; 451 case JavaTypeInt: 452 result.m_intValue = value.i; 453 break; 454 case JavaTypeLong: 455 result.m_longValue = value.j; 456 break; 457 case JavaTypeFloat: 458 result.m_floatValue = value.f; 459 break; 460 case JavaTypeDouble: 461 result.m_doubleValue = value.d; 462 break; 463 default: 464 ASSERT(false); 465 } 466 return result; 467} 468 469jvalue javaValueToJvalue(const JavaValue& value) 470{ 471 jvalue result; 472 memset(&result, 0, sizeof(jvalue)); 473 switch (value.m_type) { 474 case JavaTypeVoid: 475 break; 476#if PLATFORM(ANDROID) 477 case JavaTypeArray: 478#endif 479 case JavaTypeObject: 480 if (value.m_objectValue) { 481 // This method is used only by JavaInstanceJobject, so we know the 482 // derived type of the object. 483 result.l = static_cast<JavaInstanceJobject*>(value.m_objectValue.get())->javaInstance(); 484 } 485 break; 486 case JavaTypeString: 487 // This creates a local reference to a new String object, which will 488 // be released when the call stack returns to Java. Note that this 489 // may cause leaks if invoked from a native message loop, as is the 490 // case in workers. 491 result.l = getJNIEnv()->NewString(value.m_stringValue.characters(), value.m_stringValue.length()); 492 break; 493 case JavaTypeBoolean: 494 result.z = value.m_booleanValue ? JNI_TRUE : JNI_FALSE; 495 break; 496 case JavaTypeByte: 497 result.b = value.m_byteValue; 498 break; 499 case JavaTypeChar: 500 result.c = value.m_charValue; 501 break; 502 case JavaTypeShort: 503 result.s = value.m_shortValue; 504 break; 505 case JavaTypeInt: 506 result.i = value.m_intValue; 507 break; 508 case JavaTypeLong: 509 result.j = value.m_longValue; 510 break; 511 case JavaTypeFloat: 512 result.f = value.m_floatValue; 513 break; 514 case JavaTypeDouble: 515 result.d = value.m_doubleValue; 516 break; 517 default: 518 ASSERT(false); 519 } 520 return result; 521} 522 523} // namespace Bindings 524 525} // namespace JSC 526 527#endif // ENABLE(JAVA_BRIDGE) 528