• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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