X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b75a7d8f3b4adbae880cab104ce2c6a50eee4db2..46f4442e9a5a4f3b98b7c1083586332f6a8a99a4:/icuSources/i18n/ucurr.cpp diff --git a/icuSources/i18n/ucurr.cpp b/icuSources/i18n/ucurr.cpp index 4eb42de4..7705a5bd 100644 --- a/icuSources/i18n/ucurr.cpp +++ b/icuSources/i18n/ucurr.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (c) 2002-2003, International Business Machines +* Copyright (c) 2002-2008, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** */ @@ -11,13 +11,18 @@ #include "unicode/ucurr.h" #include "unicode/locid.h" -#include "unicode/resbund.h" +#include "unicode/ures.h" #include "unicode/ustring.h" +#include "unicode/choicfmt.h" +#include "unicode/parsepos.h" +#include "ustr_imp.h" #include "cmemory.h" #include "cstring.h" #include "uassert.h" -#include "iculserv.h" +#include "umutex.h" #include "ucln_in.h" +#include "uenumimp.h" +#include "uresimp.h" //------------------------------------------------------------ // Constants @@ -38,7 +43,9 @@ static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1; //------------------------------------------------------------ // Resource tags +// +static const char CURRENCY_DATA[] = "supplementalData"; // Tag for meta-data, in root. static const char CURRENCY_META[] = "CurrencyMeta"; @@ -55,7 +62,15 @@ static const char VAR_PRE_EURO[] = "PREEURO"; static const char VAR_EURO[] = "EURO"; // Variant delimiter -static const char VAR_DELIM[] = "_"; +static const char VAR_DELIM = '_'; +static const char VAR_DELIM_STR[] = "_"; + +// Variant for legacy euro mapping in CurrencyMap +//static const char VAR_DELIM_EURO[] = "_EURO"; + +#define VARIANT_IS_EMPTY 0 +#define VARIANT_IS_EURO 0x1 +#define VARIANT_IS_PREEURO 0x2 // Tag for localized display names (symbols) of currencies static const char CURRENCIES[] = "Currencies"; @@ -66,6 +81,8 @@ static const char CURRENCIES[] = "Currencies"; // the first mark is deleted. static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign +static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0}; + //------------------------------------------------------------ // Code @@ -87,41 +104,86 @@ myUCharsToChars(char* resultOfLen4, const UChar* currency) { * units of 10^(-fraction_digits). */ static const int32_t* -_findMetaData(const UChar* currency) { +_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.] - UErrorCode ec = U_ZERO_ERROR; - ResourceBundle currencyMeta = - ResourceBundle((char*)0, Locale(""), ec).get(CURRENCY_META, ec); - + 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]; - ResourceBundle rb = currencyMeta.get(myUCharsToChars(buf, currency), ec); - if (U_FAILURE(ec)) { - rb = currencyMeta.get(DEFAULT_META, ec); + 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 = rb.getIntVector(len, ec); - if (U_FAILURE(ec) || len < 2) { + 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; } +// ------------------------------------- + +/** + * @see VARIANT_IS_EURO + * @see VARIANT_IS_PREEURO + */ +static uint32_t +idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec) +{ + uint32_t variantType = 0; + // !!! this is internal only, assumes buffer is not null and capacity is sufficient + // Extract the country name and variant name. We only + // recognize two variant names, EURO and PREEURO. + char variant[ULOC_FULLNAME_CAPACITY]; + uloc_getCountry(locale, countryAndVariant, capacity, ec); + uloc_getVariant(locale, variant, sizeof(variant), ec); + if (variant[0] != 0) { + variantType = (0 == uprv_strcmp(variant, VAR_EURO)) + | ((0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1); + if (variantType) + { + uprv_strcat(countryAndVariant, VAR_DELIM_STR); + uprv_strcat(countryAndVariant, variant); + } + } + return variantType; +} // ------------------------------------------ // @@ -131,21 +193,25 @@ _findMetaData(const UChar* currency) { // don't use ICUService since we don't need fallback +#if !UCONFIG_NO_SERVICE +U_CDECL_BEGIN +static UBool U_CALLCONV currency_cleanup(void); +U_CDECL_END struct CReg; /* Remember to call umtx_init(&gCRegLock) before using it! */ static UMTX gCRegLock = 0; static CReg* gCRegHead = 0; -struct CReg : public UMemory { +struct CReg : public U_NAMESPACE_QUALIFIER UMemory { CReg *next; UChar iso[ISO_COUNTRY_CODE_LENGTH+1]; char id[ULOC_FULLNAME_CAPACITY]; - + CReg(const UChar* _iso, const char* _id) : next(0) { - int32_t len = uprv_strlen(_id); + int32_t len = (int32_t)uprv_strlen(_id); if (len > (int32_t)(sizeof(id)-1)) { len = (sizeof(id)-1); } @@ -154,59 +220,65 @@ struct CReg : public UMemory { uprv_memcpy(iso, _iso, ISO_COUNTRY_CODE_LENGTH * sizeof(const UChar)); iso[ISO_COUNTRY_CODE_LENGTH] = 0; } - + static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status) { if (status && U_SUCCESS(*status) && _iso && _id) { CReg* n = new CReg(_iso, _id); if (n) { umtx_init(&gCRegLock); - Mutex mutex(&gCRegLock); + umtx_lock(&gCRegLock); if (!gCRegHead) { - ucln_i18n_registerCleanup(); + /* register for the first time */ + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); } n->next = gCRegHead; gCRegHead = n; + umtx_unlock(&gCRegLock); return n; } *status = U_MEMORY_ALLOCATION_ERROR; } return 0; } - + static UBool unreg(UCurrRegistryKey key) { + UBool found = FALSE; umtx_init(&gCRegLock); - Mutex mutex(&gCRegLock); - if (gCRegHead == key) { - gCRegHead = gCRegHead->next; - delete (CReg*)key; - return TRUE; - } - - CReg* p = gCRegHead; - while (p) { - if (p->next == key) { - p->next = ((CReg*)key)->next; - delete (CReg*)key; - return TRUE; + umtx_lock(&gCRegLock); + + CReg** p = &gCRegHead; + while (*p) { + if (*p == key) { + *p = ((CReg*)key)->next; + delete (CReg*)key; + found = TRUE; + break; } - p = p->next; + p = &((*p)->next); } - - return FALSE; + + umtx_unlock(&gCRegLock); + return found; } - + static const UChar* get(const char* id) { + const UChar* result = NULL; umtx_init(&gCRegLock); - Mutex mutex(&gCRegLock); + umtx_lock(&gCRegLock); CReg* p = gCRegHead; + + /* register cleanup of the mutex */ + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); while (p) { if (uprv_strcmp(id, p->id) == 0) { - return p->iso; + result = p->iso; + break; } p = p->next; } - return NULL; + umtx_unlock(&gCRegLock); + return result; } /* This doesn't need to be thread safe. It's for u_cleanup only. */ @@ -220,29 +292,22 @@ struct CReg : public UMemory { } }; -// ------------------------------------- - -static void -idForLocale(const char* locale, char* buffer, int capacity, UErrorCode* ec) -{ - // !!! this is internal only, assumes buffer is not null and capacity is sufficient - // Extract the country name and variant name. We only - // recognize two variant names, EURO and PREEURO. - char variant[ULOC_FULLNAME_CAPACITY]; - uloc_getCountry(locale, buffer, capacity, ec); - uloc_getVariant(locale, variant, sizeof(variant), ec); - if (0 == uprv_strcmp(variant, VAR_PRE_EURO) || - 0 == uprv_strcmp(variant, VAR_EURO)) - { - uprv_strcat(buffer, VAR_DELIM); - uprv_strcat(buffer, variant); - } +/** + * Release all static memory held by currency. + */ +U_CDECL_BEGIN +static UBool U_CALLCONV currency_cleanup(void) { +#if !UCONFIG_NO_SERVICE + CReg::cleanup(); +#endif + return TRUE; } +U_CDECL_END // ------------------------------------- U_CAPI UCurrRegistryKey U_EXPORT2 -ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status) +ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status) { if (status && U_SUCCESS(*status)) { char id[ULOC_FULLNAME_CAPACITY]; @@ -255,43 +320,106 @@ ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status) // ------------------------------------- U_CAPI UBool U_EXPORT2 -ucurr_unregister(UCurrRegistryKey key, UErrorCode* status) +ucurr_unregister(UCurrRegistryKey key, UErrorCode* status) { if (status && U_SUCCESS(*status)) { return CReg::unreg(key); } return FALSE; } +#endif /* UCONFIG_NO_SERVICE */ // ------------------------------------- -U_CAPI const UChar* U_EXPORT2 -ucurr_forLocale(const char* locale, UErrorCode* ec) { +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)) { - char id[ULOC_FULLNAME_CAPACITY]; - idForLocale(locale, id, sizeof(id), ec); - if (U_FAILURE(*ec)) { - return NULL; - } - - const UChar* result = CReg::get(id); - if (result) { - return result; - } - - // Look up the CurrencyMap element in the root bundle. - UResourceBundle* rb = ures_open(NULL, "", ec); - UResourceBundle* cm = ures_getByKey(rb, CURRENCY_MAP, NULL, ec); - int32_t len; - const UChar* s = ures_getStringByKey(cm, id, &len, ec); - ures_close(cm); - ures_close(rb); - - if (U_SUCCESS(*ec)) { - return s; + 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) { + u_charsToUChars(id, buff, resLen); + } + } else { + // get country or country_variant in `id' + uint32_t variantType = idForLocale(locale, id, sizeof(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); + } +#endif + // Remove variants, which is only needed for registration. + char *idDelim = strchr(id, VAR_DELIM); + if (idDelim) { + idDelim[0] = 0; + } + + // Look up the CurrencyMap element in the root bundle. + UResourceBundle *rb = ures_openDirect(NULL, 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); + } + 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); + } + } + } + return u_terminateUChars(buff, buffCapacity, resLen, ec); + } else { + *ec = U_ILLEGAL_ARGUMENT_ERROR; } } - return NULL; + return resLen; } // end registration @@ -308,7 +436,7 @@ static UBool fallback(char *loc) { return FALSE; } UErrorCode status = U_ZERO_ERROR; - uloc_getParent(loc, loc, uprv_strlen(loc), &status); + uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status); /* char *i = uprv_strrchr(loc, '_'); if (i == NULL) { @@ -331,7 +459,7 @@ ucurr_getName(const UChar* currency, // Look up the Currencies resource for the given locale. The // Currencies locale data looks like this: //|en { - //| Currencies { + //| Currencies { //| USD { "US$", "US Dollar" } //| CHF { "Sw F", "Swiss Franc" } //| INR { "=0#Rs|1#Re|1 0 && s[0] == CHOICE_FORMAT_MARK) { + ++s; + --len; + if (len > 0 && s[0] != CHOICE_FORMAT_MARK) { + isChoice = TRUE; + } + } + if (isChoice) { + Formattable temp; + ChoiceFormat fmt(s, ec2); + fmt.parse(text, temp, pos); + len = pos.getIndex() - start; + pos.setIndex(start); + } else if (len > max && + text.compare(pos.getIndex(), len, s) != 0) { + len = 0; + } + if (len > max) { + iso = ures_getKey(names); + max = len; + } + ures_close(names); + } + ures_close(curr); + ures_close(rb); + + // Try to fallback. If that fails (because we are already at + // root) then exit. + if (!fallback(loc)) { + break; + } + } + + if (iso != NULL) { + u_charsToUChars(iso, result, 4); + } + + // If display name parse fails or if it matches fewer than 3 + // characters, try to parse 3-letter ISO. Do this after the + // display name processing so 3-letter display names are + // preferred. Consider /[A-Z]{3}/ to be valid ISO, and parse + // it manually--UnicodeSet/regex are too slow and heavy. + if (max < 3 && (text.length() - start) >= 3) { + UBool valid = TRUE; + for (int32_t k=0; k<3; ++k) { + UChar ch = text.charAt(start + k); // 16-bit ok + if (ch < 0x41/*'A'*/ || ch > 0x5A/*'Z'*/) { + valid = FALSE; + break; + } + } + if (valid) { + text.extract(start, 3, result); + result[3] = 0; + max = 3; + } + } + + pos.setIndex(start + max); +} + +/** + * Internal method. Given a currency ISO code and a locale, return + * the "static" currency name. This is usually the same as the + * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the + * format is applied to the number 2.0 (to yield the more common + * plural) to return a static name. + * + * This is used for backward compatibility with old currency logic in + * DecimalFormat and DecimalFormatSymbols. + */ +U_CFUNC void +uprv_getStaticCurrencyName(const UChar* iso, const char* loc, + U_NAMESPACE_QUALIFIER UnicodeString& result, UErrorCode& ec) +{ + U_NAMESPACE_USE + + UBool isChoiceFormat; + int32_t len; + const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec); + if (U_SUCCESS(ec)) { + // If this is a ChoiceFormat currency, then format an + // arbitrary value; pick something != 1; more common. + result.truncate(0); + if (isChoiceFormat) { + ChoiceFormat f(currname, ec); + if (U_SUCCESS(ec)) { + f.format(2.0, result); + } else { + result = iso; + } + } else { + result = currname; + } + } +} U_CAPI int32_t U_EXPORT2 -ucurr_getDefaultFractionDigits(const UChar* currency) { - return (_findMetaData(currency))[0]; +ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) { + return (_findMetaData(currency, *ec))[0]; } U_CAPI double U_EXPORT2 -ucurr_getRoundingIncrement(const UChar* currency) { - const int32_t *data = _findMetaData(currency); +ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) { + const int32_t *data = _findMetaData(currency, *ec); + + // If the meta data is invalid, return 0.0. + if (data[0] < 0 || data[0] > MAX_POW10) { + if (U_SUCCESS(*ec)) { + *ec = U_INVALID_FORMAT_ERROR; + } + return 0.0; + } - // If there is no rounding, or if the meta data is invalid, - // return 0.0 to indicate no rounding. A rounding value - // (data[1]) of 0 or 1 indicates no rounding. - if (data[1] < 2 || data[0] < 0 || data[0] > MAX_POW10) { + // If there is no rounding, return 0.0 to indicate no rounding. A + // rounding value (data[1]) of 0 or 1 indicates no rounding. + if (data[1] < 2) { return 0.0; } @@ -453,12 +739,651 @@ ucurr_getRoundingIncrement(const UChar* currency) { return double(data[1]) / POW10[data[0]]; } -/** - * Release all static memory held by currency. - */ -U_CFUNC UBool currency_cleanup(void) { - CReg::cleanup(); - return TRUE; +U_CDECL_BEGIN + +typedef struct UCurrencyContext { + uint32_t currType; /* UCurrCurrencyType */ + uint32_t listIdx; +} UCurrencyContext; + +/* +Please keep this list in alphabetical order. +You can look at the CLDR supplemental data or ISO-4217 for the meaning of some +of these items. +ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html +*/ +static const struct CurrencyList { + const char *currency; + uint32_t currType; +} gCurrencyList[] = { + {"ADP", UCURR_COMMON|UCURR_DEPRECATED}, + {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"AFA", UCURR_COMMON|UCURR_DEPRECATED}, + {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ALK", UCURR_COMMON|UCURR_DEPRECATED}, + {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"AOK", UCURR_COMMON|UCURR_DEPRECATED}, + {"AON", UCURR_COMMON|UCURR_DEPRECATED}, + {"AOR", UCURR_COMMON|UCURR_DEPRECATED}, + {"ARA", UCURR_COMMON|UCURR_DEPRECATED}, + {"ARP", UCURR_COMMON|UCURR_DEPRECATED}, + {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ATS", UCURR_COMMON|UCURR_DEPRECATED}, + {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"AZM", UCURR_COMMON|UCURR_DEPRECATED}, + {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BAD", UCURR_COMMON|UCURR_DEPRECATED}, + {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"BEF", UCURR_COMMON|UCURR_DEPRECATED}, + {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"BGL", UCURR_COMMON|UCURR_DEPRECATED}, + {"BGM", UCURR_COMMON|UCURR_DEPRECATED}, + {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BOP", UCURR_COMMON|UCURR_DEPRECATED}, + {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"BRB", UCURR_COMMON|UCURR_DEPRECATED}, + {"BRC", UCURR_COMMON|UCURR_DEPRECATED}, + {"BRE", UCURR_COMMON|UCURR_DEPRECATED}, + {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BRN", UCURR_COMMON|UCURR_DEPRECATED}, + {"BRR", UCURR_COMMON|UCURR_DEPRECATED}, + {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BUK", UCURR_COMMON|UCURR_DEPRECATED}, + {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BYB", UCURR_COMMON|UCURR_DEPRECATED}, + {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CSD", UCURR_COMMON|UCURR_DEPRECATED}, + {"CSK", UCURR_COMMON|UCURR_DEPRECATED}, + {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CYP", UCURR_COMMON|UCURR_DEPRECATED}, + {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"DDM", UCURR_COMMON|UCURR_DEPRECATED}, + {"DEM", UCURR_COMMON|UCURR_DEPRECATED}, + {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ECS", UCURR_COMMON|UCURR_DEPRECATED}, + {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"EEK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"EQE", UCURR_COMMON|UCURR_DEPRECATED}, + {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"ESP", UCURR_COMMON|UCURR_DEPRECATED}, + {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"FIM", UCURR_COMMON|UCURR_DEPRECATED}, + {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"FRF", UCURR_COMMON|UCURR_DEPRECATED}, + {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GEK", UCURR_COMMON|UCURR_DEPRECATED}, + {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GHC", UCURR_COMMON|UCURR_DEPRECATED}, + {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GNS", UCURR_COMMON|UCURR_DEPRECATED}, + {"GQE", UCURR_COMMON|UCURR_DEPRECATED}, + {"GRD", UCURR_COMMON|UCURR_DEPRECATED}, + {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GWE", UCURR_COMMON|UCURR_DEPRECATED}, + {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"HRD", UCURR_COMMON|UCURR_DEPRECATED}, + {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"IEP", UCURR_COMMON|UCURR_DEPRECATED}, + {"ILP", UCURR_COMMON|UCURR_DEPRECATED}, + {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ITL", UCURR_COMMON|UCURR_DEPRECATED}, + {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LSM", UCURR_COMMON|UCURR_DEPRECATED}, + {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LTT", UCURR_COMMON|UCURR_DEPRECATED}, + {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"LUF", UCURR_COMMON|UCURR_DEPRECATED}, + {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LVR", UCURR_COMMON|UCURR_DEPRECATED}, + {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MAF", UCURR_COMMON|UCURR_DEPRECATED}, + {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MGF", UCURR_COMMON|UCURR_DEPRECATED}, + {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MLF", UCURR_COMMON|UCURR_DEPRECATED}, + {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MTL", UCURR_COMMON|UCURR_DEPRECATED}, + {"MTP", UCURR_COMMON|UCURR_DEPRECATED}, + {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MXP", UCURR_COMMON|UCURR_DEPRECATED}, + {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MZM", UCURR_COMMON|UCURR_DEPRECATED}, + {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"NIC", UCURR_COMMON|UCURR_DEPRECATED}, + {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"NLG", UCURR_COMMON|UCURR_DEPRECATED}, + {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"PEI", UCURR_COMMON|UCURR_DEPRECATED}, + {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"PES", UCURR_COMMON|UCURR_DEPRECATED}, + {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"PLZ", UCURR_COMMON|UCURR_DEPRECATED}, + {"PTE", UCURR_COMMON|UCURR_DEPRECATED}, + {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"RHD", UCURR_COMMON|UCURR_DEPRECATED}, + {"ROL", UCURR_COMMON|UCURR_DEPRECATED}, + {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"RUR", UCURR_COMMON|UCURR_DEPRECATED}, + {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SDD", UCURR_COMMON|UCURR_DEPRECATED}, + {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SDP", UCURR_COMMON|UCURR_DEPRECATED}, + {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SIT", UCURR_COMMON|UCURR_DEPRECATED}, + {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SRG", UCURR_COMMON|UCURR_DEPRECATED}, + {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SUR", UCURR_COMMON|UCURR_DEPRECATED}, + {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TJR", UCURR_COMMON|UCURR_DEPRECATED}, + {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TMM", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TPE", UCURR_COMMON|UCURR_DEPRECATED}, + {"TRL", UCURR_COMMON|UCURR_DEPRECATED}, + {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"UAK", UCURR_COMMON|UCURR_DEPRECATED}, + {"UGS", UCURR_COMMON|UCURR_DEPRECATED}, + {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"UYP", UCURR_COMMON|UCURR_DEPRECATED}, + {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"VEB", UCURR_COMMON|UCURR_DEPRECATED}, + {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED}, + {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"YDD", UCURR_COMMON|UCURR_DEPRECATED}, + {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"YUD", UCURR_COMMON|UCURR_DEPRECATED}, + {"YUM", UCURR_COMMON|UCURR_DEPRECATED}, + {"YUN", UCURR_COMMON|UCURR_DEPRECATED}, + {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"ZRN", UCURR_COMMON|UCURR_DEPRECATED}, + {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED}, + {"ZWD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + { NULL, 0 } // Leave here to denote the end of the list. +}; + +#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \ + ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch)) + +static int32_t U_CALLCONV +ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) { + UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context); + uint32_t currType = myContext->currType; + int32_t count = 0; + + /* Count the number of items matching the type we are looking for. */ + for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) { + if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) { + count++; + } + } + return count; +} + +static const char* U_CALLCONV +ucurr_nextCurrencyList(UEnumeration *enumerator, + int32_t* resultLength, + UErrorCode * /*pErrorCode*/) +{ + UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context); + + /* Find the next in the list that matches the type we are looking for. */ + while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) { + const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++]; + if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType)) + { + if (resultLength) { + *resultLength = 3; /* Currency codes are only 3 chars long */ + } + return currItem->currency; + } + } + /* We enumerated too far. */ + if (resultLength) { + *resultLength = 0; + } + return NULL; +} + +static void U_CALLCONV +ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) { + ((UCurrencyContext *)(enumerator->context))->listIdx = 0; +} + +static void U_CALLCONV +ucurr_closeCurrencyList(UEnumeration *enumerator) { + uprv_free(enumerator->context); + uprv_free(enumerator); +} + +static const UEnumeration gEnumCurrencyList = { + NULL, + NULL, + ucurr_closeCurrencyList, + ucurr_countCurrencyList, + uenum_unextDefault, + ucurr_nextCurrencyList, + ucurr_resetCurrencyList +}; +U_CDECL_END + +U_CAPI UEnumeration * U_EXPORT2 +ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) { + UEnumeration *myEnum = NULL; + UCurrencyContext *myContext; + + myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration)); + if (myEnum == NULL) { + *pErrorCode = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration)); + myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext)); + if (myContext == NULL) { + *pErrorCode = U_MEMORY_ALLOCATION_ERROR; + uprv_free(myEnum); + return NULL; + } + myContext->currType = currType; + myContext->listIdx = 0; + myEnum->context = myContext; + return myEnum; +} + +U_CAPI int32_t U_EXPORT2 +ucurr_countCurrencies(const char* locale, + UDate date, + UErrorCode* ec) +{ + int32_t currCount = 0; + int32_t resLen = 0; + const UChar* s = NULL; + + if (ec != NULL && U_SUCCESS(*ec)) + { + // local variables + UErrorCode localStatus = U_ZERO_ERROR; + char id[ULOC_FULLNAME_CAPACITY]; + resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus); + + // get country or country_variant in `id' + uint32_t variantType = idForLocale(locale, id, sizeof(id), ec); + if (U_FAILURE(*ec)) + { + return 0; + } + + // Remove variants, which is only needed for registration. + char *idDelim = strchr(id, VAR_DELIM); + if (idDelim) + { + idDelim[0] = 0; + } + + // Look up the CurrencyMap element in the root bundle. + UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus); + UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); + + // Using the id derived from the local, get the currency data + UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus); + + // process each currency to see which one is valid for the given date + if (U_SUCCESS(localStatus)) + { + for (int32_t i=0; i 2) + { + int32_t toLength = 0; + UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus); + const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus); + + currDate64 = (int64_t)toArray[0] << 32; + currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); + UDate toDate = (UDate)currDate64; + + if ((fromDate <= date) && (date < toDate)) + { + currCount++; + } + + ures_close(toRes); + } + else + { + if (fromDate <= date) + { + currCount++; + } + } + + // close open resources + ures_close(currencyRes); + ures_close(fromRes); + + } // end For loop + } // end if (U_SUCCESS(localStatus)) + + ures_close(countryArray); + + // Check for errors + 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)) + { + // no errors + return currCount; + } + + } + + // If we got here, either error code is invalid or + // some argument passed is no good. + return 0; +} + +U_CAPI int32_t U_EXPORT2 +ucurr_forLocaleAndDate(const char* locale, + UDate date, + int32_t index, + UChar* buff, + int32_t buffCapacity, + UErrorCode* ec) +{ + int32_t resLen = 0; + int32_t currIndex = 0; + const UChar* s = NULL; + + if (ec != NULL && U_SUCCESS(*ec)) + { + // check the arguments passed + if ((buff && buffCapacity) || !buffCapacity ) + { + // local variables + UErrorCode localStatus = U_ZERO_ERROR; + char id[ULOC_FULLNAME_CAPACITY]; + resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus); + + // get country or country_variant in `id' + uint32_t variantType = idForLocale(locale, id, sizeof(id), ec); + if (U_FAILURE(*ec)) + { + return 0; + } + + // Remove variants, which is only needed for registration. + char *idDelim = strchr(id, VAR_DELIM); + if (idDelim) + { + idDelim[0] = 0; + } + + // Look up the CurrencyMap element in the root bundle. + UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus); + UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); + + // Using the id derived from the local, get the currency data + UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus); + + // process each currency to see which one is valid for the given date + bool matchFound = false; + if (U_SUCCESS(localStatus)) + { + if ((index <= 0) || (index > ures_getSize(countryArray))) + { + // requested index is out of bounds + ures_close(countryArray); + return 0; + } + + for (int32_t i=0; i 2) + { + int32_t toLength = 0; + UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus); + const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus); + + currDate64 = (int64_t)toArray[0] << 32; + currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); + UDate toDate = (UDate)currDate64; + + if ((fromDate <= date) && (date < toDate)) + { + currIndex++; + if (currIndex == index) + { + matchFound = true; + } + } + + ures_close(toRes); + } + else + { + if (fromDate <= date) + { + currIndex++; + if (currIndex == index) + { + matchFound = true; + } + } + } + + // close open resources + ures_close(currencyRes); + ures_close(fromRes); + + // check for loop exit + if (matchFound) + { + break; + } + + } // end For loop + } + + ures_close(countryArray); + + // Check for errors + 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)) + { + // no errors + if((buffCapacity > resLen) && matchFound) + { + // write out the currency value + u_strcpy(buff, s); + } + else + { + return 0; + } + } + + // return null terminated currency string + return u_terminateUChars(buff, buffCapacity, resLen, ec); + } + else + { + // illegal argument encountered + *ec = U_ILLEGAL_ARGUMENT_ERROR; + } + + } + + // If we got here, either error code is invalid or + // some argument passed is no good. + return resLen; } #endif /* #if !UCONFIG_NO_FORMATTING */