JNIUtilityPrivate.cpp revision 81bc750723a18f21cd17d1b173cd2a4dda9cea6e
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 "JavaInstanceV8.h" 32#include "JavaNPObjectV8.h" 33<<<<<<< HEAD 34#include "npruntime_impl.h" 35======= 36#include <wtf/text/CString.h> 37>>>>>>> WebKit at r80534 38 39namespace JSC { 40 41namespace Bindings { 42 43jvalue convertNPVariantToJValue(NPVariant value, const WTF::String& javaType) 44{ 45 CString javaClassName = javaType.utf8(); 46 JNIType jniType = JNITypeFromClassName(javaClassName.data()); 47 jvalue result; 48 NPVariantType type = value.type; 49 50 switch (jniType) { 51 case array_type: 52 { 53 JNIEnv* env = getJNIEnv(); 54 jobject javaArray; 55 NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0; 56 NPVariant npvLength; 57 bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength); 58 if (!success) { 59 // No length property so we don't know how many elements to put into the array. 60 // Treat this as an error. 61#ifdef EMULATE_JSC_BINDINGS 62 // JSC sends null for an array that is not an array of strings or basic types, 63 // do this also in the unknown length case. 64 memset(&result, 0, sizeof(jvalue)); 65#else 66 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks 67 // for the length of the array it was passed). Here we send a 0 length array. 68 jclass objectClass = env->FindClass("java/lang/Object"); 69 javaArray = env->NewObjectArray(0, objectClass, 0); 70 env->DeleteLocalRef(objectClass); 71#endif 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, "[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, "[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, "[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, "[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, "[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, "[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, "[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, "[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, "[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#ifdef EMULATE_JSC_BINDINGS 209 // JSC sends null for an array that is not an array of strings or basic types. 210 memset(&result, 0, sizeof(jvalue)); 211 break; 212#else 213 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks 214 // for the length of the array it was passed). Here we send a 0 length array. 215 jclass objectClass = env->FindClass("java/lang/Object"); 216 javaArray = env->NewObjectArray(0, objectClass, 0); 217 env->DeleteLocalRef(objectClass); 218#endif 219 } 220 221 result.l = javaArray; 222 } 223 break; 224 225 case object_type: 226 { 227 JNIEnv* env = getJNIEnv(); 228 result.l = static_cast<jobject>(0); 229 jobject javaString; 230 231 // First see if we have a Java instance. 232 if (type == NPVariantType_Object) { 233 NPObject* objectImp = NPVARIANT_TO_OBJECT(value); 234 if (JavaInstance* instance = ExtractJavaInstance(objectImp)) 235 result.l = instance->javaInstance(); 236 } 237 238 // Now convert value to a string if the target type is a java.lang.string, and we're not 239 // converting from a Null. 240 if (!result.l && !strcmp(javaClassName.data(), "java.lang.String")) { 241#ifdef CONVERT_NULL_TO_EMPTY_STRING 242 if (type == NPVariantType_Null) { 243 jchar buf[2]; 244 jobject javaString = env->functions->NewString(env, buf, 0); 245 result.l = javaString; 246 } else 247#else 248 if (type == NPVariantType_String) 249#endif 250 { 251 NPString src = NPVARIANT_TO_STRING(value); 252 javaString = env->NewStringUTF(src.UTF8Characters); 253 result.l = javaString; 254 } else if (type == NPVariantType_Int32) { 255 jint src = NPVARIANT_TO_INT32(value); 256 jclass integerClass = env->FindClass("java/lang/Integer"); 257 jmethodID toString = env->GetStaticMethodID(integerClass, "toString", "(I)Ljava/lang/String;"); 258 javaString = env->CallStaticObjectMethod(integerClass, toString, src); 259 result.l = javaString; 260 env->DeleteLocalRef(integerClass); 261 } else if (type == NPVariantType_Bool) { 262 jboolean src = NPVARIANT_TO_BOOLEAN(value); 263 jclass booleanClass = env->FindClass("java/lang/Boolean"); 264 jmethodID toString = env->GetStaticMethodID(booleanClass, "toString", "(Z)Ljava/lang/String;"); 265 javaString = env->CallStaticObjectMethod(booleanClass, toString, src); 266 result.l = javaString; 267 env->DeleteLocalRef(booleanClass); 268 } else if (type == NPVariantType_Double) { 269 jdouble src = NPVARIANT_TO_DOUBLE(value); 270 jclass doubleClass = env->FindClass("java/lang/Double"); 271 jmethodID toString = env->GetStaticMethodID(doubleClass, "toString", "(D)Ljava/lang/String;"); 272 javaString = env->CallStaticObjectMethod(doubleClass, toString, src); 273 result.l = javaString; 274 env->DeleteLocalRef(doubleClass); 275 } 276#ifdef EMULATE_JSC_BINDINGS 277 // For the undefined value, JSC sends the String "undefined". Feels to me like we 278 // should send null in this case. 279 else if (!NPVARIANT_IS_NULL(value)) { 280 javaString = env->NewStringUTF("undefined"); 281 result.l = javaString; 282 } 283#endif 284 } else if (!result.l) 285 memset(&result, 0, sizeof(jvalue)); // Handle it the same as a void case 286 } 287 break; 288 289 case boolean_type: 290 { 291 if (type == NPVariantType_Bool) 292 result.z = NPVARIANT_TO_BOOLEAN(value); 293 else 294 memset(&result, 0, sizeof(jvalue)); // as void case 295 } 296 break; 297 298 case byte_type: 299 { 300 if (type == NPVariantType_Int32) 301 result.b = static_cast<jbyte>(NPVARIANT_TO_INT32(value)); 302 else if (type == NPVariantType_Double) 303 result.b = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(value)); 304 else 305 memset(&result, 0, sizeof(jvalue)); 306 } 307 break; 308 309 case char_type: 310 { 311 if (type == NPVariantType_Int32) 312 result.c = static_cast<char>(NPVARIANT_TO_INT32(value)); 313#ifndef EMULATE_JSC_BINDINGS 314 // There is no char type in JavaScript - just strings 1 character 315 // long. So just converting it to an int above doesn't work. Again, 316 // we emulate the behavior for now for maximum compatability. 317 else if (type == NPVariantType_String) { 318 NPString str = NPVARIANT_TO_STRING(value); 319 result.c = str.UTF8Characters[0]; 320 } 321#endif 322 else 323 memset(&result, 0, sizeof(jvalue)); 324 } 325 break; 326 327 case short_type: 328 { 329 if (type == NPVariantType_Int32) 330 result.s = static_cast<jshort>(NPVARIANT_TO_INT32(value)); 331 else if (type == NPVariantType_Double) 332 result.s = static_cast<jshort>(NPVARIANT_TO_DOUBLE(value)); 333 else 334 memset(&result, 0, sizeof(jvalue)); 335 } 336 break; 337 338 case int_type: 339 { 340 if (type == NPVariantType_Int32) 341 result.i = static_cast<jint>(NPVARIANT_TO_INT32(value)); 342 else if (type == NPVariantType_Double) 343 result.i = static_cast<jint>(NPVARIANT_TO_DOUBLE(value)); 344 else 345 memset(&result, 0, sizeof(jvalue)); 346 } 347 break; 348 349 case long_type: 350 { 351 if (type == NPVariantType_Int32) 352 result.j = static_cast<jlong>(NPVARIANT_TO_INT32(value)); 353 else if (type == NPVariantType_Double) 354 result.j = static_cast<jlong>(NPVARIANT_TO_DOUBLE(value)); 355 else 356 memset(&result, 0, sizeof(jvalue)); 357 } 358 break; 359 360 case float_type: 361 { 362 if (type == NPVariantType_Int32) 363 result.f = static_cast<jfloat>(NPVARIANT_TO_INT32(value)); 364 else if (type == NPVariantType_Double) 365 result.f = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(value)); 366 else 367 memset(&result, 0, sizeof(jvalue)); 368 } 369 break; 370 371 case double_type: 372 { 373 if (type == NPVariantType_Int32) 374 result.d = static_cast<jdouble>(NPVARIANT_TO_INT32(value)); 375 else if (type == NPVariantType_Double) 376 result.d = static_cast<jdouble>(NPVARIANT_TO_DOUBLE(value)); 377 else 378 memset(&result, 0, sizeof(jvalue)); 379 } 380 break; 381 382 case invalid_type: 383 default: 384 case void_type: 385 { 386 memset(&result, 0, sizeof(jvalue)); 387 } 388 break; 389 } 390 return result; 391} 392 393 394void convertJValueToNPVariant(jvalue value, JNIType jniType, const char* javaTypeName, NPVariant* result) 395{ 396 switch (jniType) { 397 case void_type: 398 { 399 VOID_TO_NPVARIANT(*result); 400 } 401 break; 402 403 case object_type: 404 { 405 if (value.l) { 406 if (!strcmp(javaTypeName, "java.lang.String")) { 407 const char* v = getCharactersFromJString(static_cast<jstring>(value.l)); 408 // s is freed in NPN_ReleaseVariantValue (see npruntime.cpp) 409 const char* s = strdup(v); 410 releaseCharactersForJString(static_cast<jstring>(value.l), v); 411 STRINGZ_TO_NPVARIANT(s, *result); 412 } else 413 OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(new JavaInstance(value.l)), *result); 414 } else 415 VOID_TO_NPVARIANT(*result); 416 } 417 break; 418 419 case boolean_type: 420 { 421 BOOLEAN_TO_NPVARIANT(value.z, *result); 422 } 423 break; 424 425 case byte_type: 426 { 427 INT32_TO_NPVARIANT(value.b, *result); 428 } 429 break; 430 431 case char_type: 432 { 433#ifndef EMULATE_JSC_BINDINGS 434 // There is no char type in JavaScript - just strings 1 character 435 // long. So just converting it to an int above doesn't work. Again, 436 // we emulate the behavior for now for maximum compatability. 437 if (!strcmp(javaTypeName, "char")) { 438 const char c = value.c; 439 const char* v = strndup(&c, 1); 440 STRINGZ_TO_NPVARIANT(v, *result); 441 } else 442#endif 443 INT32_TO_NPVARIANT(value.c, *result); 444 } 445 break; 446 447 case short_type: 448 { 449 INT32_TO_NPVARIANT(value.s, *result); 450 } 451 break; 452 453 case int_type: 454 { 455 INT32_TO_NPVARIANT(value.i, *result); 456 } 457 break; 458 459 // TODO: Check if cast to double is needed. 460 case long_type: 461 { 462 DOUBLE_TO_NPVARIANT(value.j, *result); 463 } 464 break; 465 466 case float_type: 467 { 468 DOUBLE_TO_NPVARIANT(value.f, *result); 469 } 470 break; 471 472 case double_type: 473 { 474 DOUBLE_TO_NPVARIANT(value.d, *result); 475 } 476 break; 477 478 case invalid_type: 479 default: 480 { 481 VOID_TO_NPVARIANT(*result); 482 } 483 break; 484 } 485} 486 487} // namespace Bindings 488 489} // namespace JSC 490 491#endif // ENABLE(JAVA_BRIDGE) 492