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> 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 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 42 ScopedJavaLocalRef<jbyteArray> ToJavaByteArray( 43 JNIEnv* env, 44 const std::vector<uint8_t>& bytes) { 45 return ToJavaByteArray(env, bytes.data(), bytes.size()); 46 } 47 48 ScopedJavaLocalRef<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 61 ScopedJavaLocalRef<jintArray> ToJavaIntArray( 62 JNIEnv* env, const std::vector<int>& ints) { 63 return ToJavaIntArray(env, ints.data(), ints.size()); 64 } 65 66 ScopedJavaLocalRef<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. 81 BASE_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. 88 BASE_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 101 BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray( 102 JNIEnv* env, 103 const std::vector<float>& floats) { 104 return ToJavaFloatArray(env, floats.data(), floats.size()); 105 } 106 107 ScopedJavaLocalRef<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 122 ScopedJavaLocalRef<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 135 ScopedJavaLocalRef<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 148 void 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 164 void 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 180 void 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 195 void 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 204 void 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 217 void 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 227 void 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 238 void 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 249 void 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 267 void 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