1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/android/jni_array.h"
6
7#include "base/android/jni_android.h"
8#include "base/android/jni_string.h"
9#include "base/logging.h"
10
11namespace base {
12namespace android {
13namespace {
14
15// As |GetArrayLength| makes no guarantees about the returned value (e.g., it
16// may be -1 if |array| is not a valid Java array), provide a safe wrapper
17// that always returns a valid, non-negative size.
18template <typename JavaArrayType>
19size_t SafeGetArrayLength(JNIEnv* env, JavaArrayType jarray) {
20  DCHECK(jarray);
21  jsize length = env->GetArrayLength(jarray);
22  DCHECK_GE(length, 0) << "Invalid array length: " << length;
23  return static_cast<size_t>(std::max(0, length));
24}
25
26}  // namespace
27
28ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env,
29                                               const uint8_t* bytes,
30                                               size_t len) {
31  jbyteArray byte_array = env->NewByteArray(len);
32  CheckException(env);
33  DCHECK(byte_array);
34
35  env->SetByteArrayRegion(
36      byte_array, 0, len, reinterpret_cast<const jbyte*>(bytes));
37  CheckException(env);
38
39  return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
40}
41
42ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
43    JNIEnv* env,
44    const std::vector<uint8_t>& bytes) {
45  return ToJavaByteArray(env, bytes.data(), bytes.size());
46}
47
48ScopedJavaLocalRef<jintArray> ToJavaIntArray(
49    JNIEnv* env, const int* ints, size_t len) {
50  jintArray int_array = env->NewIntArray(len);
51  CheckException(env);
52  DCHECK(int_array);
53
54  env->SetIntArrayRegion(
55      int_array, 0, len, reinterpret_cast<const jint*>(ints));
56  CheckException(env);
57
58  return ScopedJavaLocalRef<jintArray>(env, int_array);
59}
60
61ScopedJavaLocalRef<jintArray> ToJavaIntArray(
62    JNIEnv* env, const std::vector<int>& ints) {
63  return ToJavaIntArray(env, ints.data(), ints.size());
64}
65
66ScopedJavaLocalRef<jlongArray> ToJavaLongArray(JNIEnv* env,
67                                               const int64_t* longs,
68                                               size_t len) {
69  jlongArray long_array = env->NewLongArray(len);
70  CheckException(env);
71  DCHECK(long_array);
72
73  env->SetLongArrayRegion(
74      long_array, 0, len, reinterpret_cast<const jlong*>(longs));
75  CheckException(env);
76
77  return ScopedJavaLocalRef<jlongArray>(env, long_array);
78}
79
80// Returns a new Java long array converted from the given int64_t array.
81BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
82    JNIEnv* env,
83    const std::vector<int64_t>& longs) {
84  return ToJavaLongArray(env, longs.data(), longs.size());
85}
86
87// Returns a new Java float array converted from the given C++ float array.
88BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
89    JNIEnv* env, const float* floats, size_t len) {
90  jfloatArray float_array = env->NewFloatArray(len);
91  CheckException(env);
92  DCHECK(float_array);
93
94  env->SetFloatArrayRegion(
95      float_array, 0, len, reinterpret_cast<const jfloat*>(floats));
96  CheckException(env);
97
98  return ScopedJavaLocalRef<jfloatArray>(env, float_array);
99}
100
101BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
102    JNIEnv* env,
103    const std::vector<float>& floats) {
104  return ToJavaFloatArray(env, floats.data(), floats.size());
105}
106
107ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
108    JNIEnv* env, const std::vector<std::string>& v) {
109  ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
110  jobjectArray joa = env->NewObjectArray(v.size(),
111                                         byte_array_clazz.obj(), NULL);
112  CheckException(env);
113
114  for (size_t i = 0; i < v.size(); ++i) {
115    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(
116        env, reinterpret_cast<const uint8_t*>(v[i].data()), v[i].length());
117    env->SetObjectArrayElement(joa, i, byte_array.obj());
118  }
119  return ScopedJavaLocalRef<jobjectArray>(env, joa);
120}
121
122ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
123    JNIEnv* env, const std::vector<std::string>& v) {
124  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
125  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
126  CheckException(env);
127
128  for (size_t i = 0; i < v.size(); ++i) {
129    ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
130    env->SetObjectArrayElement(joa, i, item.obj());
131  }
132  return ScopedJavaLocalRef<jobjectArray>(env, joa);
133}
134
135ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
136    JNIEnv* env, const std::vector<string16>& v) {
137  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
138  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
139  CheckException(env);
140
141  for (size_t i = 0; i < v.size(); ++i) {
142    ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
143    env->SetObjectArrayElement(joa, i, item.obj());
144  }
145  return ScopedJavaLocalRef<jobjectArray>(env, joa);
146}
147
148void AppendJavaStringArrayToStringVector(JNIEnv* env,
149                                         jobjectArray array,
150                                         std::vector<string16>* out) {
151  DCHECK(out);
152  if (!array)
153    return;
154  size_t len = SafeGetArrayLength(env, array);
155  size_t back = out->size();
156  out->resize(back + len);
157  for (size_t i = 0; i < len; ++i) {
158    ScopedJavaLocalRef<jstring> str(env,
159        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
160    ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i]));
161  }
162}
163
164void AppendJavaStringArrayToStringVector(JNIEnv* env,
165                                         jobjectArray array,
166                                         std::vector<std::string>* out) {
167  DCHECK(out);
168  if (!array)
169    return;
170  size_t len = SafeGetArrayLength(env, array);
171  size_t back = out->size();
172  out->resize(back + len);
173  for (size_t i = 0; i < len; ++i) {
174    ScopedJavaLocalRef<jstring> str(env,
175        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
176    ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i]));
177  }
178}
179
180void AppendJavaByteArrayToByteVector(JNIEnv* env,
181                                     jbyteArray byte_array,
182                                     std::vector<uint8_t>* out) {
183  DCHECK(out);
184  if (!byte_array)
185    return;
186  size_t len = SafeGetArrayLength(env, byte_array);
187  if (!len)
188    return;
189  size_t back = out->size();
190  out->resize(back + len);
191  env->GetByteArrayRegion(byte_array, 0, len,
192                          reinterpret_cast<int8_t*>(&(*out)[back]));
193}
194
195void JavaByteArrayToByteVector(JNIEnv* env,
196                               jbyteArray byte_array,
197                               std::vector<uint8_t>* out) {
198  DCHECK(out);
199  DCHECK(byte_array);
200  out->clear();
201  AppendJavaByteArrayToByteVector(env, byte_array, out);
202}
203
204void JavaIntArrayToIntVector(JNIEnv* env,
205                             jintArray int_array,
206                             std::vector<int>* out) {
207  DCHECK(out);
208  size_t len = SafeGetArrayLength(env, int_array);
209  out->resize(len);
210  if (!len)
211    return;
212  // TODO(jdduke): Use |out->data()| for pointer access after switch to libc++,
213  // both here and in the other conversion routines. See crbug.com/427718.
214  env->GetIntArrayRegion(int_array, 0, len, &(*out)[0]);
215}
216
217void JavaLongArrayToInt64Vector(JNIEnv* env,
218                                jlongArray long_array,
219                                std::vector<int64_t>* out) {
220  DCHECK(out);
221  std::vector<jlong> temp;
222  JavaLongArrayToLongVector(env, long_array, &temp);
223  out->resize(0);
224  out->insert(out->begin(), temp.begin(), temp.end());
225}
226
227void JavaLongArrayToLongVector(JNIEnv* env,
228                               jlongArray long_array,
229                               std::vector<jlong>* out) {
230  DCHECK(out);
231  size_t len = SafeGetArrayLength(env, long_array);
232  out->resize(len);
233  if (!len)
234    return;
235  env->GetLongArrayRegion(long_array, 0, len, &(*out)[0]);
236}
237
238void JavaFloatArrayToFloatVector(JNIEnv* env,
239                                 jfloatArray float_array,
240                                 std::vector<float>* out) {
241  DCHECK(out);
242  size_t len = SafeGetArrayLength(env, float_array);
243  out->resize(len);
244  if (!len)
245    return;
246  env->GetFloatArrayRegion(float_array, 0, len, &(*out)[0]);
247}
248
249void JavaArrayOfByteArrayToStringVector(
250    JNIEnv* env,
251    jobjectArray array,
252    std::vector<std::string>* out) {
253  DCHECK(out);
254  size_t len = SafeGetArrayLength(env, array);
255  out->resize(len);
256  for (size_t i = 0; i < len; ++i) {
257    ScopedJavaLocalRef<jbyteArray> bytes_array(
258        env, static_cast<jbyteArray>(
259            env->GetObjectArrayElement(array, i)));
260    jsize bytes_len = env->GetArrayLength(bytes_array.obj());
261    jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), nullptr);
262    (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len);
263    env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT);
264  }
265}
266
267void JavaArrayOfIntArrayToIntVector(
268    JNIEnv* env,
269    jobjectArray array,
270    std::vector<std::vector<int>>* out) {
271  DCHECK(out);
272  size_t len = SafeGetArrayLength(env, array);
273  out->resize(len);
274  for (size_t i = 0; i < len; ++i) {
275    ScopedJavaLocalRef<jintArray> int_array(
276        env, static_cast<jintArray>(env->GetObjectArrayElement(array, i)));
277    JavaIntArrayToIntVector(env, int_array.obj(), &((*out)[i]));
278  }
279}
280
281}  // namespace android
282}  // namespace base
283