/** * Internal function to look up currency data. Result is an array of * two integers. The first is the fraction digits. The second is the * rounding increment, or 0 if none. The rounding increment is in * units of 10^(-fraction_digits). */ static const int32_t* _findMetaData(const UChar* currency) { // Get CurrencyMeta resource out of root locale file. [This may // move out of the root locale file later; if it does, update this // code.] UErrorCode ec = U_ZERO_ERROR; ResourceBundle currencyMeta = ResourceBundle((char*)0, Locale(""), ec).get(CURRENCY_META, ec); if (U_FAILURE(ec)) { // Config/build error; return hard-coded defaults return LAST_RESORT_DATA; } // Look up our currency, or if that's not available, then DEFAULT char buf[ISO_COUNTRY_CODE_LENGTH+1]; ResourceBundle rb = currencyMeta.get(myUCharsToChars(buf, currency), ec); if (U_FAILURE(ec)) { rb = currencyMeta.get(DEFAULT_META, ec); if (U_FAILURE(ec)) { // Config/build error; return hard-coded defaults return LAST_RESORT_DATA; } } int32_t len; const int32_t *data = rb.getIntVector(len, ec); if (U_FAILURE(ec) || len < 2) { // Config/build error; return hard-coded defaults return LAST_RESORT_DATA; } return data; }
/** * Internal function to look up currency data. Result is an array of * two integers. The first is the fraction digits. The second is the * rounding increment, or 0 if none. The rounding increment is in * units of 10^(-fraction_digits). */ static const int32_t* _findMetaData(const UChar* currency, UErrorCode& ec) { if (currency == 0 || *currency == 0) { if (U_SUCCESS(ec)) { ec = U_ILLEGAL_ARGUMENT_ERROR; } return LAST_RESORT_DATA; } // Get CurrencyMeta resource out of root locale file. [This may // move out of the root locale file later; if it does, update this // code.] UResourceBundle* currencyData = ures_openDirect(NULL, CURRENCY_DATA, &ec); UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec); if (U_FAILURE(ec)) { ures_close(currencyMeta); // Config/build error; return hard-coded defaults return LAST_RESORT_DATA; } // Look up our currency, or if that's not available, then DEFAULT char buf[ISO_COUNTRY_CODE_LENGTH+1]; UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2); if (U_FAILURE(ec2)) { ures_close(rb); rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec); if (U_FAILURE(ec)) { ures_close(currencyMeta); ures_close(rb); // Config/build error; return hard-coded defaults return LAST_RESORT_DATA; } } int32_t len; const int32_t *data = ures_getIntVector(rb, &len, &ec); if (U_FAILURE(ec) || len != 2) { // Config/build error; return hard-coded defaults if (U_SUCCESS(ec)) { ec = U_INVALID_FORMAT_ERROR; } ures_close(currencyMeta); ures_close(rb); return LAST_RESORT_DATA; } ures_close(currencyMeta); ures_close(rb); return data; }
U_CAPI const UChar* U_EXPORT2 ucurr_getName(const UChar* currency, const char* locale, UCurrNameStyle nameStyle, UBool* isChoiceFormat, // fillin int32_t* len, // fillin UErrorCode* ec) { // Look up the Currencies resource for the given locale. The // Currencies locale data looks like this: //|en { //| Currencies { //| USD { "US$", "US Dollar" } //| CHF { "Sw F", "Swiss Franc" } //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" } //| //... //| } //|} if (U_FAILURE(*ec)) { return 0; } int32_t choice = (int32_t) nameStyle; if (choice < 0 || choice > 1) { *ec = U_ILLEGAL_ARGUMENT_ERROR; return 0; } // In the future, resource bundles may implement multi-level // fallback. That is, if a currency is not found in the en_US // Currencies data, then the en Currencies data will be searched. // Currently, if a Currencies datum exists in en_US and en, the // en_US entry hides that in en. // We want multi-level fallback for this resource, so we implement // it manually. // Use a separate UErrorCode here that does not propagate out of // this function. UErrorCode ec2 = U_ZERO_ERROR; char loc[ULOC_FULLNAME_CAPACITY]; uloc_getName(locale, loc, sizeof(loc), &ec2); if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) { *ec = U_ILLEGAL_ARGUMENT_ERROR; return 0; } char buf[ISO_COUNTRY_CODE_LENGTH+1]; myUCharsToChars(buf, currency); const UChar* s = NULL; ec2 = U_ZERO_ERROR; UResourceBundle* rb = ures_open(NULL, loc, &ec2); rb = ures_getByKey(rb, CURRENCIES, rb, &ec2); // Fetch resource with multi-level resource inheritance fallback rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2); s = ures_getStringByIndex(rb, choice, len, &ec2); ures_close(rb); // If we've succeeded we're done. Otherwise, try to fallback. // If that fails (because we are already at root) then exit. if (U_SUCCESS(ec2)) { if (ec2 == U_USING_DEFAULT_WARNING || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) { *ec = ec2; } } // Determine if this is a ChoiceFormat pattern. One leading mark // indicates a ChoiceFormat. Two indicates a static string that // starts with a mark. In either case, the first mark is ignored, // if present. Marks in the rest of the string have no special // meaning. *isChoiceFormat = FALSE; if (U_SUCCESS(ec2)) { U_ASSERT(s != NULL); int32_t i=0; while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) { ++i; } *isChoiceFormat = (i == 1); if (i != 0) ++s; // Skip over first mark return s; } // If we fail to find a match, use the ISO 4217 code *len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...? *ec = U_USING_DEFAULT_WARNING; return currency; }