Merge "Fix ICU glue for uloc_toLanguageTag."
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_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 @@
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());
+ }
}