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
41using namespace JSC;
42using namespace JSC::Bindings;
43using namespace WebCore;
44
45JSValue 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
53JavaArray::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
63JavaArray::~JavaArray()
64{
65    free(const_cast<char*>(m_type));
66}
67
68RootObject* JavaArray::rootObject() const
69{
70    return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
71}
72
73void 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
149JSValue 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
241unsigned int JavaArray::getLength() const
242{
243    return m_length;
244}
245
246#endif // ENABLE(JAVA_BRIDGE)
247