| // 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* 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<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* 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 array. |
| BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray( |
| JNIEnv* env, const std::vector<int64>& longs) { |
| return ToJavaLongArray(env, longs.data(), longs.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*>(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>* 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*>(&(*out)[back])); |
| } |
| |
| void JavaByteArrayToByteVector(JNIEnv* env, |
| jbyteArray byte_array, |
| std::vector<uint8>* 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 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(), NULL); |
| (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len); |
| env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT); |
| } |
| } |
| |
| } // namespace android |
| } // namespace base |