diff options
author | Narayan Kamath <narayan@google.com> | 2014-03-13 12:15:23 +0000 |
---|---|---|
committer | Narayan Kamath <narayan@google.com> | 2014-03-13 17:11:37 +0000 |
commit | 11c1f6f38955e0ec20d86ca70891f30bf5f5e4bb (patch) | |
tree | b5cf983a9001c31fdbcf7e0296e24b8769d6a858 /luni | |
parent | e6e7947cef6e6299d617b8efbe108d1c89a8f91d (diff) | |
download | libcore-11c1f6f38955e0ec20d86ca70891f30bf5f5e4bb.zip libcore-11c1f6f38955e0ec20d86ca70891f30bf5f5e4bb.tar.gz libcore-11c1f6f38955e0ec20d86ca70891f30bf5f5e4bb.tar.bz2 |
Fix ICU glue for uloc_toLanguageTag.
There were several issues :
- ICU does not set the output param UErrorCode* to U_ZERO_ERROR
when an API call is successful, so we need to clear it before every
API call.
- ICU sets the error code to U_BUFFER_OVERFLOW_ERROR (and sets the
output length to the required size) if the input buffer is too
small.
- ICU sets the error code to U_STRING_NOT_TERMINATED_WARNING when
the input buffer is one character too short.
bug: 13414549
bug: 13412659
Change-Id: I3e23ea507a540f37ab1c14a60afe801bca286554
Diffstat (limited to 'luni')
-rw-r--r-- | luni/src/main/native/libcore_icu_ICU.cpp | 34 | ||||
-rw-r--r-- | luni/src/test/java/libcore/java/util/LocaleTest.java | 10 |
2 files changed, 28 insertions, 16 deletions
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp index c869542..dc57b10 100644 --- a/luni/src/main/native/libcore_icu_ICU.cpp +++ b/luni/src/main/native/libcore_icu_ICU.cpp @@ -168,26 +168,28 @@ static jstring ICU_localeForLanguageTag(JNIEnv* env, jclass, jstring languageTag static jstring ICU_languageTagForLocale(JNIEnv* env, jclass, jstring javaLocaleId) { ScopedUtfChars localeID(env, javaLocaleId); - // The conversion from an ICU locale ID to a BCP 47 tag will shrink - // the size of the string unless there's an invalid language or a bad - // parse (which will result in an x-lvariant private use subtag at - // the end of the input). - const size_t initialBufferSize = localeID.size(); + // In most common cases, the BCP 47 tag will be the same size as the ICU + // locale ID + const size_t initialBufferSize = localeID.size() + 1; std::vector<char> buffer(initialBufferSize); UErrorCode status = U_ZERO_ERROR; - while (true) { - const size_t outputLength = uloc_toLanguageTag(localeID.c_str(), - &buffer[0], buffer.size(), false /* strict */, &status); - if (U_FAILURE(status)) { - return NULL; - } + const size_t outputLength = uloc_toLanguageTag(localeID.c_str(), + &buffer[0], buffer.size(), false /* strict */, &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + buffer.resize(outputLength + 1); + status = U_ZERO_ERROR; + uloc_toLanguageTag(localeID.c_str(), &buffer[0], buffer.size(), + false /* strict */, &status); + } - if (outputLength == buffer.size()) { - buffer.resize(buffer.size() << 1); - } else { - break; - } + if (status == U_STRING_NOT_TERMINATED_WARNING) { + buffer.resize(buffer.size() + 1); + buffer[buffer.size() -1] = '\0'; + } + + if (maybeThrowIcuException(env, "ICU::languageTagForLocale", status)) { + return NULL; } return env->NewStringUTF(&buffer[0]); diff --git a/luni/src/test/java/libcore/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java index c6aea9e..89a64c7 100644 --- a/luni/src/test/java/libcore/java/util/LocaleTest.java +++ b/luni/src/test/java/libcore/java/util/LocaleTest.java @@ -1134,5 +1134,15 @@ public class LocaleTest extends junit.framework.TestCase { b.setLanguage("en").setExtension('x', "fooo-baar"); assertEquals("en__#x-fooo-baar", b.build().toString()); } + + // Tests cases where our "guess" for the output size is incorrect. + // + // https://b.corp.google.com/issue?id=13414549 + public void test_toLanguageTag_largerTag() { + Locale posix = new Locale.Builder() + .setLanguage("en").setRegion("US").setVariant("POSIX") + .build(); + assertEquals("en-US-u-va-posix", posix.toLanguageTag()); + } } |