2 * Copyright 2010, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "JNIUtilityPrivate.h"
29 #if ENABLE(JAVA_BRIDGE)
31 #include "JavaInstanceV8.h"
32 #include "JavaNPObjectV8.h"
33 #include "npruntime_impl.h"
34 #include <wtf/text/CString.h>
40 jvalue convertNPVariantToJValue(NPVariant value, const WTF::String& javaType)
42 CString javaClassName = javaType.utf8();
43 JNIType jniType = JNITypeFromClassName(javaClassName.data());
45 NPVariantType type = value.type;
50 JNIEnv* env = getJNIEnv();
52 NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0;
54 bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength);
56 // No length property so we don't know how many elements to put into the array.
57 // Treat this as an error.
58 #ifdef EMULATE_JSC_BINDINGS
59 // JSC sends null for an array that is not an array of strings or basic types,
60 // do this also in the unknown length case.
61 memset(&result, 0, sizeof(jvalue));
63 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
64 // for the length of the array it was passed). Here we send a 0 length array.
65 jclass objectClass = env->FindClass("java/lang/Object");
66 javaArray = env->NewObjectArray(0, objectClass, 0);
67 env->DeleteLocalRef(objectClass);
73 if (NPVARIANT_IS_INT32(npvLength))
74 length = static_cast<jsize>(NPVARIANT_TO_INT32(npvLength));
75 else if (NPVARIANT_IS_DOUBLE(npvLength))
76 length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(npvLength));
78 if (!strcmp(javaClassName.data(), "[Ljava.lang.String;")) {
79 // Match JSC behavior by only allowing Object arrays if they are Strings.
80 jclass stringClass = env->FindClass("java/lang/String");
81 javaArray = env->NewObjectArray(length, stringClass, 0);
82 for (jsize i = 0; i < length; i++) {
84 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
85 if(NPVARIANT_IS_STRING(npvValue)) {
86 NPString str = NPVARIANT_TO_STRING(npvValue);
87 env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters));
91 env->DeleteLocalRef(stringClass);
92 } else if (!strcmp(javaClassName.data(), "[B")) {
94 javaArray = env->NewByteArray(length);
95 // Now iterate over each element and add to the array.
96 for (jsize i = 0; i < length; i++) {
98 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
100 if (NPVARIANT_IS_INT32(npvValue)) {
101 bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue));
102 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
103 bVal = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(npvValue));
105 env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal);
107 } else if (!strcmp(javaClassName.data(), "[C")) {
109 javaArray = env->NewCharArray(length);
110 // Now iterate over each element and add to the array.
111 for (jsize i = 0; i < length; i++) {
113 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
115 if (NPVARIANT_IS_INT32(npvValue)) {
116 cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue));
117 } else if (NPVARIANT_IS_STRING(npvValue)) {
118 NPString str = NPVARIANT_TO_STRING(npvValue);
119 cVal = str.UTF8Characters[0];
121 env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal);
123 } else if (!strcmp(javaClassName.data(), "[D")) {
125 javaArray = env->NewDoubleArray(length);
126 // Now iterate over each element and add to the array.
127 for (jsize i = 0; i < length; i++) {
129 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
130 if (NPVARIANT_IS_DOUBLE(npvValue)) {
131 jdouble dVal = NPVARIANT_TO_DOUBLE(npvValue);
132 env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray), i, 1, &dVal);
135 } else if (!strcmp(javaClassName.data(), "[F")) {
137 javaArray = env->NewFloatArray(length);
138 // Now iterate over each element and add to the array.
139 for (jsize i = 0; i < length; i++) {
141 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
142 if (NPVARIANT_IS_DOUBLE(npvValue)) {
143 jfloat fVal = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(npvValue));
144 env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray), i, 1, &fVal);
147 } else if (!strcmp(javaClassName.data(), "[I")) {
149 javaArray = env->NewIntArray(length);
150 // Now iterate over each element and add to the array.
151 for (jsize i = 0; i < length; i++) {
153 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
155 if (NPVARIANT_IS_INT32(npvValue)) {
156 iVal = NPVARIANT_TO_INT32(npvValue);
157 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
158 iVal = static_cast<jint>(NPVARIANT_TO_DOUBLE(npvValue));
160 env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal);
162 } else if (!strcmp(javaClassName.data(), "[J")) {
164 javaArray = env->NewLongArray(length);
165 // Now iterate over each element and add to the array.
166 for (jsize i = 0; i < length; i++) {
168 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
170 if (NPVARIANT_IS_INT32(npvValue)) {
171 jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue));
172 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
173 jVal = static_cast<jlong>(NPVARIANT_TO_DOUBLE(npvValue));
175 env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal);
177 } else if (!strcmp(javaClassName.data(), "[S")) {
179 javaArray = env->NewShortArray(length);
180 // Now iterate over each element and add to the array.
181 for (jsize i = 0; i < length; i++) {
183 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
185 if (NPVARIANT_IS_INT32(npvValue)) {
186 sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue));
187 } else if (NPVARIANT_IS_DOUBLE(npvValue)) {
188 sVal = static_cast<jshort>(NPVARIANT_TO_DOUBLE(npvValue));
190 env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal);
192 } else if (!strcmp(javaClassName.data(), "[Z")) {
194 javaArray = env->NewBooleanArray(length);
195 // Now iterate over each element and add to the array.
196 for (jsize i = 0; i < length; i++) {
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);
205 #ifdef EMULATE_JSC_BINDINGS
206 // JSC sends null for an array that is not an array of strings or basic types.
207 memset(&result, 0, sizeof(jvalue));
210 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
211 // for the length of the array it was passed). Here we send a 0 length array.
212 jclass objectClass = env->FindClass("java/lang/Object");
213 javaArray = env->NewObjectArray(0, objectClass, 0);
214 env->DeleteLocalRef(objectClass);
218 result.l = javaArray;
224 JNIEnv* env = getJNIEnv();
225 result.l = static_cast<jobject>(0);
228 // First see if we have a Java instance.
229 if (type == NPVariantType_Object) {
230 NPObject* objectImp = NPVARIANT_TO_OBJECT(value);
231 if (JavaInstance* instance = ExtractJavaInstance(objectImp))
232 result.l = instance->javaInstance();
235 // Now convert value to a string if the target type is a java.lang.string, and we're not
236 // converting from a Null.
237 if (!result.l && !strcmp(javaClassName.data(), "java.lang.String")) {
238 #ifdef CONVERT_NULL_TO_EMPTY_STRING
239 if (type == NPVariantType_Null) {
241 jobject javaString = env->functions->NewString(env, buf, 0);
242 result.l = javaString;
245 if (type == NPVariantType_String)
248 NPString src = NPVARIANT_TO_STRING(value);
249 javaString = env->NewStringUTF(src.UTF8Characters);
250 result.l = javaString;
251 } else if (type == NPVariantType_Int32) {
252 jint src = NPVARIANT_TO_INT32(value);
253 jclass integerClass = env->FindClass("java/lang/Integer");
254 jmethodID toString = env->GetStaticMethodID(integerClass, "toString", "(I)Ljava/lang/String;");
255 javaString = env->CallStaticObjectMethod(integerClass, toString, src);
256 result.l = javaString;
257 env->DeleteLocalRef(integerClass);
258 } else if (type == NPVariantType_Bool) {
259 jboolean src = NPVARIANT_TO_BOOLEAN(value);
260 jclass booleanClass = env->FindClass("java/lang/Boolean");
261 jmethodID toString = env->GetStaticMethodID(booleanClass, "toString", "(Z)Ljava/lang/String;");
262 javaString = env->CallStaticObjectMethod(booleanClass, toString, src);
263 result.l = javaString;
264 env->DeleteLocalRef(booleanClass);
265 } else if (type == NPVariantType_Double) {
266 jdouble src = NPVARIANT_TO_DOUBLE(value);
267 jclass doubleClass = env->FindClass("java/lang/Double");
268 jmethodID toString = env->GetStaticMethodID(doubleClass, "toString", "(D)Ljava/lang/String;");
269 javaString = env->CallStaticObjectMethod(doubleClass, toString, src);
270 result.l = javaString;
271 env->DeleteLocalRef(doubleClass);
273 #ifdef EMULATE_JSC_BINDINGS
274 // For the undefined value, JSC sends the String "undefined". Feels to me like we
275 // should send null in this case.
276 else if (!NPVARIANT_IS_NULL(value)) {
277 javaString = env->NewStringUTF("undefined");
278 result.l = javaString;
281 } else if (!result.l)
282 memset(&result, 0, sizeof(jvalue)); // Handle it the same as a void case
288 if (type == NPVariantType_Bool)
289 result.z = NPVARIANT_TO_BOOLEAN(value);
291 memset(&result, 0, sizeof(jvalue)); // as void case
297 if (type == NPVariantType_Int32)
298 result.b = static_cast<jbyte>(NPVARIANT_TO_INT32(value));
299 else if (type == NPVariantType_Double)
300 result.b = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(value));
302 memset(&result, 0, sizeof(jvalue));
308 if (type == NPVariantType_Int32)
309 result.c = static_cast<char>(NPVARIANT_TO_INT32(value));
310 #ifndef EMULATE_JSC_BINDINGS
311 // There is no char type in JavaScript - just strings 1 character
312 // long. So just converting it to an int above doesn't work. Again,
313 // we emulate the behavior for now for maximum compatability.
314 else if (type == NPVariantType_String) {
315 NPString str = NPVARIANT_TO_STRING(value);
316 result.c = str.UTF8Characters[0];
320 memset(&result, 0, sizeof(jvalue));
326 if (type == NPVariantType_Int32)
327 result.s = static_cast<jshort>(NPVARIANT_TO_INT32(value));
328 else if (type == NPVariantType_Double)
329 result.s = static_cast<jshort>(NPVARIANT_TO_DOUBLE(value));
331 memset(&result, 0, sizeof(jvalue));
337 if (type == NPVariantType_Int32)
338 result.i = static_cast<jint>(NPVARIANT_TO_INT32(value));
339 else if (type == NPVariantType_Double)
340 result.i = static_cast<jint>(NPVARIANT_TO_DOUBLE(value));
342 memset(&result, 0, sizeof(jvalue));
348 if (type == NPVariantType_Int32)
349 result.j = static_cast<jlong>(NPVARIANT_TO_INT32(value));
350 else if (type == NPVariantType_Double)
351 result.j = static_cast<jlong>(NPVARIANT_TO_DOUBLE(value));
353 memset(&result, 0, sizeof(jvalue));
359 if (type == NPVariantType_Int32)
360 result.f = static_cast<jfloat>(NPVARIANT_TO_INT32(value));
361 else if (type == NPVariantType_Double)
362 result.f = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(value));
364 memset(&result, 0, sizeof(jvalue));
370 if (type == NPVariantType_Int32)
371 result.d = static_cast<jdouble>(NPVARIANT_TO_INT32(value));
372 else if (type == NPVariantType_Double)
373 result.d = static_cast<jdouble>(NPVARIANT_TO_DOUBLE(value));
375 memset(&result, 0, sizeof(jvalue));
383 memset(&result, 0, sizeof(jvalue));
391 void convertJValueToNPVariant(jvalue value, JNIType jniType, const char* javaTypeName, NPVariant* result)
396 VOID_TO_NPVARIANT(*result);
403 if (!strcmp(javaTypeName, "java.lang.String")) {
404 const char* v = getCharactersFromJString(static_cast<jstring>(value.l));
405 // s is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
406 const char* s = strdup(v);
407 releaseCharactersForJString(static_cast<jstring>(value.l), v);
408 STRINGZ_TO_NPVARIANT(s, *result);
410 OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(new JavaInstance(value.l)), *result);
412 VOID_TO_NPVARIANT(*result);
418 BOOLEAN_TO_NPVARIANT(value.z, *result);
424 INT32_TO_NPVARIANT(value.b, *result);
430 #ifndef EMULATE_JSC_BINDINGS
431 // There is no char type in JavaScript - just strings 1 character
432 // long. So just converting it to an int above doesn't work. Again,
433 // we emulate the behavior for now for maximum compatability.
434 if (!strcmp(javaTypeName, "char")) {
435 const char c = value.c;
436 const char* v = strndup(&c, 1);
437 STRINGZ_TO_NPVARIANT(v, *result);
440 INT32_TO_NPVARIANT(value.c, *result);
446 INT32_TO_NPVARIANT(value.s, *result);
452 INT32_TO_NPVARIANT(value.i, *result);
456 // TODO: Check if cast to double is needed.
459 DOUBLE_TO_NPVARIANT(value.j, *result);
465 DOUBLE_TO_NPVARIANT(value.f, *result);
471 DOUBLE_TO_NPVARIANT(value.d, *result);
478 VOID_TO_NPVARIANT(*result);
484 } // namespace Bindings
488 #endif // ENABLE(JAVA_BRIDGE)