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 
11 namespace base {
12 namespace android {
13 namespace {
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.
18 template <typename JavaArrayType>
SafeGetArrayLength(JNIEnv * env,JavaArrayType jarray)19 size_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 
ToJavaByteArray(JNIEnv * env,const uint8_t * bytes,size_t len)28 ScopedJavaLocalRef<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 
ToJavaByteArray(JNIEnv * env,const std::vector<uint8_t> & bytes)42 ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
43     JNIEnv* env,
44     const std::vector<uint8_t>& bytes) {
45   return ToJavaByteArray(env, bytes.data(), bytes.size());
46 }
47 
ToJavaBooleanArray(JNIEnv * env,const bool * bools,size_t len)48 ScopedJavaLocalRef<jbooleanArray> ToJavaBooleanArray(JNIEnv* env,
49                                                      const bool* bools,
50                                                      size_t len) {
51   jbooleanArray boolean_array = env->NewBooleanArray(len);
52   CheckException(env);
53   DCHECK(boolean_array);
54 
55   env->SetBooleanArrayRegion(boolean_array, 0, len,
56                              reinterpret_cast<const jboolean*>(bools));
57   CheckException(env);
58 
59   return ScopedJavaLocalRef<jbooleanArray>(env, boolean_array);
60 }
61 
ToJavaIntArray(JNIEnv * env,const int * ints,size_t len)62 ScopedJavaLocalRef<jintArray> ToJavaIntArray(
63     JNIEnv* env, const int* ints, size_t len) {
64   jintArray int_array = env->NewIntArray(len);
65   CheckException(env);
66   DCHECK(int_array);
67 
68   env->SetIntArrayRegion(
69       int_array, 0, len, reinterpret_cast<const jint*>(ints));
70   CheckException(env);
71 
72   return ScopedJavaLocalRef<jintArray>(env, int_array);
73 }
74 
ToJavaIntArray(JNIEnv * env,const std::vector<int> & ints)75 ScopedJavaLocalRef<jintArray> ToJavaIntArray(
76     JNIEnv* env, const std::vector<int>& ints) {
77   return ToJavaIntArray(env, ints.data(), ints.size());
78 }
79 
ToJavaLongArray(JNIEnv * env,const int64_t * longs,size_t len)80 ScopedJavaLocalRef<jlongArray> ToJavaLongArray(JNIEnv* env,
81                                                const int64_t* longs,
82                                                size_t len) {
83   jlongArray long_array = env->NewLongArray(len);
84   CheckException(env);
85   DCHECK(long_array);
86 
87   env->SetLongArrayRegion(
88       long_array, 0, len, reinterpret_cast<const jlong*>(longs));
89   CheckException(env);
90 
91   return ScopedJavaLocalRef<jlongArray>(env, long_array);
92 }
93 
94 // Returns a new Java long array converted from the given int64_t array.
ToJavaLongArray(JNIEnv * env,const std::vector<int64_t> & longs)95 BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
96     JNIEnv* env,
97     const std::vector<int64_t>& longs) {
98   return ToJavaLongArray(env, longs.data(), longs.size());
99 }
100 
101 // Returns a new Java float array converted from the given C++ float array.
ToJavaFloatArray(JNIEnv * env,const float * floats,size_t len)102 BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
103     JNIEnv* env, const float* floats, size_t len) {
104   jfloatArray float_array = env->NewFloatArray(len);
105   CheckException(env);
106   DCHECK(float_array);
107 
108   env->SetFloatArrayRegion(
109       float_array, 0, len, reinterpret_cast<const jfloat*>(floats));
110   CheckException(env);
111 
112   return ScopedJavaLocalRef<jfloatArray>(env, float_array);
113 }
114 
ToJavaFloatArray(JNIEnv * env,const std::vector<float> & floats)115 BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
116     JNIEnv* env,
117     const std::vector<float>& floats) {
118   return ToJavaFloatArray(env, floats.data(), floats.size());
119 }
120 
ToJavaArrayOfByteArray(JNIEnv * env,const std::vector<std::string> & v)121 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
122     JNIEnv* env, const std::vector<std::string>& v) {
123   ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
124   jobjectArray joa = env->NewObjectArray(v.size(),
125                                          byte_array_clazz.obj(), NULL);
126   CheckException(env);
127 
128   for (size_t i = 0; i < v.size(); ++i) {
129     ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(
130         env, reinterpret_cast<const uint8_t*>(v[i].data()), v[i].length());
131     env->SetObjectArrayElement(joa, i, byte_array.obj());
132   }
133   return ScopedJavaLocalRef<jobjectArray>(env, joa);
134 }
135 
ToJavaArrayOfStrings(JNIEnv * env,const std::vector<std::string> & v)136 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
137     JNIEnv* env, const std::vector<std::string>& v) {
138   ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
139   jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
140   CheckException(env);
141 
142   for (size_t i = 0; i < v.size(); ++i) {
143     ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
144     env->SetObjectArrayElement(joa, i, item.obj());
145   }
146   return ScopedJavaLocalRef<jobjectArray>(env, joa);
147 }
148 
ToJavaArrayOfStrings(JNIEnv * env,const std::vector<string16> & v)149 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
150     JNIEnv* env, const std::vector<string16>& v) {
151   ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
152   jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
153   CheckException(env);
154 
155   for (size_t i = 0; i < v.size(); ++i) {
156     ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
157     env->SetObjectArrayElement(joa, i, item.obj());
158   }
159   return ScopedJavaLocalRef<jobjectArray>(env, joa);
160 }
161 
AppendJavaStringArrayToStringVector(JNIEnv * env,jobjectArray array,std::vector<string16> * out)162 void AppendJavaStringArrayToStringVector(JNIEnv* env,
163                                          jobjectArray array,
164                                          std::vector<string16>* out) {
165   DCHECK(out);
166   if (!array)
167     return;
168   size_t len = SafeGetArrayLength(env, array);
169   size_t back = out->size();
170   out->resize(back + len);
171   for (size_t i = 0; i < len; ++i) {
172     ScopedJavaLocalRef<jstring> str(env,
173         static_cast<jstring>(env->GetObjectArrayElement(array, i)));
174     ConvertJavaStringToUTF16(env, str.obj(), out->data() + back + i);
175   }
176 }
177 
AppendJavaStringArrayToStringVector(JNIEnv * env,jobjectArray array,std::vector<std::string> * out)178 void AppendJavaStringArrayToStringVector(JNIEnv* env,
179                                          jobjectArray array,
180                                          std::vector<std::string>* out) {
181   DCHECK(out);
182   if (!array)
183     return;
184   size_t len = SafeGetArrayLength(env, array);
185   size_t back = out->size();
186   out->resize(back + len);
187   for (size_t i = 0; i < len; ++i) {
188     ScopedJavaLocalRef<jstring> str(env,
189         static_cast<jstring>(env->GetObjectArrayElement(array, i)));
190     ConvertJavaStringToUTF8(env, str.obj(), out->data() + back + i);
191   }
192 }
193 
AppendJavaByteArrayToByteVector(JNIEnv * env,jbyteArray byte_array,std::vector<uint8_t> * out)194 void AppendJavaByteArrayToByteVector(JNIEnv* env,
195                                      jbyteArray byte_array,
196                                      std::vector<uint8_t>* out) {
197   DCHECK(out);
198   if (!byte_array)
199     return;
200   size_t len = SafeGetArrayLength(env, byte_array);
201   if (!len)
202     return;
203   size_t back = out->size();
204   out->resize(back + len);
205   env->GetByteArrayRegion(byte_array, 0, len,
206                           reinterpret_cast<int8_t*>(out->data() + back));
207 }
208 
JavaByteArrayToByteVector(JNIEnv * env,jbyteArray byte_array,std::vector<uint8_t> * out)209 void JavaByteArrayToByteVector(JNIEnv* env,
210                                jbyteArray byte_array,
211                                std::vector<uint8_t>* out) {
212   DCHECK(out);
213   DCHECK(byte_array);
214   out->clear();
215   AppendJavaByteArrayToByteVector(env, byte_array, out);
216 }
217 
JavaBooleanArrayToBoolVector(JNIEnv * env,jbooleanArray boolean_array,std::vector<bool> * out)218 void JavaBooleanArrayToBoolVector(JNIEnv* env,
219                                   jbooleanArray boolean_array,
220                                   std::vector<bool>* out) {
221   DCHECK(out);
222   if (!boolean_array)
223     return;
224   size_t len = SafeGetArrayLength(env, boolean_array);
225   if (!len)
226     return;
227   out->resize(len);
228   // It is not possible to get bool* out of vector<bool>.
229   jboolean* values = env->GetBooleanArrayElements(boolean_array, nullptr);
230   for (size_t i = 0; i < len; ++i) {
231     out->at(i) = static_cast<bool>(values[i]);
232   }
233 }
234 
JavaIntArrayToIntVector(JNIEnv * env,jintArray int_array,std::vector<int> * out)235 void JavaIntArrayToIntVector(JNIEnv* env,
236                              jintArray int_array,
237                              std::vector<int>* out) {
238   DCHECK(out);
239   size_t len = SafeGetArrayLength(env, int_array);
240   out->resize(len);
241   if (!len)
242     return;
243   env->GetIntArrayRegion(int_array, 0, len, out->data());
244 }
245 
JavaLongArrayToInt64Vector(JNIEnv * env,jlongArray long_array,std::vector<int64_t> * out)246 void JavaLongArrayToInt64Vector(JNIEnv* env,
247                                 jlongArray long_array,
248                                 std::vector<int64_t>* out) {
249   DCHECK(out);
250   std::vector<jlong> temp;
251   JavaLongArrayToLongVector(env, long_array, &temp);
252   out->resize(0);
253   out->insert(out->begin(), temp.begin(), temp.end());
254 }
255 
JavaLongArrayToLongVector(JNIEnv * env,jlongArray long_array,std::vector<jlong> * out)256 void JavaLongArrayToLongVector(JNIEnv* env,
257                                jlongArray long_array,
258                                std::vector<jlong>* out) {
259   DCHECK(out);
260   size_t len = SafeGetArrayLength(env, long_array);
261   out->resize(len);
262   if (!len)
263     return;
264   env->GetLongArrayRegion(long_array, 0, len, out->data());
265 }
266 
JavaFloatArrayToFloatVector(JNIEnv * env,jfloatArray float_array,std::vector<float> * out)267 void JavaFloatArrayToFloatVector(JNIEnv* env,
268                                  jfloatArray float_array,
269                                  std::vector<float>* out) {
270   DCHECK(out);
271   size_t len = SafeGetArrayLength(env, float_array);
272   out->resize(len);
273   if (!len)
274     return;
275   env->GetFloatArrayRegion(float_array, 0, len, out->data());
276 }
277 
JavaArrayOfByteArrayToStringVector(JNIEnv * env,jobjectArray array,std::vector<std::string> * out)278 void JavaArrayOfByteArrayToStringVector(
279     JNIEnv* env,
280     jobjectArray array,
281     std::vector<std::string>* out) {
282   DCHECK(out);
283   size_t len = SafeGetArrayLength(env, array);
284   out->resize(len);
285   for (size_t i = 0; i < len; ++i) {
286     ScopedJavaLocalRef<jbyteArray> bytes_array(
287         env, static_cast<jbyteArray>(
288             env->GetObjectArrayElement(array, i)));
289     jsize bytes_len = env->GetArrayLength(bytes_array.obj());
290     jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), nullptr);
291     (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len);
292     env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT);
293   }
294 }
295 
JavaArrayOfIntArrayToIntVector(JNIEnv * env,jobjectArray array,std::vector<std::vector<int>> * out)296 void JavaArrayOfIntArrayToIntVector(
297     JNIEnv* env,
298     jobjectArray array,
299     std::vector<std::vector<int>>* out) {
300   DCHECK(out);
301   size_t len = SafeGetArrayLength(env, array);
302   out->resize(len);
303   for (size_t i = 0; i < len; ++i) {
304     ScopedJavaLocalRef<jintArray> int_array(
305         env, static_cast<jintArray>(env->GetObjectArrayElement(array, i)));
306     JavaIntArrayToIntVector(env, int_array.obj(), &out->at(i));
307   }
308 }
309 
310 }  // namespace android
311 }  // namespace base
312