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 #include "JavaInstanceV8.h"
30 #include "JavaNPObjectV8.h"
31 #include "npruntime_impl.h"
32
33 namespace JSC {
34
35 namespace Bindings {
36
convertNPVariantToJValue(NPVariant value,JNIType jniType,const char * javaClassName)37 jvalue convertNPVariantToJValue(NPVariant value, JNIType jniType, const char* javaClassName)
38 {
39 jvalue result;
40 NPVariantType type = value.type;
41
42 switch (jniType) {
43 case array_type:
44 {
45 JNIEnv* env = getJNIEnv();
46 jobject javaArray;
47 NPObject* object = NPVARIANT_IS_OBJECT(value) ? NPVARIANT_TO_OBJECT(value) : 0;
48 NPVariant npvLength;
49 bool success = _NPN_GetProperty(0, object, _NPN_GetStringIdentifier("length"), &npvLength);
50 if (!success) {
51 // No length property so we don't know how many elements to put into the array.
52 // Treat this as an error.
53 #ifdef EMULATE_JSC_BINDINGS
54 // JSC sends null for an array that is not an array of strings or basic types,
55 // do this also in the unknown length case.
56 memset(&result, 0, sizeof(jvalue));
57 #else
58 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
59 // for the length of the array it was passed). Here we send a 0 length array.
60 jclass objectClass = env->FindClass("java/lang/Object");
61 javaArray = env->NewObjectArray(0, objectClass, 0);
62 env->DeleteLocalRef(objectClass);
63 #endif
64 break;
65 }
66
67 jsize length = static_cast<jsize>(NPVARIANT_TO_INT32(npvLength));
68
69 if (!strcmp(javaClassName, "[Ljava.lang.String;")) {
70 // Match JSC behavior by only allowing Object arrays if they are Strings.
71 jclass stringClass = env->FindClass("java/lang/String");
72 javaArray = env->NewObjectArray(length, stringClass, 0);
73 for (jsize i = 0; i < length; i++) {
74 NPVariant npvValue;
75 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
76 if(NPVARIANT_IS_STRING(npvValue)) {
77 NPString str = NPVARIANT_TO_STRING(npvValue);
78 env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters));
79 }
80 }
81
82 env->DeleteLocalRef(stringClass);
83 } else if (!strcmp(javaClassName, "[B")) {
84 // array of bytes
85 javaArray = env->NewByteArray(length);
86 // Now iterate over each element and add to the array.
87 for (jsize i = 0; i < length; i++) {
88 NPVariant npvValue;
89 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
90 if (NPVARIANT_IS_INT32(npvValue)) {
91 jbyte bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue));
92 env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal);
93 }
94 }
95 } else if (!strcmp(javaClassName, "[C")) {
96 // array of chars
97 javaArray = env->NewCharArray(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 jchar cVal = 0;
103 if (NPVARIANT_IS_INT32(npvValue)) {
104 cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue));
105 } else if (NPVARIANT_IS_STRING(npvValue)) {
106 NPString str = NPVARIANT_TO_STRING(npvValue);
107 cVal = str.UTF8Characters[0];
108 }
109 env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal);
110 }
111 } else if (!strcmp(javaClassName, "[D")) {
112 // array of doubles
113 javaArray = env->NewDoubleArray(length);
114 // Now iterate over each element and add to the array.
115 for (jsize i = 0; i < length; i++) {
116 NPVariant npvValue;
117 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
118 if (NPVARIANT_IS_DOUBLE(npvValue)) {
119 jdouble dVal = NPVARIANT_TO_DOUBLE(npvValue);
120 env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray), i, 1, &dVal);
121 }
122 }
123 } else if (!strcmp(javaClassName, "[F")) {
124 // array of floats
125 javaArray = env->NewFloatArray(length);
126 // Now iterate over each element and add to the array.
127 for (jsize i = 0; i < length; i++) {
128 NPVariant npvValue;
129 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
130 if (NPVARIANT_IS_DOUBLE(npvValue)) {
131 jfloat fVal = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(npvValue));
132 env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray), i, 1, &fVal);
133 }
134 }
135 } else if (!strcmp(javaClassName, "[I")) {
136 // array of ints
137 javaArray = env->NewIntArray(length);
138 // Now iterate over each element and add to the array.
139 for (jsize i = 0; i < length; i++) {
140 NPVariant npvValue;
141 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
142 if (NPVARIANT_IS_INT32(npvValue)) {
143 jint iVal = NPVARIANT_TO_INT32(npvValue);
144 env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal);
145 }
146 }
147 } else if (!strcmp(javaClassName, "[J")) {
148 // array of longs
149 javaArray = env->NewLongArray(length);
150 // Now iterate over each element and add to the array.
151 for (jsize i = 0; i < length; i++) {
152 NPVariant npvValue;
153 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
154 if (NPVARIANT_IS_INT32(npvValue)) {
155 jlong jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue));
156 env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal);
157 }
158 }
159 } else if (!strcmp(javaClassName, "[S")) {
160 // array of shorts
161 javaArray = env->NewShortArray(length);
162 // Now iterate over each element and add to the array.
163 for (jsize i = 0; i < length; i++) {
164 NPVariant npvValue;
165 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
166 if (NPVARIANT_IS_INT32(npvValue)) {
167 jshort sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue));
168 env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal);
169 }
170 }
171 } else if (!strcmp(javaClassName, "[Z")) {
172 // array of booleans
173 javaArray = env->NewBooleanArray(length);
174 // Now iterate over each element and add to the array.
175 for (jsize i = 0; i < length; i++) {
176 NPVariant npvValue;
177 _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue);
178 if (NPVARIANT_IS_BOOLEAN(npvValue)) {
179 jboolean zVal = NPVARIANT_TO_BOOLEAN(npvValue);
180 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray), i, 1, &zVal);
181 }
182 }
183 } else {
184 #ifdef EMULATE_JSC_BINDINGS
185 // JSC sends null for an array that is not an array of strings or basic types.
186 memset(&result, 0, sizeof(jvalue));
187 break;
188 #else
189 // Sending NULL as JSC does seems dangerous. (Imagine the java method that asks
190 // for the length of the array it was passed). Here we send a 0 length array.
191 jclass objectClass = env->FindClass("java/lang/Object");
192 javaArray = env->NewObjectArray(0, objectClass, 0);
193 env->DeleteLocalRef(objectClass);
194 #endif
195 }
196
197 result.l = javaArray;
198 }
199 break;
200
201 case object_type:
202 {
203 JNIEnv* env = getJNIEnv();
204 result.l = static_cast<jobject>(0);
205 jobject javaString;
206
207 // First see if we have a Java instance.
208 if (type == NPVariantType_Object) {
209 NPObject* objectImp = NPVARIANT_TO_OBJECT(value);
210 if (JavaInstance* instance = ExtractJavaInstance(objectImp))
211 result.l = instance->javaInstance();
212 }
213
214 // Now convert value to a string if the target type is a java.lang.string, and we're not
215 // converting from a Null.
216 if (!result.l && !strcmp(javaClassName, "java.lang.String")) {
217 #ifdef CONVERT_NULL_TO_EMPTY_STRING
218 if (type == NPVariantType_Null) {
219 jchar buf[2];
220 jobject javaString = env->functions->NewString(env, buf, 0);
221 result.l = javaString;
222 } else
223 #else
224 if (type == NPVariantType_String)
225 #endif
226 {
227 NPString src = NPVARIANT_TO_STRING(value);
228 javaString = env->NewStringUTF(src.UTF8Characters);
229 result.l = javaString;
230 } else if (type == NPVariantType_Int32) {
231 jint src = NPVARIANT_TO_INT32(value);
232 jclass integerClass = env->FindClass("java/lang/Integer");
233 jmethodID toString = env->GetStaticMethodID(integerClass, "toString", "(I)Ljava/lang/String;");
234 javaString = env->CallStaticObjectMethod(integerClass, toString, src);
235 result.l = javaString;
236 env->DeleteLocalRef(integerClass);
237 } else if (type == NPVariantType_Bool) {
238 jboolean src = NPVARIANT_TO_BOOLEAN(value);
239 jclass booleanClass = env->FindClass("java/lang/Boolean");
240 jmethodID toString = env->GetStaticMethodID(booleanClass, "toString", "(Z)Ljava/lang/String;");
241 javaString = env->CallStaticObjectMethod(booleanClass, toString, src);
242 result.l = javaString;
243 env->DeleteLocalRef(booleanClass);
244 } else if (type == NPVariantType_Double) {
245 jdouble src = NPVARIANT_TO_DOUBLE(value);
246 jclass doubleClass = env->FindClass("java/lang/Double");
247 jmethodID toString = env->GetStaticMethodID(doubleClass, "toString", "(D)Ljava/lang/String;");
248 javaString = env->CallStaticObjectMethod(doubleClass, toString, src);
249 result.l = javaString;
250 env->DeleteLocalRef(doubleClass);
251 }
252 #ifdef EMULATE_JSC_BINDINGS
253 // For the undefined value, JSC sends the String "undefined". Feels to me like we
254 // should send null in this case.
255 else if (!NPVARIANT_IS_NULL(value)) {
256 javaString = env->NewStringUTF("undefined");
257 result.l = javaString;
258 }
259 #endif
260 } else if (!result.l)
261 memset(&result, 0, sizeof(jvalue)); // Handle it the same as a void case
262 }
263 break;
264
265 case boolean_type:
266 {
267 if (type == NPVariantType_Bool)
268 result.z = NPVARIANT_TO_BOOLEAN(value);
269 else
270 memset(&result, 0, sizeof(jvalue)); // as void case
271 }
272 break;
273
274 case byte_type:
275 {
276 if (type == NPVariantType_Int32)
277 result.b = static_cast<char>(NPVARIANT_TO_INT32(value));
278 else
279 memset(&result, 0, sizeof(jvalue));
280 }
281 break;
282
283 case char_type:
284 {
285 if (type == NPVariantType_Int32)
286 result.c = static_cast<char>(NPVARIANT_TO_INT32(value));
287 #ifndef EMULATE_JSC_BINDINGS
288 // There is no char type in JavaScript - just strings 1 character
289 // long. So just converting it to an int above doesn't work. Again,
290 // we emulate the behavior for now for maximum compatability.
291 else if (type == NPVariantType_String) {
292 NPString str = NPVARIANT_TO_STRING(value);
293 result.c = str.UTF8Characters[0];
294 }
295 #endif
296 else
297 memset(&result, 0, sizeof(jvalue));
298 }
299 break;
300
301 case short_type:
302 {
303 if (type == NPVariantType_Int32)
304 result.s = static_cast<jshort>(NPVARIANT_TO_INT32(value));
305 else
306 memset(&result, 0, sizeof(jvalue));
307 }
308 break;
309
310 case int_type:
311 {
312 if (type == NPVariantType_Int32)
313 result.i = static_cast<jint>(NPVARIANT_TO_INT32(value));
314 else
315 memset(&result, 0, sizeof(jvalue));
316 }
317 break;
318
319 case long_type:
320 {
321 if (type == NPVariantType_Int32)
322 result.j = static_cast<jlong>(NPVARIANT_TO_INT32(value));
323 else if (type == NPVariantType_Double)
324 result.j = static_cast<jlong>(NPVARIANT_TO_DOUBLE(value));
325 else
326 memset(&result, 0, sizeof(jvalue));
327 }
328 break;
329
330 case float_type:
331 {
332 if (type == NPVariantType_Int32)
333 result.f = static_cast<jfloat>(NPVARIANT_TO_INT32(value));
334 else if (type == NPVariantType_Double)
335 result.f = static_cast<jfloat>(NPVARIANT_TO_DOUBLE(value));
336 else
337 memset(&result, 0, sizeof(jvalue));
338 }
339 break;
340
341 case double_type:
342 {
343 if (type == NPVariantType_Int32)
344 result.d = static_cast<jdouble>(NPVARIANT_TO_INT32(value));
345 else if (type == NPVariantType_Double)
346 result.d = static_cast<jdouble>(NPVARIANT_TO_DOUBLE(value));
347 else
348 memset(&result, 0, sizeof(jvalue));
349 }
350 break;
351
352 case invalid_type:
353 default:
354 case void_type:
355 {
356 memset(&result, 0, sizeof(jvalue));
357 }
358 break;
359 }
360 return result;
361 }
362
363
convertJValueToNPVariant(jvalue value,JNIType jniType,const char * javaTypeName,NPVariant * result)364 void convertJValueToNPVariant(jvalue value, JNIType jniType, const char* javaTypeName, NPVariant* result)
365 {
366 switch (jniType) {
367 case void_type:
368 {
369 VOID_TO_NPVARIANT(*result);
370 }
371 break;
372
373 case object_type:
374 {
375 if (value.l) {
376 if (!strcmp(javaTypeName, "java.lang.String")) {
377 const char* v = getCharactersFromJString(static_cast<jstring>(value.l));
378 // s is freed in NPN_ReleaseVariantValue (see npruntime.cpp)
379 const char* s = strdup(v);
380 releaseCharactersForJString(static_cast<jstring>(value.l), v);
381 STRINGZ_TO_NPVARIANT(s, *result);
382 } else
383 OBJECT_TO_NPVARIANT(JavaInstanceToNPObject(new JavaInstance(value.l)), *result);
384 } else
385 VOID_TO_NPVARIANT(*result);
386 }
387 break;
388
389 case boolean_type:
390 {
391 BOOLEAN_TO_NPVARIANT(value.z, *result);
392 }
393 break;
394
395 case byte_type:
396 {
397 INT32_TO_NPVARIANT(value.b, *result);
398 }
399 break;
400
401 case char_type:
402 {
403 #ifndef EMULATE_JSC_BINDINGS
404 // There is no char type in JavaScript - just strings 1 character
405 // long. So just converting it to an int above doesn't work. Again,
406 // we emulate the behavior for now for maximum compatability.
407 if (!strcmp(javaTypeName, "char")) {
408 const char c = value.c;
409 const char* v = strndup(&c, 1);
410 STRINGZ_TO_NPVARIANT(v, *result);
411 } else
412 #endif
413 INT32_TO_NPVARIANT(value.c, *result);
414 }
415 break;
416
417 case short_type:
418 {
419 INT32_TO_NPVARIANT(value.s, *result);
420 }
421 break;
422
423 case int_type:
424 {
425 INT32_TO_NPVARIANT(value.i, *result);
426 }
427 break;
428
429 // TODO: Check if cast to double is needed.
430 case long_type:
431 {
432 DOUBLE_TO_NPVARIANT(value.j, *result);
433 }
434 break;
435
436 case float_type:
437 {
438 DOUBLE_TO_NPVARIANT(value.f, *result);
439 }
440 break;
441
442 case double_type:
443 {
444 DOUBLE_TO_NPVARIANT(value.d, *result);
445 }
446 break;
447
448 case invalid_type:
449 default:
450 {
451 VOID_TO_NPVARIANT(*result);
452 }
453 break;
454 }
455 }
456
457 } // end of namespace Bindings
458
459 } // end of namespace JSC
460