1 /*
2 * Copyright (C) 2003, 2010 Apple, Inc. All rights reserved.
3 * Copyright 2009, The Android Open Source Project
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "JNIUtilityPrivate.h"
29
30 #if ENABLE(JAVA_BRIDGE)
31
32 #include "JavaArrayJSC.h"
33 #include "JavaInstanceJSC.h"
34 #include "JavaRuntimeObject.h"
35 #include "jni_jsobject.h"
36 #include "runtime_array.h"
37 #include "runtime_object.h"
38 #include "runtime_root.h"
39 #include <runtime/JSArray.h>
40 #include <runtime/JSLock.h>
41
42 namespace JSC {
43
44 namespace Bindings {
45
convertArrayInstanceToJavaArray(ExecState * exec,JSArray * jsArray,const char * javaClassName)46 static jobject convertArrayInstanceToJavaArray(ExecState* exec, JSArray* jsArray, const char* javaClassName)
47 {
48 JNIEnv* env = getJNIEnv();
49 // As JS Arrays can contain a mixture of objects, assume we can convert to
50 // the requested Java Array type requested, unless the array type is some object array
51 // other than a string.
52 unsigned length = jsArray->length();
53 jobjectArray jarray = 0;
54
55 // Build the correct array type
56 switch (javaTypeFromPrimitiveType(javaClassName[1])) {
57 case JavaTypeObject:
58 {
59 // Only support string object types
60 if (!strcmp("[Ljava.lang.String;", javaClassName)) {
61 jarray = (jobjectArray)env->NewObjectArray(length,
62 env->FindClass("java/lang/String"),
63 env->NewStringUTF(""));
64 for (unsigned i = 0; i < length; i++) {
65 JSValue item = jsArray->get(exec, i);
66 UString stringValue = item.toString(exec);
67 env->SetObjectArrayElement(jarray, i,
68 env->functions->NewString(env, (const jchar *)stringValue.characters(), stringValue.length()));
69 }
70 }
71 break;
72 }
73
74 case JavaTypeBoolean:
75 {
76 jarray = (jobjectArray)env->NewBooleanArray(length);
77 for (unsigned i = 0; i < length; i++) {
78 JSValue item = jsArray->get(exec, i);
79 jboolean value = (jboolean)item.toNumber(exec);
80 env->SetBooleanArrayRegion((jbooleanArray)jarray, (jsize)i, (jsize)1, &value);
81 }
82 break;
83 }
84
85 case JavaTypeByte:
86 {
87 jarray = (jobjectArray)env->NewByteArray(length);
88 for (unsigned i = 0; i < length; i++) {
89 JSValue item = jsArray->get(exec, i);
90 jbyte value = (jbyte)item.toNumber(exec);
91 env->SetByteArrayRegion((jbyteArray)jarray, (jsize)i, (jsize)1, &value);
92 }
93 break;
94 }
95
96 case JavaTypeChar:
97 {
98 jarray = (jobjectArray)env->NewCharArray(length);
99 for (unsigned i = 0; i < length; i++) {
100 JSValue item = jsArray->get(exec, i);
101 UString stringValue = item.toString(exec);
102 jchar value = 0;
103 if (stringValue.length() > 0)
104 value = ((const jchar*)stringValue.characters())[0];
105 env->SetCharArrayRegion((jcharArray)jarray, (jsize)i, (jsize)1, &value);
106 }
107 break;
108 }
109
110 case JavaTypeShort:
111 {
112 jarray = (jobjectArray)env->NewShortArray(length);
113 for (unsigned i = 0; i < length; i++) {
114 JSValue item = jsArray->get(exec, i);
115 jshort value = (jshort)item.toNumber(exec);
116 env->SetShortArrayRegion((jshortArray)jarray, (jsize)i, (jsize)1, &value);
117 }
118 break;
119 }
120
121 case JavaTypeInt:
122 {
123 jarray = (jobjectArray)env->NewIntArray(length);
124 for (unsigned i = 0; i < length; i++) {
125 JSValue item = jsArray->get(exec, i);
126 jint value = (jint)item.toNumber(exec);
127 env->SetIntArrayRegion((jintArray)jarray, (jsize)i, (jsize)1, &value);
128 }
129 break;
130 }
131
132 case JavaTypeLong:
133 {
134 jarray = (jobjectArray)env->NewLongArray(length);
135 for (unsigned i = 0; i < length; i++) {
136 JSValue item = jsArray->get(exec, i);
137 jlong value = (jlong)item.toNumber(exec);
138 env->SetLongArrayRegion((jlongArray)jarray, (jsize)i, (jsize)1, &value);
139 }
140 break;
141 }
142
143 case JavaTypeFloat:
144 {
145 jarray = (jobjectArray)env->NewFloatArray(length);
146 for (unsigned i = 0; i < length; i++) {
147 JSValue item = jsArray->get(exec, i);
148 jfloat value = (jfloat)item.toNumber(exec);
149 env->SetFloatArrayRegion((jfloatArray)jarray, (jsize)i, (jsize)1, &value);
150 }
151 break;
152 }
153
154 case JavaTypeDouble:
155 {
156 jarray = (jobjectArray)env->NewDoubleArray(length);
157 for (unsigned i = 0; i < length; i++) {
158 JSValue item = jsArray->get(exec, i);
159 jdouble value = (jdouble)item.toNumber(exec);
160 env->SetDoubleArrayRegion((jdoubleArray)jarray, (jsize)i, (jsize)1, &value);
161 }
162 break;
163 }
164
165 case JavaTypeArray: // don't handle embedded arrays
166 case JavaTypeVoid: // Don't expect arrays of void objects
167 case JavaTypeInvalid: // Array of unknown objects
168 break;
169 }
170
171 // if it was not one of the cases handled, then null is returned
172 return jarray;
173 }
174
convertValueToJValue(ExecState * exec,RootObject * rootObject,JSValue value,JavaType javaType,const char * javaClassName)175 jvalue convertValueToJValue(ExecState* exec, RootObject* rootObject, JSValue value, JavaType javaType, const char* javaClassName)
176 {
177 JSLock lock(SilenceAssertionsOnly);
178
179 jvalue result;
180 memset(&result, 0, sizeof(jvalue));
181
182 switch (javaType) {
183 case JavaTypeArray:
184 case JavaTypeObject:
185 {
186 // FIXME: JavaJSObject::convertValueToJObject functionality is almost exactly the same,
187 // these functions should use common code.
188
189 if (value.isObject()) {
190 JSObject* object = asObject(value);
191 if (object->inherits(&JavaRuntimeObject::s_info)) {
192 // Unwrap a Java instance.
193 JavaRuntimeObject* runtimeObject = static_cast<JavaRuntimeObject*>(object);
194 JavaInstance* instance = runtimeObject->getInternalJavaInstance();
195 if (instance)
196 result.l = instance->javaInstance();
197 } else if (object->classInfo() == &RuntimeArray::s_info) {
198 // Input is a JavaScript Array that was originally created from a Java Array
199 RuntimeArray* imp = static_cast<RuntimeArray*>(object);
200 JavaArray* array = static_cast<JavaArray*>(imp->getConcreteArray());
201 result.l = array->javaArray();
202 } else if (object->classInfo() == &JSArray::s_info) {
203 // Input is a Javascript Array. We need to create it to a Java Array.
204 result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName);
205 } else if ((!result.l && (!strcmp(javaClassName, "java.lang.Object")))
206 || (!strcmp(javaClassName, "netscape.javascript.JSObject"))) {
207 // Wrap objects in JSObject instances.
208 JNIEnv* env = getJNIEnv();
209 jclass jsObjectClass = env->FindClass("sun/plugin/javascript/webkit/JSObject");
210 jmethodID constructorID = env->GetMethodID(jsObjectClass, "<init>", "(J)V");
211 if (constructorID) {
212 jlong nativeHandle = ptr_to_jlong(object);
213 rootObject->gcProtect(object);
214 result.l = env->NewObject(jsObjectClass, constructorID, nativeHandle);
215 }
216 }
217 }
218
219 // Create an appropriate Java object if target type is java.lang.Object.
220 if (!result.l && !strcmp(javaClassName, "java.lang.Object")) {
221 if (value.isString()) {
222 UString stringValue = asString(value)->value(exec);
223 JNIEnv* env = getJNIEnv();
224 jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length());
225 result.l = javaString;
226 } else if (value.isNumber()) {
227 double doubleValue = value.uncheckedGetNumber();
228 JNIEnv* env = getJNIEnv();
229 jclass clazz = env->FindClass("java/lang/Double");
230 jmethodID constructor = env->GetMethodID(clazz, "<init>", "(D)V");
231 jobject javaDouble = env->functions->NewObject(env, clazz, constructor, doubleValue);
232 result.l = javaDouble;
233 } else if (value.isBoolean()) {
234 bool boolValue = value.getBoolean();
235 JNIEnv* env = getJNIEnv();
236 jclass clazz = env->FindClass("java/lang/Boolean");
237 jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Z)V");
238 jobject javaBoolean = env->functions->NewObject(env, clazz, constructor, boolValue);
239 result.l = javaBoolean;
240 } else if (value.isUndefined()) {
241 UString stringValue = "undefined";
242 JNIEnv* env = getJNIEnv();
243 jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length());
244 result.l = javaString;
245 }
246 }
247
248 // Convert value to a string if the target type is a java.lang.String, and we're not
249 // converting from a null.
250 if (!result.l && !strcmp(javaClassName, "java.lang.String")) {
251 if (!value.isNull()) {
252 UString stringValue = value.toString(exec);
253 JNIEnv* env = getJNIEnv();
254 jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length());
255 result.l = javaString;
256 }
257 }
258 }
259 break;
260
261 case JavaTypeBoolean:
262 {
263 result.z = (jboolean)value.toNumber(exec);
264 }
265 break;
266
267 case JavaTypeByte:
268 {
269 result.b = (jbyte)value.toNumber(exec);
270 }
271 break;
272
273 case JavaTypeChar:
274 {
275 result.c = (jchar)value.toNumber(exec);
276 }
277 break;
278
279 case JavaTypeShort:
280 {
281 result.s = (jshort)value.toNumber(exec);
282 }
283 break;
284
285 case JavaTypeInt:
286 {
287 result.i = (jint)value.toNumber(exec);
288 }
289 break;
290
291 case JavaTypeLong:
292 {
293 result.j = (jlong)value.toNumber(exec);
294 }
295 break;
296
297 case JavaTypeFloat:
298 {
299 result.f = (jfloat)value.toNumber(exec);
300 }
301 break;
302
303 case JavaTypeDouble:
304 {
305 result.d = (jdouble)value.toNumber(exec);
306 }
307 break;
308
309 case JavaTypeInvalid:
310 case JavaTypeVoid:
311 break;
312 }
313 return result;
314 }
315
316 } // end of namespace Bindings
317
318 } // end of namespace JSC
319
320 #endif // ENABLE(JAVA_BRIDGE)
321