1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/android/jni_string.h"
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/android/jni_android.h"
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/logging.h"
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/strings/utf_string_conversions.h"
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace {
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Internal version that does not use a scoped local pointer.
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezjstring ConvertUTF16ToJavaStringImpl(JNIEnv* env,
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                     const base::StringPiece16& str) {
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  jstring result = env->NewString(str.data(), str.length());
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::android::CheckException(env);
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return result;
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace base {
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace android {
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid ConvertJavaStringToUTF8(JNIEnv* env, jstring str, std::string* result) {
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(str);
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!str) {
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    LOG(WARNING) << "ConvertJavaStringToUTF8 called with null string.";
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    result->clear();
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const jsize length = env->GetStringLength(str);
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!length) {
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    result->clear();
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    CheckException(env);
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // JNI's GetStringUTFChars() returns strings in Java "modified" UTF8, so
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // instead get the String in UTF16 and convert using chromium's conversion
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // function that yields plain (non Java-modified) UTF8.
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const jchar* chars = env->GetStringChars(str, NULL);
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(chars);
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  UTF16ToUTF8(chars, length, result);
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  env->ReleaseStringChars(str, chars);
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CheckException(env);
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstd::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  std::string result;
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ConvertJavaStringToUTF8(env, str, &result);
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return result;
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstd::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str) {
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj());
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstd::string ConvertJavaStringToUTF8(JNIEnv* env, const JavaRef<jstring>& str) {
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return ConvertJavaStringToUTF8(env, str.obj());
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    JNIEnv* env,
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const base::StringPiece& str) {
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // JNI's NewStringUTF expects "modified" UTF8 so instead create the string
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // via our own UTF16 conversion utility.
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Further, Dalvik requires the string passed into NewStringUTF() to come from
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // a trusted source. We can't guarantee that all UTF8 will be sanitized before
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // it gets here, so constructing via UTF16 side-steps this issue.
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // a significant performance hit by doing it this way).
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return ScopedJavaLocalRef<jstring>(env, ConvertUTF16ToJavaStringImpl(
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      env, UTF8ToUTF16(str)));
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid ConvertJavaStringToUTF16(JNIEnv* env, jstring str, string16* result) {
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(str);
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!str) {
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    LOG(WARNING) << "ConvertJavaStringToUTF16 called with null string.";
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    result->clear();
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const jsize length = env->GetStringLength(str);
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!length) {
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    result->clear();
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    CheckException(env);
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const jchar* chars = env->GetStringChars(str, NULL);
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(chars);
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // GetStringChars isn't required to NULL-terminate the strings
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // it returns, so the length must be explicitly checked.
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  result->assign(chars, length);
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  env->ReleaseStringChars(str, chars);
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CheckException(env);
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstring16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  string16 result;
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ConvertJavaStringToUTF16(env, str, &result);
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return result;
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstring16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str) {
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj());
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstring16 ConvertJavaStringToUTF16(JNIEnv* env, const JavaRef<jstring>& str) {
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return ConvertJavaStringToUTF16(env, str.obj());
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    JNIEnv* env,
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const base::StringPiece16& str) {
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return ScopedJavaLocalRef<jstring>(env,
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                     ConvertUTF16ToJavaStringImpl(env, str));
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace android
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace base
122