Home | History | Annotate | Download | only in android
      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