Commit de36240a authored by mmenke@chromium.org's avatar mmenke@chromium.org

Implement alternative string conversion functions in net/ on Android,

using Java conversion functions.  This is part of making it possible
to build net/ without ICU, to get binary size down when building net/
as a library

BUG=362608

Review URL: https://codereview.chromium.org/266053002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269595 0039d316-1c4b-4281-b951-d872f2087c98
parent cbdf6d50
...@@ -44,10 +44,6 @@ specific_include_rules = { ...@@ -44,10 +44,6 @@ specific_include_rules = {
"+third_party/icu/source/common/unicode/ucnv.h" "+third_party/icu/source/common/unicode/ucnv.h"
], ],
# Only use icu for string conversions.
"proxy_script_fetcher_impl\.cc": [
"+base/i18n/icu_string_conversions.h",
],
"websocket_channel\.h": [ "websocket_channel\.h": [
"+base/i18n", "+base/i18n",
], ],
......
// Copyright 2014 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.
package org.chromium.net;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.text.Normalizer;
/**
* Utility functions for converting strings between formats when not built with
* icu.
*/
@JNINamespace("net::android")
public class NetStringUtil {
/**
* Attempts to convert text in a given character set to a Unicode string.
* Returns null on failure.
* @param text ByteBuffer containing the character array to convert.
* @param charset Character set it's in encoded in.
* @return: Unicode string on success, null on failure.
*/
@CalledByNative
private static String convertToUnicode(
ByteBuffer text,
String charset_name) {
try {
Charset charset = Charset.forName(charset_name);
CharsetDecoder decoder = charset.newDecoder();
// On invalid characters, this will throw an exception.
return decoder.decode(text).toString();
} catch (Exception e) {
return null;
}
}
/**
* Attempts to convert text in a given character set to a Unicode string,
* and normalize it. Returns null on failure.
* @param text ByteBuffer containing the character array to convert.
* @param charset Character set it's in encoded in.
* @return: Unicode string on success, null on failure.
*/
@CalledByNative
private static String convertToUnicodeAndNormalize(
ByteBuffer text,
String charset_name) {
String unicodeString = convertToUnicode(text, charset_name);
if (unicodeString == null)
return unicodeString;
return Normalizer.normalize(unicodeString, Normalizer.Form.NFC);
}
/**
* Convert text in a given character set to a Unicode string. Any invalid
* characters are replaced with U+FFFD. Returns null if the character set
* is not recognized.
* @param text ByteBuffer containing the character array to convert.
* @param charset Character set it's in encoded in.
* @return: Unicode string on success, null on failure.
*/
@CalledByNative
private static String convertToUnicodeWithSubstitutions(
ByteBuffer text,
String charset_name) {
try {
Charset charset = Charset.forName(charset_name);
// TODO(mmenke): Investigate if Charset.decode() can be used
// instead. The question is whether it uses the proper replace
// character. JDK CharsetDecoder docs say U+FFFD is the default,
// but Charset.decode() docs say it uses the "charset's default
// replacement byte array".
CharsetDecoder decoder = charset.newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPLACE);
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
decoder.replaceWith("\uFFFD");
return decoder.decode(text).toString();
} catch (Exception e) {
return null;
}
}
}
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
#include "net/cert/x509_util_android.h" #include "net/cert/x509_util_android.h"
#include "net/proxy/proxy_config_service_android.h" #include "net/proxy/proxy_config_service_android.h"
#if defined(USE_ICU_ALTERNATIVES)
#include "net/base/net_string_util_icu_alternatives_android.h"
#endif
namespace net { namespace net {
namespace android { namespace android {
...@@ -28,6 +32,9 @@ static base::android::RegistrationMethod kNetRegisteredMethods[] = { ...@@ -28,6 +32,9 @@ static base::android::RegistrationMethod kNetRegisteredMethods[] = {
net::NetworkChangeNotifierAndroid::Register }, net::NetworkChangeNotifierAndroid::Register },
{ "ProxyConfigService", net::ProxyConfigServiceAndroid::Register }, { "ProxyConfigService", net::ProxyConfigServiceAndroid::Register },
{ "X509Util", net::RegisterX509Util }, { "X509Util", net::RegisterX509Util },
#if defined(USE_ICU_ALTERNATIVES)
{ "NetStringUtils", net::RegisterNetStringUtils }
#endif
}; };
bool RegisterJni(JNIEnv* env) { bool RegisterJni(JNIEnv* env) {
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
namespace net { namespace net {
extern const char* const kCharsetLatin1;
// Converts |text| using |charset| to UTF-8, and writes it to |output|. // Converts |text| using |charset| to UTF-8, and writes it to |output|.
// On failure, returns false and |output| is cleared. // On failure, returns false and |output| is cleared.
bool ConvertToUtf8(const std::string& text, const char* charset, bool ConvertToUtf8(const std::string& text, const char* charset,
...@@ -24,19 +26,16 @@ bool ConvertToUtf8(const std::string& text, const char* charset, ...@@ -24,19 +26,16 @@ bool ConvertToUtf8(const std::string& text, const char* charset,
bool ConvertToUtf8AndNormalize(const std::string& text, const char* charset, bool ConvertToUtf8AndNormalize(const std::string& text, const char* charset,
std::string* output); std::string* output);
// Converts |text| encoded in Latin-1 to UTF-8, normalizes the result, and
// writes it to |output|. On failure, returns false and |output| is cleared.
bool ConvertLatin1ToUtf8AndNormalize(const std::string& text,
std::string* output);
// Converts |text| using |charset| to UTF-16, and writes it to |output|. // Converts |text| using |charset| to UTF-16, and writes it to |output|.
// On failure, returns false and |output| is cleared. // On failure, returns false and |output| is cleared.
bool ConvertToUTF16(const std::string& text, const char* charset, bool ConvertToUTF16(const std::string& text, const char* charset,
base::string16* output); base::string16* output);
// Converts |text| encoded in Latin-1 to UTF-16, and writes it to |output|. // Converts |text| using |charset| to UTF-16, and writes it to |output|.
// On failure, returns false and |output| is cleared. // Any characters that can not be converted are replaced with U+FFFD.
bool ConvertLatin1ToUTF16(const std::string& text, base::string16* output); bool ConvertToUTF16WithSubstitutions(const std::string& text,
const char* charset,
base::string16* output);
} // namespace net } // namespace net
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
namespace net { namespace net {
const char* const kCharsetLatin1 = base::kCodepageLatin1;
bool ConvertToUtf8(const std::string& text, const char* charset, bool ConvertToUtf8(const std::string& text, const char* charset,
std::string* output) { std::string* output) {
output->clear(); output->clear();
...@@ -43,20 +45,18 @@ bool ConvertToUtf8AndNormalize(const std::string& text, const char* charset, ...@@ -43,20 +45,18 @@ bool ConvertToUtf8AndNormalize(const std::string& text, const char* charset,
return base::ConvertToUtf8AndNormalize(text, charset, output); return base::ConvertToUtf8AndNormalize(text, charset, output);
} }
bool ConvertLatin1ToUtf8AndNormalize(const std::string& text,
std::string* output) {
return net::ConvertToUtf8AndNormalize(text, base::kCodepageLatin1, output);
}
bool ConvertToUTF16(const std::string& text, const char* charset, bool ConvertToUTF16(const std::string& text, const char* charset,
base::string16* output) { base::string16* output) {
return base::CodepageToUTF16(text, charset, return base::CodepageToUTF16(text, charset,
base::OnStringConversionError::FAIL, output); base::OnStringConversionError::FAIL, output);
} }
bool ConvertLatin1ToUTF16(const std::string& text, base::string16* output) { bool ConvertToUTF16WithSubstitutions(const std::string& text,
return base::CodepageToUTF16(text, base::kCodepageLatin1, const char* charset,
base::OnStringConversionError::FAIL, output); base::string16* output) {
return base::CodepageToUTF16(text, charset,
base::OnStringConversionError::SUBSTITUTE,
output);
} }
} // namespace net } // namespace net
// Copyright 2014 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 "net/base/net_string_util_icu_alternatives_android.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "jni/NetStringUtil_jni.h"
#include "net/base/net_string_util.h"
namespace net {
namespace {
// Attempts to convert |text| encoded in |charset| to a jstring (Java unicode
// string). Returns the result jstring, or NULL on failure.
ScopedJavaLocalRef<jstring> ConvertToJstring(const std::string& text,
const char* charset) {
JNIEnv* env = base::android::AttachCurrentThread();
jobject java_byte_buffer =
env->NewDirectByteBuffer(const_cast<char*>(text.data()), text.length());
base::android::ScopedJavaLocalRef<jstring> java_charset =
base::android::ConvertUTF8ToJavaString(env, base::StringPiece(charset));
ScopedJavaLocalRef<jstring> java_result =
android::Java_NetStringUtil_convertToUnicode(env, java_byte_buffer,
java_charset.obj());
return java_result;
}
// Attempts to convert |text| encoded in |charset| to a jstring (Java unicode
// string) and then normalizes the string. Returns the result jstring, or NULL
// on failure.
ScopedJavaLocalRef<jstring> ConvertToNormalizedJstring(
const std::string& text, const char* charset) {
JNIEnv* env = base::android::AttachCurrentThread();
jobject java_byte_buffer =
env->NewDirectByteBuffer(const_cast<char*>(text.data()), text.length());
base::android::ScopedJavaLocalRef<jstring> java_charset =
base::android::ConvertUTF8ToJavaString(env, base::StringPiece(charset));
ScopedJavaLocalRef<jstring> java_result =
android::Java_NetStringUtil_convertToUnicodeAndNormalize(
env, java_byte_buffer, java_charset.obj());
return java_result;
}
// Converts |text| encoded in |charset| to a jstring (Java unicode string).
// Any characters that can not be converted are replaced with U+FFFD.
ScopedJavaLocalRef<jstring> ConvertToJstringWithSubstitutions(
const std::string& text, const char* charset) {
JNIEnv* env = base::android::AttachCurrentThread();
jobject java_byte_buffer =
env->NewDirectByteBuffer(const_cast<char*>(text.data()), text.length());
base::android::ScopedJavaLocalRef<jstring> java_charset =
base::android::ConvertUTF8ToJavaString(env, base::StringPiece(charset));
ScopedJavaLocalRef<jstring> java_result =
android::Java_NetStringUtil_convertToUnicodeWithSubstitutions(
env, java_byte_buffer, java_charset.obj());
return java_result;
}
} // namespace
const char* const kCharsetLatin1 = "ISO-8859-1";
bool ConvertToUtf8(const std::string& text, const char* charset,
std::string* output) {
output->clear();
ScopedJavaLocalRef<jstring> java_result = ConvertToJstring(text, charset);
if (java_result.is_null())
return false;
*output = base::android::ConvertJavaStringToUTF8(java_result);
return true;
}
bool ConvertToUtf8AndNormalize(const std::string& text, const char* charset,
std::string* output) {
output->clear();
ScopedJavaLocalRef<jstring> java_result = ConvertToNormalizedJstring(
text, charset);
if (java_result.is_null())
return false;
*output = base::android::ConvertJavaStringToUTF8(java_result);
return true;
}
bool ConvertToUTF16(const std::string& text, const char* charset,
base::string16* output) {
output->clear();
ScopedJavaLocalRef<jstring> java_result = ConvertToJstring(text, charset);
if (java_result.is_null())
return false;
*output = base::android::ConvertJavaStringToUTF16(java_result);
return true;
}
bool ConvertToUTF16WithSubstitutions(const std::string& text,
const char* charset,
base::string16* output) {
output->clear();
ScopedJavaLocalRef<jstring> java_result =
ConvertToJstringWithSubstitutions(text, charset);
if (java_result.is_null())
return false;
*output = base::android::ConvertJavaStringToUTF16(java_result);
return true;
}
bool RegisterNetStringUtils(JNIEnv* env) {
return android::RegisterNativesImpl(env);
}
} // namespace net
// Copyright 2014 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.
#ifndef NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
#define NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
#include <jni.h>
namespace net {
// Explicitly register static JNI functions needed when not using ICU.
bool RegisterNetStringUtils(JNIEnv* env);
} // namespace net
#endif // NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
...@@ -115,7 +115,7 @@ std::string DataToString(CSSM_DATA data) { ...@@ -115,7 +115,7 @@ std::string DataToString(CSSM_DATA data) {
// Converts raw CSSM_DATA in ISO-8859-1 to a std::string in UTF-8. // Converts raw CSSM_DATA in ISO-8859-1 to a std::string in UTF-8.
std::string Latin1DataToUTF8String(CSSM_DATA data) { std::string Latin1DataToUTF8String(CSSM_DATA data) {
base::string16 utf16; base::string16 utf16;
if (!ConvertLatin1ToUTF16(DataToString(data), &utf16)) if (!ConvertToUTF16(DataToString(data), kCharsetLatin1, &utf16))
return ""; return "";
return base::UTF16ToUTF8(utf16); return base::UTF16ToUTF8(utf16);
} }
......
...@@ -43,8 +43,10 @@ bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer, ...@@ -43,8 +43,10 @@ bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer,
if (!LowerCaseEqualsASCII(parameters.name(), "realm")) if (!LowerCaseEqualsASCII(parameters.name(), "realm"))
continue; continue;
if (!net::ConvertLatin1ToUtf8AndNormalize(parameters.value(), realm)) if (!net::ConvertToUtf8AndNormalize(parameters.value(), kCharsetLatin1,
realm)) {
return false; return false;
}
} }
return parameters.valid(); return parameters.valid();
} }
......
...@@ -227,7 +227,7 @@ bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name, ...@@ -227,7 +227,7 @@ bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name,
const std::string& value) { const std::string& value) {
if (LowerCaseEqualsASCII(name, "realm")) { if (LowerCaseEqualsASCII(name, "realm")) {
std::string realm; std::string realm;
if (!net::ConvertLatin1ToUtf8AndNormalize(value, &realm)) if (!net::ConvertToUtf8AndNormalize(value, kCharsetLatin1, &realm))
return false; return false;
realm_ = realm; realm_ = realm;
original_realm_ = value; original_realm_ = value;
......
...@@ -438,6 +438,16 @@ ...@@ -438,6 +438,16 @@
], ],
}, },
], ],
[ 'use_icu_alternatives_on_android == 1', {
'sources!': [
'base/net_string_util_icu.cc',
],
'sources': [
'base/net_string_util_icu_alternatives_android.cc',
'base/net_string_util_icu_alternatives_android.h',
],
},
],
], ],
'target_conditions': [ 'target_conditions': [
# These source files are excluded by default platform rules, but they # These source files are excluded by default platform rules, but they
...@@ -1430,6 +1440,14 @@ ...@@ -1430,6 +1440,14 @@
'jni_generator_ptr_type': 'long', 'jni_generator_ptr_type': 'long',
}, },
'includes': [ '../build/jni_generator.gypi' ], 'includes': [ '../build/jni_generator.gypi' ],
'conditions': [
['use_icu_alternatives_on_android==1', {
'sources': [
'android/java/src/org/chromium/net/NetStringUtil.java',
],
}],
],
}, },
{ {
'target_name': 'net_test_jni_headers', 'target_name': 'net_test_jni_headers',
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "net/proxy/proxy_script_fetcher_impl.h" #include "net/proxy/proxy_script_fetcher_impl.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
...@@ -13,6 +12,7 @@ ...@@ -13,6 +12,7 @@
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/base/net_string_util.h"
#include "net/base/request_priority.h" #include "net/base/request_priority.h"
#include "net/cert/cert_status_flags.h" #include "net/cert/cert_status_flags.h"
#include "net/http/http_response_headers.h" #include "net/http/http_response_headers.h"
...@@ -56,18 +56,15 @@ void ConvertResponseToUTF16(const std::string& charset, ...@@ -56,18 +56,15 @@ void ConvertResponseToUTF16(const std::string& charset,
if (charset.empty()) { if (charset.empty()) {
// Assume ISO-8859-1 if no charset was specified. // Assume ISO-8859-1 if no charset was specified.
codepage = base::kCodepageLatin1; codepage = kCharsetLatin1;
} else { } else {
// Otherwise trust the charset that was provided. // Otherwise trust the charset that was provided.
codepage = charset.c_str(); codepage = charset.c_str();
} }
// We will be generous in the conversion -- if any characters lie // Be generous in the conversion -- if any characters lie outside of |charset|
// outside of |charset| (i.e. invalid), then substitute them with // (i.e. invalid), then substitute them with U+FFFD rather than failing.
// U+FFFD rather than failing. ConvertToUTF16WithSubstitutions(bytes, codepage, utf16);
base::CodepageToUTF16(bytes, codepage,
base::OnStringConversionError::SUBSTITUTE,
utf16);
} }
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment