ICU-22520 Replace char arrays with icu::CharString.

This commit is contained in:
Fredrik Roubert 2024-02-06 13:39:46 +01:00 committed by Fredrik Roubert
parent 930b4d9ab9
commit d28e12b1f2
10 changed files with 152 additions and 189 deletions

View file

@ -357,7 +357,7 @@ _getStringOrCopyKey(const char *path, const char *locale,
return u_terminateUChars(dest, destCapacity, length, pErrorCode);
}
typedef int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
using UDisplayNameGetter = icu::CharString(const char*, UErrorCode&);
static int32_t
_getDisplayNameForComponent(const char *locale,
@ -366,8 +366,6 @@ _getDisplayNameForComponent(const char *locale,
UDisplayNameGetter *getter,
const char *tag,
UErrorCode *pErrorCode) {
char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
int32_t length;
UErrorCode localStatus;
const char* root = nullptr;
@ -382,15 +380,15 @@ _getDisplayNameForComponent(const char *locale,
}
localStatus = U_ZERO_ERROR;
length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
icu::CharString localeBuffer = (*getter)(locale, localStatus);
if (U_FAILURE(localStatus)) {
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
if(length==0) {
if (localeBuffer.isEmpty()) {
// For the display name, we treat this as unknown language (ICU-20273).
if (getter == uloc_getLanguage) {
uprv_strcpy(localeBuffer, "und");
if (getter == ulocimp_getLanguage) {
localeBuffer.append("und", *pErrorCode);
} else {
return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
}
@ -399,8 +397,8 @@ _getDisplayNameForComponent(const char *locale,
root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
return _getStringOrCopyKey(root, displayLocale,
tag, nullptr, localeBuffer,
localeBuffer,
tag, nullptr, localeBuffer.data(),
localeBuffer.data(),
dest, destCapacity,
pErrorCode);
}
@ -411,7 +409,7 @@ uloc_getDisplayLanguage(const char *locale,
char16_t *dest, int32_t destCapacity,
UErrorCode *pErrorCode) {
return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
uloc_getLanguage, _kLanguages, pErrorCode);
ulocimp_getLanguage, _kLanguages, pErrorCode);
}
U_CAPI int32_t U_EXPORT2
@ -422,17 +420,17 @@ uloc_getDisplayScript(const char* locale,
{
UErrorCode err = U_ZERO_ERROR;
int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
uloc_getScript, _kScriptsStandAlone, &err);
ulocimp_getScript, _kScriptsStandAlone, &err);
if (destCapacity == 0 && err == U_BUFFER_OVERFLOW_ERROR) {
// For preflight, return the max of the value and the fallback.
int32_t fallback_res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
uloc_getScript, _kScripts, pErrorCode);
ulocimp_getScript, _kScripts, pErrorCode);
return (fallback_res > res) ? fallback_res : res;
}
if ( err == U_USING_DEFAULT_WARNING ) {
return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
uloc_getScript, _kScripts, pErrorCode);
ulocimp_getScript, _kScripts, pErrorCode);
} else {
*pErrorCode = err;
return res;
@ -446,7 +444,7 @@ uloc_getDisplayScriptInContext(const char* locale,
UErrorCode *pErrorCode)
{
return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
uloc_getScript, _kScripts, pErrorCode);
ulocimp_getScript, _kScripts, pErrorCode);
}
U_CAPI int32_t U_EXPORT2
@ -455,7 +453,7 @@ uloc_getDisplayCountry(const char *locale,
char16_t *dest, int32_t destCapacity,
UErrorCode *pErrorCode) {
return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
uloc_getCountry, _kCountries, pErrorCode);
ulocimp_getRegion, _kCountries, pErrorCode);
}
/*
@ -469,7 +467,7 @@ uloc_getDisplayVariant(const char *locale,
char16_t *dest, int32_t destCapacity,
UErrorCode *pErrorCode) {
return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
uloc_getVariant, _kVariants, pErrorCode);
ulocimp_getVariant, _kVariants, pErrorCode);
}
/* Instead of having a separate pass for 'special' patterns, reintegrate the two

View file

@ -509,22 +509,16 @@ static const char LANG_DIR_STRING[] =
U_CAPI UBool U_EXPORT2
uloc_isRightToLeft(const char *locale) {
UErrorCode errorCode = U_ZERO_ERROR;
char script[8];
int32_t scriptLength = uloc_getScript(locale, script, UPRV_LENGTHOF(script), &errorCode);
if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING ||
scriptLength == 0) {
icu::CharString lang;
icu::CharString script;
ulocimp_getSubtags(locale, &lang, &script, nullptr, nullptr, nullptr, errorCode);
if (U_FAILURE(errorCode) || script.isEmpty()) {
// Fastpath: We know the likely scripts and their writing direction
// for some common languages.
errorCode = U_ZERO_ERROR;
char lang[8];
int32_t langLength = uloc_getLanguage(locale, lang, UPRV_LENGTHOF(lang), &errorCode);
if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
return false;
}
if (langLength > 0) {
const char* langPtr = uprv_strstr(LANG_DIR_STRING, lang);
if (!lang.isEmpty()) {
const char* langPtr = uprv_strstr(LANG_DIR_STRING, lang.data());
if (langPtr != nullptr) {
switch (langPtr[langLength]) {
switch (langPtr[lang.length()]) {
case '-': return false;
case '+': return true;
default: break; // partial match of a longer code
@ -538,16 +532,15 @@ uloc_isRightToLeft(const char *locale) {
icu::CharStringByteSink sink(&likely);
ulocimp_addLikelySubtags(locale, sink, &errorCode);
}
if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
if (U_FAILURE(errorCode)) {
return false;
}
scriptLength = uloc_getScript(likely.data(), script, UPRV_LENGTHOF(script), &errorCode);
if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING ||
scriptLength == 0) {
ulocimp_getSubtags(likely.data(), nullptr, &script, nullptr, nullptr, nullptr, errorCode);
if (U_FAILURE(errorCode) || script.isEmpty()) {
return false;
}
}
UScriptCode scriptCode = (UScriptCode)u_getPropertyValueEnum(UCHAR_SCRIPT, script);
UScriptCode scriptCode = (UScriptCode)u_getPropertyValueEnum(UCHAR_SCRIPT, script.data());
return uscript_isRightToLeft(scriptCode);
}
@ -560,36 +553,30 @@ Locale::isRightToLeft() const {
U_NAMESPACE_END
// The following must at least allow for rg key value (6) plus terminator (1).
#define ULOC_RG_BUFLEN 8
namespace {
int GetRegionFromKey(const char *localeID, const char* key, char* buf) {
UErrorCode status = U_ZERO_ERROR;
icu::CharString
GetRegionFromKey(const char* localeID, const char* key, UErrorCode& status) {
icu::CharString result;
// First check for rg keyword value
icu::CharString rg;
// First check for keyword value
icu::CharString kw;
{
icu::CharStringByteSink sink(&rg);
icu::CharStringByteSink sink(&kw);
ulocimp_getKeywordValue(localeID, key, sink, &status);
}
int32_t len = rg.length();
if (U_FAILURE(status) || len < 3 || len > 7) {
len = 0;
} else {
int32_t len = kw.length();
if (U_SUCCESS(status) && len >= 3 && len <= 7) {
// chop off the subdivision code (which will generally be "zzzz" anyway)
const char* const data = rg.data();
const char* const data = kw.data();
if (uprv_isASCIILetter(data[0])) {
len = 2;
buf[0] = uprv_toupper(data[0]);
buf[1] = uprv_toupper(data[1]);
result.append(uprv_toupper(data[0]), status);
result.append(uprv_toupper(data[1]), status);
} else {
// assume three-digit region code
len = 3;
uprv_memcpy(buf, data, len);
result.append(data, 3, status);
}
}
return len;
return result;
}
} // namespace
@ -599,17 +586,14 @@ ulocimp_getRegionForSupplementalData(const char *localeID, UBool inferRegion,
if (U_FAILURE(*status)) {
return 0;
}
char rgBuf[ULOC_RG_BUFLEN];
int32_t rgLen = GetRegionFromKey(localeID, "rg", rgBuf);
if (rgLen == 0) {
icu::CharString rgBuf = GetRegionFromKey(localeID, "rg", *status);
if (U_SUCCESS(*status) && rgBuf.isEmpty()) {
// No valid rg keyword value, try for unicode_region_subtag
rgLen = uloc_getCountry(localeID, rgBuf, ULOC_RG_BUFLEN, status);
if (U_FAILURE(*status)) {
rgLen = 0;
} else if (rgLen == 0 && inferRegion) {
rgBuf = ulocimp_getRegion(localeID, *status);
if (U_SUCCESS(*status) && rgBuf.isEmpty() && inferRegion) {
// Second check for sd keyword value
rgLen = GetRegionFromKey(localeID, "sd", rgBuf);
if (rgLen == 0) {
rgBuf = GetRegionFromKey(localeID, "sd", *status);
if (U_SUCCESS(*status) && rgBuf.isEmpty()) {
// no unicode_region_subtag but inferRegion true, try likely subtags
UErrorCode rgStatus = U_ZERO_ERROR;
icu::CharString locBuf;
@ -618,17 +602,11 @@ ulocimp_getRegionForSupplementalData(const char *localeID, UBool inferRegion,
ulocimp_addLikelySubtags(localeID, sink, &rgStatus);
}
if (U_SUCCESS(rgStatus)) {
rgLen = uloc_getCountry(locBuf.data(), rgBuf, ULOC_RG_BUFLEN, status);
if (U_FAILURE(*status)) {
rgLen = 0;
}
rgBuf = ulocimp_getRegion(locBuf.data(), *status);
}
}
}
}
rgBuf[rgLen] = 0;
uprv_strncpy(region, rgBuf, regionCapacity);
return u_terminateChars(region, regionCapacity, rgLen, status);
return rgBuf.extract(region, regionCapacity, *status);
}

View file

@ -2143,17 +2143,16 @@ U_CAPI const char* U_EXPORT2
uloc_getISO3Language(const char* localeID)
{
int16_t offset;
char lang[ULOC_LANG_CAPACITY];
UErrorCode err = U_ZERO_ERROR;
if (localeID == nullptr)
{
localeID = uloc_getDefault();
}
uloc_getLanguage(localeID, lang, ULOC_LANG_CAPACITY, &err);
CharString lang = ulocimp_getLanguage(localeID, err);
if (U_FAILURE(err))
return "";
offset = _findIndex(LANGUAGES, lang);
offset = _findIndex(LANGUAGES, lang.data());
if (offset < 0)
return "";
return LANGUAGES_3[offset];
@ -2163,17 +2162,16 @@ U_CAPI const char* U_EXPORT2
uloc_getISO3Country(const char* localeID)
{
int16_t offset;
char cntry[ULOC_LANG_CAPACITY];
UErrorCode err = U_ZERO_ERROR;
if (localeID == nullptr)
{
localeID = uloc_getDefault();
}
uloc_getCountry(localeID, cntry, ULOC_LANG_CAPACITY, &err);
CharString cntry = ulocimp_getRegion(localeID, err);
if (U_FAILURE(err))
return "";
offset = _findIndex(COUNTRIES, cntry);
offset = _findIndex(COUNTRIES, cntry.data());
if (offset < 0)
return "";
@ -2184,7 +2182,6 @@ U_CAPI uint32_t U_EXPORT2
uloc_getLCID(const char* localeID)
{
UErrorCode status = U_ZERO_ERROR;
char langID[ULOC_FULLNAME_CAPACITY];
uint32_t lcid = 0;
/* Check for incomplete id. */
@ -2203,8 +2200,8 @@ uloc_getLCID(const char* localeID)
return lcid;
}
uloc_getLanguage(localeID, langID, sizeof(langID), &status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
CharString langID = ulocimp_getLanguage(localeID, status);
if (U_FAILURE(status)) {
return 0;
}
@ -2224,7 +2221,7 @@ uloc_getLCID(const char* localeID)
}
ulocimp_setKeywordValue("collation", collVal.data(), tmpLocaleID, &status);
if (U_SUCCESS(status)) {
return uprv_convertToLCID(langID, tmpLocaleID.data(), &status);
return uprv_convertToLCID(langID.data(), tmpLocaleID.data(), &status);
}
}
@ -2232,7 +2229,7 @@ uloc_getLCID(const char* localeID)
status = U_ZERO_ERROR;
}
return uprv_convertToLCID(langID, localeID, &status);
return uprv_convertToLCID(langID.data(), localeID, &status);
}
U_CAPI int32_t U_EXPORT2

View file

@ -1012,28 +1012,25 @@ _initializeULanguageTag(ULanguageTag* langtag) {
static void
_appendLanguageToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool strict, UErrorCode* status) {
char buf[ULOC_LANG_CAPACITY];
UErrorCode tmpStatus = U_ZERO_ERROR;
int32_t len, i;
if (U_FAILURE(*status)) {
return;
}
len = uloc_getLanguage(localeID, buf, sizeof(buf), &tmpStatus);
if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
icu::CharString buf = ulocimp_getLanguage(localeID, tmpStatus);
if (U_FAILURE(tmpStatus)) {
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
len = 0;
}
/* Note: returned language code is in lower case letters */
if (len == 0) {
if (buf.isEmpty()) {
sink.Append(LANG_UND, LANG_UND_LEN);
} else if (!ultag_isLanguageSubtag(buf, len)) {
} else if (!ultag_isLanguageSubtag(buf.data(), buf.length())) {
/* invalid language code */
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
@ -1042,42 +1039,40 @@ _appendLanguageToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
sink.Append(LANG_UND, LANG_UND_LEN);
} else {
/* resolve deprecated */
for (i = 0; i < UPRV_LENGTHOF(DEPRECATEDLANGS); i += 2) {
for (int32_t i = 0; i < UPRV_LENGTHOF(DEPRECATEDLANGS); i += 2) {
// 2-letter deprecated subtags are listede before 3-letter
// ones in DEPRECATEDLANGS[]. Get out of loop on coming
// across the 1st 3-letter subtag, if the input is a 2-letter code.
// to avoid continuing to try when there's no match.
if (uprv_strlen(buf) < uprv_strlen(DEPRECATEDLANGS[i])) break;
if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDLANGS[i]) == 0) {
uprv_strcpy(buf, DEPRECATEDLANGS[i + 1]);
len = (int32_t)uprv_strlen(buf);
break;
if (buf.length() < (int32_t)uprv_strlen(DEPRECATEDLANGS[i])) break;
if (uprv_compareInvCharsAsAscii(buf.data(), DEPRECATEDLANGS[i]) == 0) {
const char* const resolved = DEPRECATEDLANGS[i + 1];
sink.Append(resolved, (int32_t)uprv_strlen(resolved));
return;
}
}
sink.Append(buf, len);
sink.Append(buf.data(), buf.length());
}
}
static void
_appendScriptToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool strict, UErrorCode* status) {
char buf[ULOC_SCRIPT_CAPACITY];
UErrorCode tmpStatus = U_ZERO_ERROR;
int32_t len;
if (U_FAILURE(*status)) {
return;
}
len = uloc_getScript(localeID, buf, sizeof(buf), &tmpStatus);
if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
icu::CharString buf = ulocimp_getScript(localeID, tmpStatus);
if (U_FAILURE(tmpStatus)) {
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
}
return;
}
if (len > 0) {
if (!ultag_isScriptSubtag(buf, len)) {
if (!buf.isEmpty()) {
if (!ultag_isScriptSubtag(buf.data(), buf.length())) {
/* invalid script code */
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
@ -1085,31 +1080,29 @@ _appendScriptToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool stri
return;
} else {
sink.Append("-", 1);
sink.Append(buf, len);
sink.Append(buf.data(), buf.length());
}
}
}
static void
_appendRegionToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool strict, UErrorCode* status) {
char buf[ULOC_COUNTRY_CAPACITY];
UErrorCode tmpStatus = U_ZERO_ERROR;
int32_t len;
if (U_FAILURE(*status)) {
return;
}
len = uloc_getCountry(localeID, buf, sizeof(buf), &tmpStatus);
if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
icu::CharString buf = ulocimp_getRegion(localeID, tmpStatus);
if (U_FAILURE(tmpStatus)) {
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
}
return;
}
if (len > 0) {
if (!ultag_isRegionSubtag(buf, len)) {
if (!buf.isEmpty()) {
if (!ultag_isRegionSubtag(buf.data(), buf.length())) {
/* invalid region code */
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
@ -1118,14 +1111,14 @@ _appendRegionToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool stri
} else {
sink.Append("-", 1);
/* resolve deprecated */
for (int i = 0; i < UPRV_LENGTHOF(DEPRECATEDREGIONS); i += 2) {
if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDREGIONS[i]) == 0) {
uprv_strcpy(buf, DEPRECATEDREGIONS[i + 1]);
len = (int32_t)uprv_strlen(buf);
break;
for (int32_t i = 0; i < UPRV_LENGTHOF(DEPRECATEDREGIONS); i += 2) {
if (uprv_compareInvCharsAsAscii(buf.data(), DEPRECATEDREGIONS[i]) == 0) {
const char* const resolved = DEPRECATEDREGIONS[i + 1];
sink.Append(resolved, (int32_t)uprv_strlen(resolved));
return;
}
}
sink.Append(buf, len);
sink.Append(buf.data(), buf.length());
}
}
}
@ -1145,15 +1138,13 @@ static void _sortVariants(VariantListEntry* first) {
static void
_appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool strict, UBool *hadPosix, UErrorCode* status) {
char buf[ULOC_FULLNAME_CAPACITY];
UErrorCode tmpStatus = U_ZERO_ERROR;
int32_t len, i;
if (U_FAILURE(*status)) {
return;
}
len = uloc_getVariant(localeID, buf, sizeof(buf), &tmpStatus);
icu::CharString buf = ulocimp_getVariant(localeID, tmpStatus);
if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
@ -1161,13 +1152,13 @@ _appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
return;
}
if (len > 0) {
if (!buf.isEmpty()) {
char *p, *pVar;
UBool bNext = true;
VariantListEntry *varFirst = nullptr;
pVar = nullptr;
p = buf;
p = buf.data();
while (bNext) {
if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
if (*p == 0) {
@ -1184,13 +1175,13 @@ _appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
} else {
/* ICU uses upper case letters for variants, but
the canonical format is lowercase in BCP47 */
for (i = 0; *(pVar + i) != 0; i++) {
for (int32_t i = 0; *(pVar + i) != 0; i++) {
*(pVar + i) = uprv_tolower(*(pVar + i));
}
/* validate */
if (_isVariantSubtag(pVar, -1)) {
if (uprv_strcmp(pVar,POSIX_VALUE) || len != (int32_t)uprv_strlen(POSIX_VALUE)) {
if (uprv_strcmp(pVar,POSIX_VALUE) || buf.length() != (int32_t)uprv_strlen(POSIX_VALUE)) {
/* emit the variant to the list */
icu::LocalPointer<VariantListEntry> var(new VariantListEntry, *status);
if (U_FAILURE(*status)) {
@ -1858,30 +1849,28 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
static void
_appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool strict, UBool hadPosix, UErrorCode* status) {
(void)hadPosix;
char buf[ULOC_FULLNAME_CAPACITY];
UErrorCode tmpStatus = U_ZERO_ERROR;
int32_t len, i;
if (U_FAILURE(*status)) {
return;
}
len = uloc_getVariant(localeID, buf, sizeof(buf), &tmpStatus);
if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
icu::CharString buf = ulocimp_getVariant(localeID, tmpStatus);
if (U_FAILURE(tmpStatus)) {
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
}
return;
}
if (len > 0) {
if (!buf.isEmpty()) {
char *p, *pPriv;
UBool bNext = true;
UBool firstValue = true;
UBool writeValue;
pPriv = nullptr;
p = buf;
p = buf.data();
while (bNext) {
writeValue = false;
if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
@ -1892,7 +1881,7 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool
}
if (pPriv != nullptr) {
/* Private use in the canonical format is lowercase in BCP47 */
for (i = 0; *(pPriv + i) != 0; i++) {
for (int32_t i = 0; *(pPriv + i) != 0; i++) {
*(pPriv + i) = uprv_tolower(*(pPriv + i));
}
@ -1923,7 +1912,7 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool
firstValue = false;
}
len = (int32_t)uprv_strlen(pPriv);
int32_t len = (int32_t)uprv_strlen(pPriv);
sink.Append(pPriv, len);
}
}

View file

@ -94,8 +94,16 @@ static UBool chopLocale(char *name) {
static UBool hasVariant(const char* localeID) {
UErrorCode err = U_ZERO_ERROR;
int32_t variantLength = uloc_getVariant(localeID, nullptr, 0, &err);
return variantLength != 0;
CheckedArrayByteSink sink(nullptr, 0);
ulocimp_getSubtags(
localeID,
nullptr,
nullptr,
nullptr,
&sink,
nullptr,
err);
return sink.NumberOfBytesAppended() != 0;
}
// This file contains the tables for doing locale fallback, which are generated
@ -3249,11 +3257,9 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
if (res != NULL && uprv_strcmp(resName, "collations") == 0) {
const char *validLoc = ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus);
if (U_SUCCESS(subStatus) && validLoc != NULL && validLoc[0] != 0 && uprv_strcmp(validLoc, "root") != 0) {
char validLang[ULOC_LANG_CAPACITY];
char parentLang[ULOC_LANG_CAPACITY];
uloc_getLanguage(validLoc, validLang, ULOC_LANG_CAPACITY, &subStatus);
uloc_getLanguage(parent.data(), parentLang, ULOC_LANG_CAPACITY, &subStatus);
if (U_SUCCESS(subStatus) && uprv_strcmp(validLang, parentLang) != 0) {
CharString validLang = ulocimp_getLanguage(validLoc, subStatus);
CharString parentLang = ulocimp_getLanguage(parent.data(), subStatus);
if (U_SUCCESS(subStatus) && validLang != parentLang) {
// validLoc is not root and has a different language than parent, use it instead
found.clear().append(validLoc, subStatus);
haveFound = true;

View file

@ -57,33 +57,25 @@ setOneCode(UScriptCode script, UScriptCode *scripts, int32_t capacity, UErrorCod
static int32_t
getCodesFromLocale(const char *locale,
UScriptCode *scripts, int32_t capacity, UErrorCode *err) {
UErrorCode internalErrorCode = U_ZERO_ERROR;
char lang[8] = {0};
char script[8] = {0};
int32_t scriptLength;
if(U_FAILURE(*err)) { return 0; }
if (U_FAILURE(*err)) { return 0; }
icu::CharString lang;
icu::CharString script;
ulocimp_getSubtags(locale, &lang, &script, nullptr, nullptr, nullptr, *err);
if (U_FAILURE(*err)) { return 0; }
// Multi-script languages, equivalent to the LocaleScript data
// that we used to load from locale resource bundles.
/*length = */ uloc_getLanguage(locale, lang, UPRV_LENGTHOF(lang), &internalErrorCode);
if(U_FAILURE(internalErrorCode) || internalErrorCode == U_STRING_NOT_TERMINATED_WARNING) {
return 0;
}
if(0 == uprv_strcmp(lang, "ja")) {
if (lang == "ja") {
return setCodes(JAPANESE, UPRV_LENGTHOF(JAPANESE), scripts, capacity, err);
}
if(0 == uprv_strcmp(lang, "ko")) {
if (lang == "ko") {
return setCodes(KOREAN, UPRV_LENGTHOF(KOREAN), scripts, capacity, err);
}
scriptLength = uloc_getScript(locale, script, UPRV_LENGTHOF(script), &internalErrorCode);
if(U_FAILURE(internalErrorCode) || internalErrorCode == U_STRING_NOT_TERMINATED_WARNING) {
return 0;
}
if(0 == uprv_strcmp(lang, "zh") && 0 == uprv_strcmp(script, "Hant")) {
if (lang == "zh" && script == "Hant") {
return setCodes(HAN_BOPO, UPRV_LENGTHOF(HAN_BOPO), scripts, capacity, err);
}
// Explicit script code.
if(scriptLength != 0) {
UScriptCode scriptCode = (UScriptCode)u_getPropertyValueEnum(UCHAR_SCRIPT, script);
if (!script.isEmpty()) {
UScriptCode scriptCode = (UScriptCode)u_getPropertyValueEnum(UCHAR_SCRIPT, script.data());
if(scriptCode != USCRIPT_INVALID_CODE) {
if(scriptCode == USCRIPT_SIMPLIFIED_HAN || scriptCode == USCRIPT_TRADITIONAL_HAN) {
scriptCode = USCRIPT_HAN;

View file

@ -1561,7 +1561,6 @@ RuleBasedCollator::internalGetShortDefinitionString(const char *locale,
// Append items in alphabetic order of their short definition letters.
CharString result;
char subtag[ULOC_KEYWORD_AND_VALUES_CAPACITY];
if(attributeHasBeenSetExplicitly(UCOL_ALTERNATE_HANDLING)) {
appendAttribute(result, 'A', getAttribute(UCOL_ALTERNATE_HANDLING, errorCode), errorCode);
@ -1587,24 +1586,25 @@ RuleBasedCollator::internalGetShortDefinitionString(const char *locale,
ulocimp_getKeywordValue(resultLocale, "collation", sink, &errorCode);
appendSubtag(result, 'K', collation.data(), collation.length(), errorCode);
}
length = uloc_getLanguage(resultLocale, subtag, UPRV_LENGTHOF(subtag), &errorCode);
if (length == 0) {
CharString language;
CharString script;
CharString region;
CharString variant;
ulocimp_getSubtags(resultLocale, &language, &script, &region, &variant, nullptr, errorCode);
if (language.isEmpty()) {
appendSubtag(result, 'L', "root", 4, errorCode);
} else {
appendSubtag(result, 'L', subtag, length, errorCode);
appendSubtag(result, 'L', language.data(), language.length(), errorCode);
}
if(attributeHasBeenSetExplicitly(UCOL_NORMALIZATION_MODE)) {
appendAttribute(result, 'N', getAttribute(UCOL_NORMALIZATION_MODE, errorCode), errorCode);
}
length = uloc_getCountry(resultLocale, subtag, UPRV_LENGTHOF(subtag), &errorCode);
appendSubtag(result, 'R', subtag, length, errorCode);
appendSubtag(result, 'R', region.data(), region.length(), errorCode);
if(attributeHasBeenSetExplicitly(UCOL_STRENGTH)) {
appendAttribute(result, 'S', getAttribute(UCOL_STRENGTH, errorCode), errorCode);
}
length = uloc_getVariant(resultLocale, subtag, UPRV_LENGTHOF(subtag), &errorCode);
appendSubtag(result, 'V', subtag, length, errorCode);
length = uloc_getScript(resultLocale, subtag, UPRV_LENGTHOF(subtag), &errorCode);
appendSubtag(result, 'Z', subtag, length, errorCode);
appendSubtag(result, 'V', variant.data(), variant.length(), errorCode);
appendSubtag(result, 'Z', script.data(), script.length(), errorCode);
if(U_FAILURE(errorCode)) { return 0; }
return result.extract(buffer, capacity, errorCode);

View file

@ -299,7 +299,7 @@ private:
TextTrieMap fGNamesTrie;
UBool fGNamesTrieFullyLoaded;
char fTargetRegion[ULOC_COUNTRY_CAPACITY];
CharString fTargetRegion;
void initialize(const Locale& locale, UErrorCode& status);
void cleanup();
@ -339,7 +339,8 @@ TZGNCore::TZGNCore(const Locale& locale, UErrorCode& status)
fLocaleDisplayNames(nullptr),
fStringPool(status),
fGNamesTrie(true, deleteGNameInfo),
fGNamesTrieFullyLoaded(false) {
fGNamesTrieFullyLoaded(false),
fTargetRegion() {
initialize(locale, status);
}
@ -415,17 +416,13 @@ TZGNCore::initialize(const Locale& locale, UErrorCode& status) {
ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
}
regionLen = uloc_getCountry(loc.data(), fTargetRegion, sizeof(fTargetRegion), &status);
if (U_SUCCESS(status)) {
fTargetRegion[regionLen] = 0;
} else {
ulocimp_getSubtags(loc.data(), nullptr, nullptr, &fTargetRegion, nullptr, nullptr, status);
if (U_FAILURE(status)) {
cleanup();
return;
}
} else if (regionLen < (int32_t)sizeof(fTargetRegion)) {
uprv_strcpy(fTargetRegion, region);
} else {
fTargetRegion[0] = 0;
fTargetRegion.append(region, regionLen, status);
}
// preload generic names for the default zone
@ -704,7 +701,7 @@ TZGNCore::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameT
// golden zone at the given date.
char16_t idBuf[32];
UnicodeString goldenID(idBuf, 0, UPRV_LENGTHOF(idBuf));
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, goldenID);
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion.data(), goldenID);
if (!goldenID.isEmpty() && goldenID != tzID) {
TimeZone *goldenZone = TimeZone::createTimeZone(goldenID);
int32_t raw1, sav1;
@ -866,7 +863,7 @@ TZGNCore::loadStrings(const UnicodeString& tzCanonicalID) {
// if this time zone is not the golden zone of the meta zone,
// partial location name (such as "PT (Los Angeles)") might be
// available.
fTimeZoneNames->getReferenceZoneID(*mzID, fTargetRegion, goldenID);
fTimeZoneNames->getReferenceZoneID(*mzID, fTargetRegion.data(), goldenID);
if (tzCanonicalID != goldenID) {
for (int32_t i = 0; genNonLocTypes[i] != UTZNM_UNKNOWN; i++) {
fTimeZoneNames->getMetaZoneDisplayName(*mzID, genNonLocTypes[i], mzGenName);
@ -914,7 +911,7 @@ TZGNCore::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types
if (!tznamesMatches->getTimeZoneIDAt(i, bestMatchTzID)) {
// name for a meta zone
if (tznamesMatches->getMetaZoneIDAt(i, mzID)) {
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, bestMatchTzID);
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion.data(), bestMatchTzID);
}
}
UTimeZoneNameType nameType = tznamesMatches->getNameTypeAt(i);

View file

@ -16,6 +16,7 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/strenum.h"
#include "unicode/stringpiece.h"
#include "unicode/ustring.h"
#include "unicode/timezone.h"
#include "unicode/utf16.h"
@ -1912,7 +1913,7 @@ U_CDECL_END
class TZDBNameSearchHandler : public TextTrieMapSearchResultHandler {
public:
TZDBNameSearchHandler(uint32_t types, const char* region);
TZDBNameSearchHandler(uint32_t types, StringPiece region);
virtual ~TZDBNameSearchHandler();
UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) override;
@ -1922,10 +1923,10 @@ private:
uint32_t fTypes;
int32_t fMaxMatchLen;
TimeZoneNames::MatchInfoCollection* fResults;
const char* fRegion;
StringPiece fRegion;
};
TZDBNameSearchHandler::TZDBNameSearchHandler(uint32_t types, const char* region)
TZDBNameSearchHandler::TZDBNameSearchHandler(uint32_t types, StringPiece region)
: fTypes(types), fMaxMatchLen(0), fResults(nullptr), fRegion(region) {
}
@ -1974,7 +1975,7 @@ TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *nod
// as metazone China (China Standard Time).
for (int32_t j = 0; j < ninfo->nRegions; j++) {
const char *region = ninfo->parseRegions[j];
if (uprv_strcmp(fRegion, region) == 0) {
if (fRegion == region) {
match = ninfo;
matchRegion = true;
break;
@ -2153,7 +2154,7 @@ static void U_CALLCONV prepareFind(UErrorCode &status) {
U_CDECL_END
TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
: fLocale(locale) {
: fLocale(locale), fRegion() {
UBool useWorld = true;
const char* region = fLocale.getCountry();
int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
@ -2164,16 +2165,20 @@ TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
CharStringByteSink sink(&loc);
ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
}
regionLen = uloc_getCountry(loc.data(), fRegion, sizeof(fRegion), &status);
if (U_SUCCESS(status) && regionLen < (int32_t)sizeof(fRegion)) {
ulocimp_getSubtags(loc.data(), nullptr, nullptr, &fRegion, nullptr, nullptr, status);
if (U_SUCCESS(status)) {
useWorld = false;
}
} else if (regionLen < (int32_t)sizeof(fRegion)) {
uprv_strcpy(fRegion, region);
} else {
UErrorCode status = U_ZERO_ERROR;
fRegion.append(region, regionLen, status);
U_ASSERT(U_SUCCESS(status));
useWorld = false;
}
if (useWorld) {
uprv_strcpy(fRegion, "001");
UErrorCode status = U_ZERO_ERROR;
fRegion.append("001", status);
U_ASSERT(U_SUCCESS(status));
}
}
@ -2251,7 +2256,7 @@ TZDBTimeZoneNames::find(const UnicodeString& text, int32_t start, uint32_t types
return nullptr;
}
TZDBNameSearchHandler handler(types, fRegion);
TZDBNameSearchHandler handler(types, fRegion.toStringPiece());
gTZDBNamesTrie->search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
if (U_FAILURE(status)) {
return nullptr;

View file

@ -26,6 +26,7 @@
#include "uhash.h"
#include "uvector.h"
#include "umutex.h"
#include "charstr.h"
// Some zone display names involving supplementary characters can be over 50 chars, 100 UTF-16 code units, 200 UTF-8 bytes
#define ZONE_NAME_U16_MAX 128
@ -255,7 +256,7 @@ public:
private:
Locale fLocale;
char fRegion[ULOC_COUNTRY_CAPACITY];
CharString fRegion;
};
U_NAMESPACE_END