1 /*
2 * Copyright (C) 2003, 2004, 2005, 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright 2010, 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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "JavaArrayJSC.h"
29
30 #if ENABLE(JAVA_BRIDGE)
31
32 #include "JNIUtilityPrivate.h"
33 #include "JavaInstanceJSC.h"
34 #include "JobjectWrapper.h"
35 #include "Logging.h"
36 #include "runtime_array.h"
37 #include "runtime_object.h"
38 #include "runtime_root.h"
39 #include <runtime/Error.h>
40
41 using namespace JSC;
42 using namespace JSC::Bindings;
43 using namespace WebCore;
44
convertJObjectToArray(ExecState * exec,jobject anObject,const char * type,PassRefPtr<RootObject> rootObject)45 JSValue JavaArray::convertJObjectToArray(ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject> rootObject)
46 {
47 if (type[0] != '[')
48 return jsUndefined();
49
50 return new (exec) RuntimeArray(exec, new JavaArray(anObject, type, rootObject));
51 }
52
JavaArray(jobject array,const char * type,PassRefPtr<RootObject> rootObject)53 JavaArray::JavaArray(jobject array, const char* type, PassRefPtr<RootObject> rootObject)
54 : Array(rootObject)
55 {
56 m_array = new JobjectWrapper(array);
57 // Java array are fixed length, so we can cache length.
58 JNIEnv* env = getJNIEnv();
59 m_length = env->GetArrayLength(static_cast<jarray>(m_array->m_instance));
60 m_type = strdup(type);
61 }
62
~JavaArray()63 JavaArray::~JavaArray()
64 {
65 free(const_cast<char*>(m_type));
66 }
67
rootObject() const68 RootObject* JavaArray::rootObject() const
69 {
70 return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
71 }
72
setValueAt(ExecState * exec,unsigned index,JSValue aValue) const73 void JavaArray::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
74 {
75 JNIEnv* env = getJNIEnv();
76 char* javaClassName = 0;
77
78 JavaType arrayType = javaTypeFromPrimitiveType(m_type[1]);
79 if (m_type[1] == 'L') {
80 // The type of the array will be something like:
81 // "[Ljava.lang.string;". This is guaranteed, so no need
82 // for extra sanity checks.
83 javaClassName = strdup(&m_type[2]);
84 javaClassName[strchr(javaClassName, ';')-javaClassName] = 0;
85 }
86 jvalue aJValue = convertValueToJValue(exec, m_rootObject.get(), aValue, arrayType, javaClassName);
87
88 switch (arrayType) {
89 case JavaTypeObject:
90 {
91 env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray()), index, aJValue.l);
92 break;
93 }
94
95 case JavaTypeBoolean:
96 {
97 env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray()), index, 1, &aJValue.z);
98 break;
99 }
100
101 case JavaTypeByte:
102 {
103 env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray()), index, 1, &aJValue.b);
104 break;
105 }
106
107 case JavaTypeChar:
108 {
109 env->SetCharArrayRegion(static_cast<jcharArray>(javaArray()), index, 1, &aJValue.c);
110 break;
111 }
112
113 case JavaTypeShort:
114 {
115 env->SetShortArrayRegion(static_cast<jshortArray>(javaArray()), index, 1, &aJValue.s);
116 break;
117 }
118
119 case JavaTypeInt:
120 {
121 env->SetIntArrayRegion(static_cast<jintArray>(javaArray()), index, 1, &aJValue.i);
122 break;
123 }
124
125 case JavaTypeLong:
126 {
127 env->SetLongArrayRegion(static_cast<jlongArray>(javaArray()), index, 1, &aJValue.j);
128 }
129
130 case JavaTypeFloat:
131 {
132 env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray()), index, 1, &aJValue.f);
133 break;
134 }
135
136 case JavaTypeDouble:
137 {
138 env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray()), index, 1, &aJValue.d);
139 break;
140 }
141 default:
142 break;
143 }
144
145 if (javaClassName)
146 free(const_cast<char*>(javaClassName));
147 }
148
valueAt(ExecState * exec,unsigned index) const149 JSValue JavaArray::valueAt(ExecState* exec, unsigned index) const
150 {
151 JNIEnv* env = getJNIEnv();
152 JavaType arrayType = javaTypeFromPrimitiveType(m_type[1]);
153 switch (arrayType) {
154 case JavaTypeObject:
155 {
156 jobjectArray objectArray = static_cast<jobjectArray>(javaArray());
157 jobject anObject;
158 anObject = env->GetObjectArrayElement(objectArray, index);
159
160 // No object?
161 if (!anObject)
162 return jsNull();
163
164 // Nested array?
165 if (m_type[1] == '[')
166 return JavaArray::convertJObjectToArray(exec, anObject, m_type + 1, rootObject());
167 // or array of other object type?
168 return JavaInstance::create(anObject, rootObject())->createRuntimeObject(exec);
169 }
170
171 case JavaTypeBoolean:
172 {
173 jbooleanArray booleanArray = static_cast<jbooleanArray>(javaArray());
174 jboolean aBoolean;
175 env->GetBooleanArrayRegion(booleanArray, index, 1, &aBoolean);
176 return jsBoolean(aBoolean);
177 }
178
179 case JavaTypeByte:
180 {
181 jbyteArray byteArray = static_cast<jbyteArray>(javaArray());
182 jbyte aByte;
183 env->GetByteArrayRegion(byteArray, index, 1, &aByte);
184 return jsNumber(aByte);
185 }
186
187 case JavaTypeChar:
188 {
189 jcharArray charArray = static_cast<jcharArray>(javaArray());
190 jchar aChar;
191 env->GetCharArrayRegion(charArray, index, 1, &aChar);
192 return jsNumber(aChar);
193 break;
194 }
195
196 case JavaTypeShort:
197 {
198 jshortArray shortArray = static_cast<jshortArray>(javaArray());
199 jshort aShort;
200 env->GetShortArrayRegion(shortArray, index, 1, &aShort);
201 return jsNumber(aShort);
202 }
203
204 case JavaTypeInt:
205 {
206 jintArray intArray = static_cast<jintArray>(javaArray());
207 jint anInt;
208 env->GetIntArrayRegion(intArray, index, 1, &anInt);
209 return jsNumber(anInt);
210 }
211
212 case JavaTypeLong:
213 {
214 jlongArray longArray = static_cast<jlongArray>(javaArray());
215 jlong aLong;
216 env->GetLongArrayRegion(longArray, index, 1, &aLong);
217 return jsNumber(aLong);
218 }
219
220 case JavaTypeFloat:
221 {
222 jfloatArray floatArray = static_cast<jfloatArray>(javaArray());
223 jfloat aFloat;
224 env->GetFloatArrayRegion(floatArray, index, 1, &aFloat);
225 return jsNumber(aFloat);
226 }
227
228 case JavaTypeDouble:
229 {
230 jdoubleArray doubleArray = static_cast<jdoubleArray>(javaArray());
231 jdouble aDouble;
232 env->GetDoubleArrayRegion(doubleArray, index, 1, &aDouble);
233 return jsNumber(aDouble);
234 }
235 default:
236 break;
237 }
238 return jsUndefined();
239 }
240
getLength() const241 unsigned int JavaArray::getLength() const
242 {
243 return m_length;
244 }
245
246 #endif // ENABLE(JAVA_BRIDGE)
247