| diff --git a/source/common/ucurr.cpp b/source/common/ucurr.cpp |
| index 885ca3a9..f2cae13c 100644 |
| --- a/source/common/ucurr.cpp |
| +++ b/source/common/ucurr.cpp |
| @@ -25,6 +25,7 @@ |
| #include "uenumimp.h" |
| #include "uhash.h" |
| #include "hash.h" |
| +#include "uinvchar.h" |
| #include "uresimp.h" |
| #include "ulist.h" |
| #include "ureslocs.h" |
| @@ -545,93 +546,97 @@ U_CAPI int32_t U_EXPORT2 |
| ucurr_forLocale(const char* locale, |
| UChar* buff, |
| int32_t buffCapacity, |
| - UErrorCode* ec) |
| -{ |
| - int32_t resLen = 0; |
| - const UChar* s = NULL; |
| - if (ec != NULL && U_SUCCESS(*ec)) { |
| - if ((buff && buffCapacity) || !buffCapacity) { |
| - UErrorCode localStatus = U_ZERO_ERROR; |
| - char id[ULOC_FULLNAME_CAPACITY]; |
| - if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) { |
| - // there is a currency keyword. Try to see if it's valid |
| - if(buffCapacity > resLen) { |
| - /* Normalize the currency keyword value to upper case. */ |
| - T_CString_toUpperCase(id); |
| - u_charsToUChars(id, buff, resLen); |
| - } |
| - } else { |
| - // get country or country_variant in `id' |
| - uint32_t variantType = idForLocale(locale, id, sizeof(id), ec); |
| + UErrorCode* ec) { |
| + if (U_FAILURE(*ec)) { return 0; } |
| + if (buffCapacity < 0 || (buff == nullptr && buffCapacity > 0)) { |
| + *ec = U_ILLEGAL_ARGUMENT_ERROR; |
| + return 0; |
| + } |
| |
| - if (U_FAILURE(*ec)) { |
| - return 0; |
| - } |
| + char currency[4]; // ISO currency codes are alpha3 codes. |
| + UErrorCode localStatus = U_ZERO_ERROR; |
| + int32_t resLen = uloc_getKeywordValue(locale, "currency", |
| + currency, UPRV_LENGTHOF(currency), &localStatus); |
| + if (U_SUCCESS(localStatus) && resLen == 3 && uprv_isInvariantString(currency, resLen)) { |
| + if (resLen < buffCapacity) { |
| + T_CString_toUpperCase(currency); |
| + u_charsToUChars(currency, buff, resLen); |
| + } |
| + return u_terminateUChars(buff, buffCapacity, resLen, ec); |
| + } |
| + |
| + // get country or country_variant in `id' |
| + char id[ULOC_FULLNAME_CAPACITY]; |
| + uint32_t variantType = idForLocale(locale, id, UPRV_LENGTHOF(id), ec); |
| + if (U_FAILURE(*ec)) { |
| + return 0; |
| + } |
| |
| #if !UCONFIG_NO_SERVICE |
| - const UChar* result = CReg::get(id); |
| - if (result) { |
| - if(buffCapacity > u_strlen(result)) { |
| - u_strcpy(buff, result); |
| - } |
| - return u_strlen(result); |
| - } |
| + const UChar* result = CReg::get(id); |
| + if (result) { |
| + if(buffCapacity > u_strlen(result)) { |
| + u_strcpy(buff, result); |
| + } |
| + resLen = u_strlen(result); |
| + return u_terminateUChars(buff, buffCapacity, resLen, ec); |
| + } |
| #endif |
| - // Remove variants, which is only needed for registration. |
| - char *idDelim = strchr(id, VAR_DELIM); |
| - if (idDelim) { |
| - idDelim[0] = 0; |
| - } |
| + // Remove variants, which is only needed for registration. |
| + char *idDelim = uprv_strchr(id, VAR_DELIM); |
| + if (idDelim) { |
| + idDelim[0] = 0; |
| + } |
| |
| - // Look up the CurrencyMap element in the root bundle. |
| - UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus); |
| - UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); |
| - UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus); |
| - UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus); |
| + const UChar* s; // Currency code from data file. |
| + if (id[0] == 0) { |
| + // No point looking in the data for an empty string. |
| + // This is what we would get. |
| + localStatus = U_MISSING_RESOURCE_ERROR; |
| + } else { |
| + // Look up the CurrencyMap element in the root bundle. |
| + localStatus = U_ZERO_ERROR; |
| + UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus); |
| + UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); |
| + UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus); |
| + UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus); |
| + s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus); |
| + |
| + // Get the second item when PREEURO is requested, and this is a known Euro country. |
| + // If the requested variant is PREEURO, and this isn't a Euro country, |
| + // assume that the country changed over to the Euro in the future. |
| + // This is probably an old version of ICU that hasn't been updated yet. |
| + // The latest currency is probably correct. |
| + if (U_SUCCESS(localStatus)) { |
| + if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) { |
| + currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus); |
| s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus); |
| - |
| - /* |
| - Get the second item when PREEURO is requested, and this is a known Euro country. |
| - If the requested variant is PREEURO, and this isn't a Euro country, assume |
| - that the country changed over to the Euro in the future. This is probably |
| - an old version of ICU that hasn't been updated yet. The latest currency is |
| - probably correct. |
| - */ |
| - if (U_SUCCESS(localStatus)) { |
| - if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) { |
| - currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus); |
| - s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus); |
| - } |
| - else if ((variantType & VARIANT_IS_EURO)) { |
| - s = EUR_STR; |
| - } |
| - } |
| - ures_close(countryArray); |
| - ures_close(currencyReq); |
| - |
| - if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0) |
| - { |
| - // We don't know about it. Check to see if we support the variant. |
| - uloc_getParent(locale, id, sizeof(id), ec); |
| - *ec = U_USING_FALLBACK_WARNING; |
| - return ucurr_forLocale(id, buff, buffCapacity, ec); |
| - } |
| - else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) { |
| - // There is nothing to fallback to. Report the failure/warning if possible. |
| - *ec = localStatus; |
| - } |
| - if (U_SUCCESS(*ec)) { |
| - if(buffCapacity > resLen) { |
| - u_strcpy(buff, s); |
| - } |
| - } |
| + } else if ((variantType & VARIANT_IS_EURO)) { |
| + s = EUR_STR; |
| } |
| - return u_terminateUChars(buff, buffCapacity, resLen, ec); |
| - } else { |
| - *ec = U_ILLEGAL_ARGUMENT_ERROR; |
| } |
| + ures_close(currencyReq); |
| + ures_close(countryArray); |
| } |
| - return resLen; |
| + |
| + if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0) { |
| + // We don't know about it. Check to see if we support the variant. |
| + uloc_getParent(locale, id, UPRV_LENGTHOF(id), ec); |
| + *ec = U_USING_FALLBACK_WARNING; |
| + // TODO: Loop over the shortened id rather than recursing and |
| + // looking again for a currency keyword. |
| + return ucurr_forLocale(id, buff, buffCapacity, ec); |
| + } |
| + if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) { |
| + // There is nothing to fallback to. Report the failure/warning if possible. |
| + *ec = localStatus; |
| + } |
| + if (U_SUCCESS(*ec)) { |
| + if(buffCapacity > resLen) { |
| + u_strcpy(buff, s); |
| + } |
| + } |
| + return u_terminateUChars(buff, buffCapacity, resLen, ec); |
| } |
| |
| // end registration |
| diff --git a/source/i18n/dcfmtsym.cpp b/source/i18n/dcfmtsym.cpp |
| index 08a85b54..43eea49e 100644 |
| --- a/source/i18n/dcfmtsym.cpp |
| +++ b/source/i18n/dcfmtsym.cpp |
| @@ -433,12 +433,13 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, UBool us |
| UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out |
| UChar curriso[4]; |
| UnicodeString tempStr; |
| - ucurr_forLocale(locStr, curriso, 4, &internalStatus); |
| - |
| - uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus); |
| - if (U_SUCCESS(internalStatus)) { |
| - fSymbols[kIntlCurrencySymbol].setTo(curriso, -1); |
| - fSymbols[kCurrencySymbol] = tempStr; |
| + int32_t currisoLength = ucurr_forLocale(locStr, curriso, UPRV_LENGTHOF(curriso), &internalStatus); |
| + if (U_SUCCESS(internalStatus) && currisoLength == 3) { |
| + uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus); |
| + if (U_SUCCESS(internalStatus)) { |
| + fSymbols[kIntlCurrencySymbol].setTo(curriso, currisoLength); |
| + fSymbols[kCurrencySymbol] = tempStr; |
| + } |
| } |
| /* else use the default values. */ |
| |