| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/android/jni_array.h" |
| |
| #include "base/android/jni_android.h" |
| #include "base/android/jni_string.h" |
| #include "base/logging.h" |
| |
| namespace base { |
| namespace android { |
| namespace { |
| |
| // As |GetArrayLength| makes no guarantees about the returned value (e.g., it |
| // may be -1 if |array| is not a valid Java array), provide a safe wrapper |
| // that always returns a valid, non-negative size. |
| template <typename JavaArrayType> |
| size_t SafeGetArrayLength(JNIEnv* env, JavaArrayType jarray) { |
| DCHECK(jarray); |
| jsize length = env->GetArrayLength(jarray); |
| DCHECK_GE(length, 0) << "Invalid array length: " << length; |
| return static_cast<size_t>(std::max(0, length)); |
| } |
| |
| } // namespace |
| |
| ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env, |
| const uint8_t* bytes, |
| size_t len) { |
| jbyteArray byte_array = env->NewByteArray(len); |
| CheckException(env); |
| DCHECK(byte_array); |
| |
| env->SetByteArrayRegion( |
| byte_array, 0, len, reinterpret_cast<const jbyte*>(bytes)); |
| CheckException(env); |
| |
| return ScopedJavaLocalRef<jbyteArray>(env, byte_array); |
| } |
| |
| ScopedJavaLocalRef<jbyteArray> ToJavaByteArray( |
| JNIEnv* env, |
| const std::vector<uint8_t>& bytes) { |
| return ToJavaByteArray(env, bytes.data(), bytes.size()); |
| } |
| |
| ScopedJavaLocalRef<jintArray> ToJavaIntArray( |
| JNIEnv* env, const int* ints, size_t len) { |
| jintArray int_array = env->NewIntArray(len); |
| CheckException(env); |
| DCHECK(int_array); |
| |
| env->SetIntArrayRegion( |
| int_array, 0, len, reinterpret_cast<const jint*>(ints)); |
| CheckException(env); |
| |
| return ScopedJavaLocalRef<jintArray>(env, int_array); |
| } |
| |
| ScopedJavaLocalRef<jintArray> ToJavaIntArray( |
| JNIEnv* env, const std::vector<int>& ints) { |
| return ToJavaIntArray(env, ints.data(), ints.size()); |
| } |
| |
| ScopedJavaLocalRef<jlongArray> ToJavaLongArray(JNIEnv* env, |
| const int64_t* longs, |
| size_t len) { |
| jlongArray long_array = env->NewLongArray(len); |
| CheckException(env); |
| DCHECK(long_array); |
| |
| env->SetLongArrayRegion( |
| long_array, 0, len, reinterpret_cast<const jlong*>(longs)); |
| CheckException(env); |
| |
| return ScopedJavaLocalRef<jlongArray>(env, long_array); |
| } |
| |
| // Returns a new Java long array converted from the given int64_t array. |
| BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray( |
| JNIEnv* env, |
| const std::vector<int64_t>& longs) { |
| return ToJavaLongArray(env, longs.data(), longs.size()); |
| } |
| |
| // Returns a new Java float array converted from the given C++ float array. |
| BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray( |
| JNIEnv* env, const float* floats, size_t len) { |
| jfloatArray float_array = env->NewFloatArray(len); |
| CheckException(env); |
| DCHECK(float_array); |
| |
| env->SetFloatArrayRegion( |
| float_array, 0, len, reinterpret_cast<const jfloat*>(floats)); |
| CheckException(env); |
| |
| return ScopedJavaLocalRef<jfloatArray>(env, float_array); |
| } |
| |
| BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray( |
| JNIEnv* env, |
| const std::vector<float>& floats) { |
| return ToJavaFloatArray(env, floats.data(), floats.size()); |
| } |
| |
| ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray( |
| JNIEnv* env, const std::vector<std::string>& v) { |
| ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B"); |
| jobjectArray joa = env->NewObjectArray(v.size(), |
| byte_array_clazz.obj(), NULL); |
| CheckException(env); |
| |
| for (size_t i = 0; i < v.size(); ++i) { |
| ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray( |
| env, reinterpret_cast<const uint8_t*>(v[i].data()), v[i].length()); |
| env->SetObjectArrayElement(joa, i, byte_array.obj()); |
| } |
| return ScopedJavaLocalRef<jobjectArray>(env, joa); |
| } |
| |
| ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings( |
| JNIEnv* env, const std::vector<std::string>& v) { |
| ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String"); |
| jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL); |
| CheckException(env); |
| |
| for (size_t i = 0; i < v.size(); ++i) { |
| ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]); |
| env->SetObjectArrayElement(joa, i, item.obj()); |
| } |
| return ScopedJavaLocalRef<jobjectArray>(env, joa); |
| } |
| |
| ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings( |
| JNIEnv* env, const std::vector<string16>& v) { |
| ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String"); |
| jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL); |
| CheckException(env); |
| |
| for (size_t i = 0; i < v.size(); ++i) { |
| ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]); |
| env->SetObjectArrayElement(joa, i, item.obj()); |
| } |
| return ScopedJavaLocalRef<jobjectArray>(env, joa); |
| } |
| |
| void AppendJavaStringArrayToStringVector(JNIEnv* env, |
| jobjectArray array, |
| std::vector<string16>* out) { |
| DCHECK(out); |
| if (!array) |
| return; |
| size_t len = SafeGetArrayLength(env, array); |
| size_t back = out->size(); |
| out->resize(back + len); |
| for (size_t i = 0; i < len; ++i) { |
| ScopedJavaLocalRef<jstring> str(env, |
| static_cast<jstring>(env->GetObjectArrayElement(array, i))); |
| ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i])); |
| } |
| } |
| |
| void AppendJavaStringArrayToStringVector(JNIEnv* env, |
| jobjectArray array, |
| std::vector<std::string>* out) { |
| DCHECK(out); |
| if (!array) |
| return; |
| size_t len = SafeGetArrayLength(env, array); |
| size_t back = out->size(); |
| out->resize(back + len); |
| for (size_t i = 0; i < len; ++i) { |
| ScopedJavaLocalRef<jstring> str(env, |
| static_cast<jstring>(env->GetObjectArrayElement(array, i))); |
| ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i])); |
| } |
| } |
| |
| void AppendJavaByteArrayToByteVector(JNIEnv* env, |
| jbyteArray byte_array, |
| std::vector<uint8_t>* out) { |
| DCHECK(out); |
| if (!byte_array) |
| return; |
| size_t len = SafeGetArrayLength(env, byte_array); |
| if (!len) |
| return; |
| size_t back = out->size(); |
| out->resize(back + len); |
| env->GetByteArrayRegion(byte_array, 0, len, |
| reinterpret_cast<int8_t*>(&(*out)[back])); |
| } |
| |
| void JavaByteArrayToByteVector(JNIEnv* env, |
| jbyteArray byte_array, |
| std::vector<uint8_t>* out) { |
| DCHECK(out); |
| DCHECK(byte_array); |
| out->clear(); |
| AppendJavaByteArrayToByteVector(env, byte_array, out); |
| } |
| |
| void JavaIntArrayToIntVector(JNIEnv* env, |
| jintArray int_array, |
| std::vector<int>* out) { |
| DCHECK(out); |
| size_t len = SafeGetArrayLength(env, int_array); |
| out->resize(len); |
| if (!len) |
| return; |
| // TODO(jdduke): Use |out->data()| for pointer access after switch to libc++, |
| // both here and in the other conversion routines. See crbug.com/427718. |
| env->GetIntArrayRegion(int_array, 0, len, &(*out)[0]); |
| } |
| |
| void JavaLongArrayToInt64Vector(JNIEnv* env, |
| jlongArray long_array, |
| std::vector<int64_t>* out) { |
| DCHECK(out); |
| std::vector<jlong> temp; |
| JavaLongArrayToLongVector(env, long_array, &temp); |
| out->resize(0); |
| out->insert(out->begin(), temp.begin(), temp.end()); |
| } |
| |
| void JavaLongArrayToLongVector(JNIEnv* env, |
| jlongArray long_array, |
| std::vector<jlong>* out) { |
| DCHECK(out); |
| size_t len = SafeGetArrayLength(env, long_array); |
| out->resize(len); |
| if (!len) |
| return; |
| env->GetLongArrayRegion(long_array, 0, len, &(*out)[0]); |
| } |
| |
| void JavaFloatArrayToFloatVector(JNIEnv* env, |
| jfloatArray float_array, |
| std::vector<float>* out) { |
| DCHECK(out); |
| size_t len = SafeGetArrayLength(env, float_array); |
| out->resize(len); |
| if (!len) |
| return; |
| env->GetFloatArrayRegion(float_array, 0, len, &(*out)[0]); |
| } |
| |
| void JavaArrayOfByteArrayToStringVector( |
| JNIEnv* env, |
| jobjectArray array, |
| std::vector<std::string>* out) { |
| DCHECK(out); |
| size_t len = SafeGetArrayLength(env, array); |
| out->resize(len); |
| for (size_t i = 0; i < len; ++i) { |
| ScopedJavaLocalRef<jbyteArray> bytes_array( |
| env, static_cast<jbyteArray>( |
| env->GetObjectArrayElement(array, i))); |
| jsize bytes_len = env->GetArrayLength(bytes_array.obj()); |
| jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), nullptr); |
| (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len); |
| env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT); |
| } |
| } |
| |
| void JavaArrayOfIntArrayToIntVector( |
| JNIEnv* env, |
| jobjectArray array, |
| std::vector<std::vector<int>>* out) { |
| DCHECK(out); |
| size_t len = SafeGetArrayLength(env, array); |
| out->resize(len); |
| for (size_t i = 0; i < len; ++i) { |
| ScopedJavaLocalRef<jintArray> int_array( |
| env, static_cast<jintArray>(env->GetObjectArrayElement(array, i))); |
| JavaIntArrayToIntVector(env, int_array.obj(), &((*out)[i])); |
| } |
| } |
| |
| } // namespace android |
| } // namespace base |