Home | History | Annotate | Download | only in i18n
      1 /*
      2 **********************************************************************
      3 * Copyright (c) 2002-2012, International Business Machines
      4 * Corporation and others.  All Rights Reserved.
      5 **********************************************************************
      6 */
      7 
      8 #include "unicode/utypes.h"
      9 
     10 #if !UCONFIG_NO_FORMATTING
     11 
     12 #include "unicode/ucurr.h"
     13 #include "unicode/locid.h"
     14 #include "unicode/ures.h"
     15 #include "unicode/ustring.h"
     16 #include "unicode/choicfmt.h"
     17 #include "unicode/parsepos.h"
     18 #include "ustr_imp.h"
     19 #include "cmemory.h"
     20 #include "cstring.h"
     21 #include "uassert.h"
     22 #include "umutex.h"
     23 #include "ucln_in.h"
     24 #include "uenumimp.h"
     25 #include "uhash.h"
     26 #include "uresimp.h"
     27 #include "ulist.h"
     28 #include "ureslocs.h"
     29 
     30 // #define UCURR_DEBUG 1
     31 #ifdef UCURR_DEBUG
     32 #include "stdio.h"
     33 #endif
     34 
     35 typedef struct IsoCodeEntry {
     36     const UChar *isoCode; /* const because it's a reference to a resource bundle string. */
     37     UDate from;
     38     UDate to;
     39 } IsoCodeEntry;
     40 
     41 //------------------------------------------------------------
     42 // Constants
     43 
     44 // Default currency meta data of last resort.  We try to use the
     45 // defaults encoded in the meta data resource bundle.  If there is a
     46 // configuration/build error and these are not available, we use these
     47 // hard-coded defaults (which should be identical).
     48 static const int32_t LAST_RESORT_DATA[] = { 2, 0 };
     49 
     50 // POW10[i] = 10^i, i=0..MAX_POW10
     51 static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
     52                                  1000000, 10000000, 100000000, 1000000000 };
     53 
     54 static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
     55 
     56 #define ISO_CURRENCY_CODE_LENGTH 3
     57 
     58 //------------------------------------------------------------
     59 // Resource tags
     60 //
     61 
     62 static const char CURRENCY_DATA[] = "supplementalData";
     63 // Tag for meta-data, in root.
     64 static const char CURRENCY_META[] = "CurrencyMeta";
     65 
     66 // Tag for map from countries to currencies, in root.
     67 static const char CURRENCY_MAP[] = "CurrencyMap";
     68 
     69 // Tag for default meta-data, in CURRENCY_META
     70 static const char DEFAULT_META[] = "DEFAULT";
     71 
     72 // Variant for legacy pre-euro mapping in CurrencyMap
     73 static const char VAR_PRE_EURO[] = "PREEURO";
     74 
     75 // Variant for legacy euro mapping in CurrencyMap
     76 static const char VAR_EURO[] = "EURO";
     77 
     78 // Variant delimiter
     79 static const char VAR_DELIM = '_';
     80 static const char VAR_DELIM_STR[] = "_";
     81 
     82 // Variant for legacy euro mapping in CurrencyMap
     83 //static const char VAR_DELIM_EURO[] = "_EURO";
     84 
     85 #define VARIANT_IS_EMPTY    0
     86 #define VARIANT_IS_EURO     0x1
     87 #define VARIANT_IS_PREEURO  0x2
     88 
     89 // Tag for localized display names (symbols) of currencies
     90 static const char CURRENCIES[] = "Currencies";
     91 static const char CURRENCYPLURALS[] = "CurrencyPlurals";
     92 
     93 // Marker character indicating that a display name is a ChoiceFormat
     94 // pattern.  Strings that start with one mark are ChoiceFormat
     95 // patterns.  Strings that start with 2 marks are static strings, and
     96 // the first mark is deleted.
     97 static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
     98 
     99 static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
    100 
    101 // ISO codes mapping table
    102 static UHashtable* gIsoCodes = NULL;
    103 static UBool gIsoCodesInitialized = FALSE;
    104 
    105 static UMutex gIsoCodesLock = U_MUTEX_INITIALIZER;
    106 
    107 //------------------------------------------------------------
    108 // Code
    109 
    110 /**
    111  * Cleanup callback func
    112  */
    113 static UBool U_CALLCONV
    114 isoCodes_cleanup(void)
    115 {
    116     if (gIsoCodes != NULL) {
    117         uhash_close(gIsoCodes);
    118         gIsoCodes = NULL;
    119     }
    120     gIsoCodesInitialized = FALSE;
    121 
    122     return TRUE;
    123 }
    124 
    125 /**
    126  * Deleter for OlsonToMetaMappingEntry
    127  */
    128 static void U_CALLCONV
    129 deleteIsoCodeEntry(void *obj) {
    130     IsoCodeEntry *entry = (IsoCodeEntry*)obj;
    131     uprv_free(entry);
    132 }
    133 
    134 /**
    135  * Unfortunately, we have to convert the UChar* currency code to char*
    136  * to use it as a resource key.
    137  */
    138 static inline char*
    139 myUCharsToChars(char* resultOfLen4, const UChar* currency) {
    140     u_UCharsToChars(currency, resultOfLen4, ISO_CURRENCY_CODE_LENGTH);
    141     resultOfLen4[ISO_CURRENCY_CODE_LENGTH] = 0;
    142     return resultOfLen4;
    143 }
    144 
    145 /**
    146  * Internal function to look up currency data.  Result is an array of
    147  * two integers.  The first is the fraction digits.  The second is the
    148  * rounding increment, or 0 if none.  The rounding increment is in
    149  * units of 10^(-fraction_digits).
    150  */
    151 static const int32_t*
    152 _findMetaData(const UChar* currency, UErrorCode& ec) {
    153 
    154     if (currency == 0 || *currency == 0) {
    155         if (U_SUCCESS(ec)) {
    156             ec = U_ILLEGAL_ARGUMENT_ERROR;
    157         }
    158         return LAST_RESORT_DATA;
    159     }
    160 
    161     // Get CurrencyMeta resource out of root locale file.  [This may
    162     // move out of the root locale file later; if it does, update this
    163     // code.]
    164     UResourceBundle* currencyData = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &ec);
    165     UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
    166 
    167     if (U_FAILURE(ec)) {
    168         ures_close(currencyMeta);
    169         // Config/build error; return hard-coded defaults
    170         return LAST_RESORT_DATA;
    171     }
    172 
    173     // Look up our currency, or if that's not available, then DEFAULT
    174     char buf[ISO_CURRENCY_CODE_LENGTH+1];
    175     UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
    176     UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
    177       if (U_FAILURE(ec2)) {
    178         ures_close(rb);
    179         rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
    180         if (U_FAILURE(ec)) {
    181             ures_close(currencyMeta);
    182             ures_close(rb);
    183             // Config/build error; return hard-coded defaults
    184             return LAST_RESORT_DATA;
    185         }
    186     }
    187 
    188     int32_t len;
    189     const int32_t *data = ures_getIntVector(rb, &len, &ec);
    190     if (U_FAILURE(ec) || len != 2) {
    191         // Config/build error; return hard-coded defaults
    192         if (U_SUCCESS(ec)) {
    193             ec = U_INVALID_FORMAT_ERROR;
    194         }
    195         ures_close(currencyMeta);
    196         ures_close(rb);
    197         return LAST_RESORT_DATA;
    198     }
    199 
    200     ures_close(currencyMeta);
    201     ures_close(rb);
    202     return data;
    203 }
    204 
    205 // -------------------------------------
    206 
    207 /**
    208  * @see VARIANT_IS_EURO
    209  * @see VARIANT_IS_PREEURO
    210  */
    211 static uint32_t
    212 idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
    213 {
    214     uint32_t variantType = 0;
    215     // !!! this is internal only, assumes buffer is not null and capacity is sufficient
    216     // Extract the country name and variant name.  We only
    217     // recognize two variant names, EURO and PREEURO.
    218     char variant[ULOC_FULLNAME_CAPACITY];
    219     uloc_getCountry(locale, countryAndVariant, capacity, ec);
    220     uloc_getVariant(locale, variant, sizeof(variant), ec);
    221     if (variant[0] != 0) {
    222         variantType = (uint32_t)(0 == uprv_strcmp(variant, VAR_EURO))
    223                    | ((uint32_t)(0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
    224         if (variantType)
    225         {
    226             uprv_strcat(countryAndVariant, VAR_DELIM_STR);
    227             uprv_strcat(countryAndVariant, variant);
    228         }
    229     }
    230     return variantType;
    231 }
    232 
    233 // ------------------------------------------
    234 //
    235 // Registration
    236 //
    237 //-------------------------------------------
    238 
    239 // don't use ICUService since we don't need fallback
    240 
    241 U_CDECL_BEGIN
    242 static UBool U_CALLCONV currency_cleanup(void);
    243 U_CDECL_END
    244 
    245 #if !UCONFIG_NO_SERVICE
    246 struct CReg;
    247 
    248 static UMutex gCRegLock = U_MUTEX_INITIALIZER;
    249 static CReg* gCRegHead = 0;
    250 
    251 struct CReg : public icu::UMemory {
    252     CReg *next;
    253     UChar iso[ISO_CURRENCY_CODE_LENGTH+1];
    254     char  id[ULOC_FULLNAME_CAPACITY];
    255 
    256     CReg(const UChar* _iso, const char* _id)
    257         : next(0)
    258     {
    259         int32_t len = (int32_t)uprv_strlen(_id);
    260         if (len > (int32_t)(sizeof(id)-1)) {
    261             len = (sizeof(id)-1);
    262         }
    263         uprv_strncpy(id, _id, len);
    264         id[len] = 0;
    265         uprv_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH * sizeof(const UChar));
    266         iso[ISO_CURRENCY_CODE_LENGTH] = 0;
    267     }
    268 
    269     static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
    270     {
    271         if (status && U_SUCCESS(*status) && _iso && _id) {
    272             CReg* n = new CReg(_iso, _id);
    273             if (n) {
    274                 umtx_lock(&gCRegLock);
    275                 if (!gCRegHead) {
    276                     /* register for the first time */
    277                     ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
    278                 }
    279                 n->next = gCRegHead;
    280                 gCRegHead = n;
    281                 umtx_unlock(&gCRegLock);
    282                 return n;
    283             }
    284             *status = U_MEMORY_ALLOCATION_ERROR;
    285         }
    286         return 0;
    287     }
    288 
    289     static UBool unreg(UCurrRegistryKey key) {
    290         UBool found = FALSE;
    291         umtx_lock(&gCRegLock);
    292 
    293         CReg** p = &gCRegHead;
    294         while (*p) {
    295             if (*p == key) {
    296                 *p = ((CReg*)key)->next;
    297                 delete (CReg*)key;
    298                 found = TRUE;
    299                 break;
    300             }
    301             p = &((*p)->next);
    302         }
    303 
    304         umtx_unlock(&gCRegLock);
    305         return found;
    306     }
    307 
    308     static const UChar* get(const char* id) {
    309         const UChar* result = NULL;
    310         umtx_lock(&gCRegLock);
    311         CReg* p = gCRegHead;
    312 
    313         /* register cleanup of the mutex */
    314         ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
    315         while (p) {
    316             if (uprv_strcmp(id, p->id) == 0) {
    317                 result = p->iso;
    318                 break;
    319             }
    320             p = p->next;
    321         }
    322         umtx_unlock(&gCRegLock);
    323         return result;
    324     }
    325 
    326     /* This doesn't need to be thread safe. It's for u_cleanup only. */
    327     static void cleanup(void) {
    328         while (gCRegHead) {
    329             CReg* n = gCRegHead;
    330             gCRegHead = gCRegHead->next;
    331             delete n;
    332         }
    333     }
    334 };
    335 
    336 // -------------------------------------
    337 
    338 U_CAPI UCurrRegistryKey U_EXPORT2
    339 ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
    340 {
    341     if (status && U_SUCCESS(*status)) {
    342         char id[ULOC_FULLNAME_CAPACITY];
    343         idForLocale(locale, id, sizeof(id), status);
    344         return CReg::reg(isoCode, id, status);
    345     }
    346     return NULL;
    347 }
    348 
    349 // -------------------------------------
    350 
    351 U_CAPI UBool U_EXPORT2
    352 ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
    353 {
    354     if (status && U_SUCCESS(*status)) {
    355         return CReg::unreg(key);
    356     }
    357     return FALSE;
    358 }
    359 #endif /* UCONFIG_NO_SERVICE */
    360 
    361 // -------------------------------------
    362 
    363 /**
    364  * Release all static memory held by currency.
    365  */
    366 /*The declaration here is needed so currency_cleanup(void)
    367  * can call this function.
    368  */
    369 static UBool U_CALLCONV
    370 currency_cache_cleanup(void);
    371 
    372 U_CDECL_BEGIN
    373 static UBool U_CALLCONV currency_cleanup(void) {
    374 #if !UCONFIG_NO_SERVICE
    375     CReg::cleanup();
    376 #endif
    377     /*
    378      * There might be some cached currency data or isoCodes data.
    379      */
    380     currency_cache_cleanup();
    381     isoCodes_cleanup();
    382 
    383     return TRUE;
    384 }
    385 U_CDECL_END
    386 
    387 // -------------------------------------
    388 
    389 U_CAPI int32_t U_EXPORT2
    390 ucurr_forLocale(const char* locale,
    391                 UChar* buff,
    392                 int32_t buffCapacity,
    393                 UErrorCode* ec)
    394 {
    395     int32_t resLen = 0;
    396     const UChar* s = NULL;
    397     if (ec != NULL && U_SUCCESS(*ec)) {
    398         if ((buff && buffCapacity) || !buffCapacity) {
    399             UErrorCode localStatus = U_ZERO_ERROR;
    400             char id[ULOC_FULLNAME_CAPACITY];
    401             if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
    402                 // there is a currency keyword. Try to see if it's valid
    403                 if(buffCapacity > resLen) {
    404                     /* Normalize the currency keyword value to upper case. */
    405                     T_CString_toUpperCase(id);
    406                     u_charsToUChars(id, buff, resLen);
    407                 }
    408             } else {
    409                 // get country or country_variant in `id'
    410                 uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
    411 
    412                 if (U_FAILURE(*ec)) {
    413                     return 0;
    414                 }
    415 
    416 #if !UCONFIG_NO_SERVICE
    417                 const UChar* result = CReg::get(id);
    418                 if (result) {
    419                     if(buffCapacity > u_strlen(result)) {
    420                         u_strcpy(buff, result);
    421                     }
    422                     return u_strlen(result);
    423                 }
    424 #endif
    425                 // Remove variants, which is only needed for registration.
    426                 char *idDelim = strchr(id, VAR_DELIM);
    427                 if (idDelim) {
    428                     idDelim[0] = 0;
    429                 }
    430 
    431                 // Look up the CurrencyMap element in the root bundle.
    432                 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
    433                 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
    434                 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
    435                 UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
    436                 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
    437 
    438                 /*
    439                 Get the second item when PREEURO is requested, and this is a known Euro country.
    440                 If the requested variant is PREEURO, and this isn't a Euro country, assume
    441                 that the country changed over to the Euro in the future. This is probably
    442                 an old version of ICU that hasn't been updated yet. The latest currency is
    443                 probably correct.
    444                 */
    445                 if (U_SUCCESS(localStatus)) {
    446                     if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
    447                         currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
    448                         s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
    449                     }
    450                     else if ((variantType & VARIANT_IS_EURO)) {
    451                         s = EUR_STR;
    452                     }
    453                 }
    454                 ures_close(countryArray);
    455                 ures_close(currencyReq);
    456 
    457                 if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
    458                 {
    459                     // We don't know about it.  Check to see if we support the variant.
    460                     uloc_getParent(locale, id, sizeof(id), ec);
    461                     *ec = U_USING_FALLBACK_WARNING;
    462                     return ucurr_forLocale(id, buff, buffCapacity, ec);
    463                 }
    464                 else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
    465                     // There is nothing to fallback to. Report the failure/warning if possible.
    466                     *ec = localStatus;
    467                 }
    468                 if (U_SUCCESS(*ec)) {
    469                     if(buffCapacity > resLen) {
    470                         u_strcpy(buff, s);
    471                     }
    472                 }
    473             }
    474             return u_terminateUChars(buff, buffCapacity, resLen, ec);
    475         } else {
    476             *ec = U_ILLEGAL_ARGUMENT_ERROR;
    477         }
    478     }
    479     return resLen;
    480 }
    481 
    482 // end registration
    483 
    484 /**
    485  * Modify the given locale name by removing the rightmost _-delimited
    486  * element.  If there is none, empty the string ("" == root).
    487  * NOTE: The string "root" is not recognized; do not use it.
    488  * @return TRUE if the fallback happened; FALSE if locale is already
    489  * root ("").
    490  */
    491 static UBool fallback(char *loc) {
    492     if (!*loc) {
    493         return FALSE;
    494     }
    495     UErrorCode status = U_ZERO_ERROR;
    496     uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
    497  /*
    498     char *i = uprv_strrchr(loc, '_');
    499     if (i == NULL) {
    500         i = loc;
    501     }
    502     *i = 0;
    503  */
    504     return TRUE;
    505 }
    506 
    507 
    508 U_CAPI const UChar* U_EXPORT2
    509 ucurr_getName(const UChar* currency,
    510               const char* locale,
    511               UCurrNameStyle nameStyle,
    512               UBool* isChoiceFormat, // fillin
    513               int32_t* len, // fillin
    514               UErrorCode* ec) {
    515 
    516     // Look up the Currencies resource for the given locale.  The
    517     // Currencies locale data looks like this:
    518     //|en {
    519     //|  Currencies {
    520     //|    USD { "US$", "US Dollar" }
    521     //|    CHF { "Sw F", "Swiss Franc" }
    522     //|    INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
    523     //|    //...
    524     //|  }
    525     //|}
    526 
    527     if (U_FAILURE(*ec)) {
    528         return 0;
    529     }
    530 
    531     int32_t choice = (int32_t) nameStyle;
    532     if (choice < 0 || choice > 1) {
    533         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    534         return 0;
    535     }
    536 
    537     // In the future, resource bundles may implement multi-level
    538     // fallback.  That is, if a currency is not found in the en_US
    539     // Currencies data, then the en Currencies data will be searched.
    540     // Currently, if a Currencies datum exists in en_US and en, the
    541     // en_US entry hides that in en.
    542 
    543     // We want multi-level fallback for this resource, so we implement
    544     // it manually.
    545 
    546     // Use a separate UErrorCode here that does not propagate out of
    547     // this function.
    548     UErrorCode ec2 = U_ZERO_ERROR;
    549 
    550     char loc[ULOC_FULLNAME_CAPACITY];
    551     uloc_getName(locale, loc, sizeof(loc), &ec2);
    552     if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
    553         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    554         return 0;
    555     }
    556 
    557     char buf[ISO_CURRENCY_CODE_LENGTH+1];
    558     myUCharsToChars(buf, currency);
    559 
    560     /* Normalize the keyword value to uppercase */
    561     T_CString_toUpperCase(buf);
    562 
    563     const UChar* s = NULL;
    564     ec2 = U_ZERO_ERROR;
    565     UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
    566 
    567     rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
    568 
    569     // Fetch resource with multi-level resource inheritance fallback
    570     rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
    571 
    572     s = ures_getStringByIndex(rb, choice, len, &ec2);
    573     ures_close(rb);
    574 
    575     // If we've succeeded we're done.  Otherwise, try to fallback.
    576     // If that fails (because we are already at root) then exit.
    577     if (U_SUCCESS(ec2)) {
    578         if (ec2 == U_USING_DEFAULT_WARNING
    579             || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
    580             *ec = ec2;
    581         }
    582     }
    583 
    584     // Determine if this is a ChoiceFormat pattern.  One leading mark
    585     // indicates a ChoiceFormat.  Two indicates a static string that
    586     // starts with a mark.  In either case, the first mark is ignored,
    587     // if present.  Marks in the rest of the string have no special
    588     // meaning.
    589     *isChoiceFormat = FALSE;
    590     if (U_SUCCESS(ec2)) {
    591         U_ASSERT(s != NULL);
    592         int32_t i=0;
    593         while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
    594             ++i;
    595         }
    596         *isChoiceFormat = (i == 1);
    597         if (i != 0) ++s; // Skip over first mark
    598         return s;
    599     }
    600 
    601     // If we fail to find a match, use the ISO 4217 code
    602     *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
    603     *ec = U_USING_DEFAULT_WARNING;
    604     return currency;
    605 }
    606 
    607 U_CAPI const UChar* U_EXPORT2
    608 ucurr_getPluralName(const UChar* currency,
    609                     const char* locale,
    610                     UBool* isChoiceFormat,
    611                     const char* pluralCount,
    612                     int32_t* len, // fillin
    613                     UErrorCode* ec) {
    614     // Look up the Currencies resource for the given locale.  The
    615     // Currencies locale data looks like this:
    616     //|en {
    617     //|  CurrencyPlurals {
    618     //|    USD{
    619     //|      one{"US dollar"}
    620     //|      other{"US dollars"}
    621     //|    }
    622     //|  }
    623     //|}
    624 
    625     if (U_FAILURE(*ec)) {
    626         return 0;
    627     }
    628 
    629     // Use a separate UErrorCode here that does not propagate out of
    630     // this function.
    631     UErrorCode ec2 = U_ZERO_ERROR;
    632 
    633     char loc[ULOC_FULLNAME_CAPACITY];
    634     uloc_getName(locale, loc, sizeof(loc), &ec2);
    635     if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
    636         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    637         return 0;
    638     }
    639 
    640     char buf[ISO_CURRENCY_CODE_LENGTH+1];
    641     myUCharsToChars(buf, currency);
    642 
    643     const UChar* s = NULL;
    644     ec2 = U_ZERO_ERROR;
    645     UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
    646 
    647     rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
    648 
    649     // Fetch resource with multi-level resource inheritance fallback
    650     rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
    651 
    652     s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
    653     if (U_FAILURE(ec2)) {
    654         //  fall back to "other"
    655         ec2 = U_ZERO_ERROR;
    656         s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);
    657         if (U_FAILURE(ec2)) {
    658             ures_close(rb);
    659             // fall back to long name in Currencies
    660             return ucurr_getName(currency, locale, UCURR_LONG_NAME,
    661                                  isChoiceFormat, len, ec);
    662         }
    663     }
    664     ures_close(rb);
    665 
    666     // If we've succeeded we're done.  Otherwise, try to fallback.
    667     // If that fails (because we are already at root) then exit.
    668     if (U_SUCCESS(ec2)) {
    669         if (ec2 == U_USING_DEFAULT_WARNING
    670             || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
    671             *ec = ec2;
    672         }
    673         U_ASSERT(s != NULL);
    674         return s;
    675     }
    676 
    677     // If we fail to find a match, use the ISO 4217 code
    678     *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
    679     *ec = U_USING_DEFAULT_WARNING;
    680     return currency;
    681 }
    682 
    683 
    684 //========================================================================
    685 // Following are structure and function for parsing currency names
    686 
    687 #define NEED_TO_BE_DELETED 0x1
    688 
    689 // TODO: a better way to define this?
    690 #define MAX_CURRENCY_NAME_LEN 100
    691 
    692 typedef struct {
    693     const char* IsoCode;  // key
    694     UChar* currencyName;  // value
    695     int32_t currencyNameLen;  // value length
    696     int32_t flag;  // flags
    697 } CurrencyNameStruct;
    698 
    699 
    700 #ifndef MIN
    701 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
    702 #endif
    703 
    704 #ifndef MAX
    705 #define MAX(a,b) (((a)<(b)) ? (b) : (a))
    706 #endif
    707 
    708 
    709 // Comparason function used in quick sort.
    710 static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
    711     const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
    712     const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
    713     for (int32_t i = 0;
    714          i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen);
    715          ++i) {
    716         if (currName_1->currencyName[i] < currName_2->currencyName[i]) {
    717             return -1;
    718         }
    719         if (currName_1->currencyName[i] > currName_2->currencyName[i]) {
    720             return 1;
    721         }
    722     }
    723     if (currName_1->currencyNameLen < currName_2->currencyNameLen) {
    724         return -1;
    725     } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) {
    726         return 1;
    727     }
    728     return 0;
    729 }
    730 
    731 
    732 // Give a locale, return the maximum number of currency names associated with
    733 // this locale.
    734 // It gets currency names from resource bundles using fallback.
    735 // It is the maximum number because in the fallback chain, some of the
    736 // currency names are duplicated.
    737 // For example, given locale as "en_US", the currency names get from resource
    738 // bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
    739 // all currency names in "en_US" and "en".
    740 static void
    741 getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) {
    742     U_NAMESPACE_USE
    743     *total_currency_name_count = 0;
    744     *total_currency_symbol_count = 0;
    745     const UChar* s = NULL;
    746     char locale[ULOC_FULLNAME_CAPACITY];
    747     uprv_strcpy(locale, loc);
    748     for (;;) {
    749         UErrorCode ec2 = U_ZERO_ERROR;
    750         // TODO: ures_openDirect?
    751         UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2);
    752         UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
    753         int32_t n = ures_getSize(curr);
    754         for (int32_t i=0; i<n; ++i) {
    755             UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
    756             int32_t len;
    757             s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
    758             UBool isChoice = FALSE;
    759             if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
    760                 ++s;
    761                 --len;
    762                 if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
    763                     isChoice = TRUE;
    764                 }
    765             }
    766             if (isChoice) {
    767                 ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2);
    768                 int32_t fmt_count;
    769                 fmt.getFormats(fmt_count);
    770                 *total_currency_symbol_count += fmt_count;
    771             } else {
    772                 ++(*total_currency_symbol_count);  // currency symbol
    773             }
    774 
    775             ++(*total_currency_symbol_count); // iso code
    776             ++(*total_currency_name_count); // long name
    777             ures_close(names);
    778         }
    779 
    780         // currency plurals
    781         UErrorCode ec3 = U_ZERO_ERROR;
    782         UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
    783         n = ures_getSize(curr_p);
    784         for (int32_t i=0; i<n; ++i) {
    785             UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
    786             *total_currency_name_count += ures_getSize(names);
    787             ures_close(names);
    788         }
    789         ures_close(curr_p);
    790         ures_close(curr);
    791         ures_close(rb);
    792 
    793         if (!fallback(locale)) {
    794             break;
    795         }
    796     }
    797 }
    798 
    799 static UChar*
    800 toUpperCase(const UChar* source, int32_t len, const char* locale) {
    801     UChar* dest = NULL;
    802     UErrorCode ec = U_ZERO_ERROR;
    803     int32_t destLen = u_strToUpper(dest, 0, source, len, locale, &ec);
    804 
    805     ec = U_ZERO_ERROR;
    806     dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
    807     u_strToUpper(dest, destLen, source, len, locale, &ec);
    808     if (U_FAILURE(ec)) {
    809         uprv_memcpy(dest, source, sizeof(UChar) * len);
    810     }
    811     return dest;
    812 }
    813 
    814 
    815 // Collect all available currency names associated with the given locale
    816 // (enable fallback chain).
    817 // Read currenc names defined in resource bundle "Currencies" and
    818 // "CurrencyPlural", enable fallback chain.
    819 // return the malloc-ed currency name arrays and the total number of currency
    820 // names in the array.
    821 static void
    822 collectCurrencyNames(const char* locale,
    823                      CurrencyNameStruct** currencyNames,
    824                      int32_t* total_currency_name_count,
    825                      CurrencyNameStruct** currencySymbols,
    826                      int32_t* total_currency_symbol_count,
    827                      UErrorCode& ec) {
    828     U_NAMESPACE_USE
    829     // Look up the Currencies resource for the given locale.
    830     UErrorCode ec2 = U_ZERO_ERROR;
    831 
    832     char loc[ULOC_FULLNAME_CAPACITY];
    833     uloc_getName(locale, loc, sizeof(loc), &ec2);
    834     if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
    835         ec = U_ILLEGAL_ARGUMENT_ERROR;
    836     }
    837 
    838     // Get maximum currency name count first.
    839     getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
    840 
    841     *currencyNames = (CurrencyNameStruct*)uprv_malloc
    842         (sizeof(CurrencyNameStruct) * (*total_currency_name_count));
    843     *currencySymbols = (CurrencyNameStruct*)uprv_malloc
    844         (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
    845 
    846     const UChar* s = NULL;  // currency name
    847     char* iso = NULL;  // currency ISO code
    848 
    849     *total_currency_name_count = 0;
    850     *total_currency_symbol_count = 0;
    851 
    852     UErrorCode ec3 = U_ZERO_ERROR;
    853     UErrorCode ec4 = U_ZERO_ERROR;
    854 
    855     // Using hash to remove duplicates caused by locale fallback
    856     UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3);
    857     UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4);
    858     for (int32_t localeLevel = 0; ; ++localeLevel) {
    859         ec2 = U_ZERO_ERROR;
    860         // TODO: ures_openDirect
    861         UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
    862         UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
    863         int32_t n = ures_getSize(curr);
    864         for (int32_t i=0; i<n; ++i) {
    865             UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
    866             int32_t len;
    867             s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
    868             // TODO: uhash_put wont change key/value?
    869             iso = (char*)ures_getKey(names);
    870             if (localeLevel == 0) {
    871                 uhash_put(currencyIsoCodes, iso, iso, &ec3);
    872             } else {
    873                 if (uhash_get(currencyIsoCodes, iso) != NULL) {
    874                     ures_close(names);
    875                     continue;
    876                 } else {
    877                     uhash_put(currencyIsoCodes, iso, iso, &ec3);
    878                 }
    879             }
    880             UBool isChoice = FALSE;
    881             if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
    882                 ++s;
    883                 --len;
    884                 if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
    885                     isChoice = TRUE;
    886                 }
    887             }
    888             if (isChoice) {
    889                 ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2);
    890                 int32_t fmt_count;
    891                 const UnicodeString* formats = fmt.getFormats(fmt_count);
    892                 for (int i = 0; i < fmt_count; ++i) {
    893                     // put iso, formats[i]; into array
    894                     int32_t length = formats[i].length();
    895                     UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length);
    896                     formats[i].extract(0, length, name);
    897                     (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
    898                     (*currencySymbols)[*total_currency_symbol_count].currencyName = name;
    899                     (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
    900                     (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length;
    901                 }
    902             } else {
    903                 // Add currency symbol.
    904                 (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
    905                 (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
    906                 (*currencySymbols)[*total_currency_symbol_count].flag = 0;
    907                 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
    908             }
    909 
    910             // Add currency long name.
    911             s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
    912             (*currencyNames)[*total_currency_name_count].IsoCode = iso;
    913             UChar* upperName = toUpperCase(s, len, locale);
    914             (*currencyNames)[*total_currency_name_count].currencyName = upperName;
    915             (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
    916             (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
    917 
    918             // put (iso, 3, and iso) in to array
    919             // Add currency ISO code.
    920             (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
    921             (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
    922             // Must convert iso[] into Unicode
    923             u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
    924             (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
    925             (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
    926 
    927             ures_close(names);
    928         }
    929 
    930         // currency plurals
    931         UErrorCode ec3 = U_ZERO_ERROR;
    932         UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
    933         n = ures_getSize(curr_p);
    934         for (int32_t i=0; i<n; ++i) {
    935             UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
    936             iso = (char*)ures_getKey(names);
    937             // Using hash to remove duplicated ISO codes in fallback chain.
    938             if (localeLevel == 0) {
    939                 uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
    940             } else {
    941                 if (uhash_get(currencyPluralIsoCodes, iso) != NULL) {
    942                     ures_close(names);
    943                     continue;
    944                 } else {
    945                     uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
    946                 }
    947             }
    948             int32_t num = ures_getSize(names);
    949             int32_t len;
    950             for (int32_t j = 0; j < num; ++j) {
    951                 // TODO: remove duplicates between singular name and
    952                 // currency long name?
    953                 s = ures_getStringByIndex(names, j, &len, &ec3);
    954                 (*currencyNames)[*total_currency_name_count].IsoCode = iso;
    955                 UChar* upperName = toUpperCase(s, len, locale);
    956                 (*currencyNames)[*total_currency_name_count].currencyName = upperName;
    957                 (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
    958                 (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
    959             }
    960             ures_close(names);
    961         }
    962         ures_close(curr_p);
    963         ures_close(curr);
    964         ures_close(rb);
    965 
    966         if (!fallback(loc)) {
    967             break;
    968         }
    969     }
    970 
    971     uhash_close(currencyIsoCodes);
    972     uhash_close(currencyPluralIsoCodes);
    973 
    974     // quick sort the struct
    975     qsort(*currencyNames, *total_currency_name_count,
    976           sizeof(CurrencyNameStruct), currencyNameComparator);
    977     qsort(*currencySymbols, *total_currency_symbol_count,
    978           sizeof(CurrencyNameStruct), currencyNameComparator);
    979 
    980 #ifdef UCURR_DEBUG
    981     printf("currency name count: %d\n", *total_currency_name_count);
    982     for (int32_t index = 0; index < *total_currency_name_count; ++index) {
    983         printf("index: %d\n", index);
    984         printf("iso: %s\n", (*currencyNames)[index].IsoCode);
    985         printf("currencyName:");
    986         for (int32_t i = 0; i < (*currencyNames)[index].currencyNameLen; ++i) {
    987             printf("%c", (unsigned char)(*currencyNames)[index].currencyName[i]);
    988         }
    989         printf("\n");
    990         printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
    991     }
    992     printf("currency symbol count: %d\n", *total_currency_symbol_count);
    993     for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
    994         printf("index: %d\n", index);
    995         printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
    996         printf("currencySymbol:");
    997         for (int32_t i = 0; i < (*currencySymbols)[index].currencyNameLen; ++i) {
    998             printf("%c", (unsigned char)(*currencySymbols)[index].currencyName[i]);
    999         }
   1000         printf("\n");
   1001         printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
   1002     }
   1003 #endif
   1004 }
   1005 
   1006 // @param  currencyNames: currency names array
   1007 // @param  indexInCurrencyNames: the index of the character in currency names
   1008 //         array against which the comparison is done
   1009 // @param  key: input text char to compare against
   1010 // @param  begin(IN/OUT): the begin index of matching range in currency names array
   1011 // @param  end(IN/OUT): the end index of matching range in currency names array.
   1012 static int32_t
   1013 binarySearch(const CurrencyNameStruct* currencyNames,
   1014              int32_t indexInCurrencyNames,
   1015              const UChar key,
   1016              int32_t* begin, int32_t* end) {
   1017 #ifdef UCURR_DEBUG
   1018     printf("key = %x\n", key);
   1019 #endif
   1020    int32_t first = *begin;
   1021    int32_t last = *end;
   1022    while (first <= last) {
   1023        int32_t mid = (first + last) / 2;  // compute mid point.
   1024        if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) {
   1025            first = mid + 1;
   1026        } else {
   1027            if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) {
   1028                first = mid + 1;
   1029            }
   1030            else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) {
   1031                last = mid - 1;
   1032            }
   1033            else {
   1034                 // Find a match, and looking for ranges
   1035                 // Now do two more binary searches. First, on the left side for
   1036                 // the greatest L such that CurrencyNameStruct[L] < key.
   1037                 int32_t L = *begin;
   1038                 int32_t R = mid;
   1039 
   1040 #ifdef UCURR_DEBUG
   1041                 printf("mid = %d\n", mid);
   1042 #endif
   1043                 while (L < R) {
   1044                     int32_t M = (L + R) / 2;
   1045 #ifdef UCURR_DEBUG
   1046                     printf("L = %d, R = %d, M = %d\n", L, R, M);
   1047 #endif
   1048                     if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) {
   1049                         L = M + 1;
   1050                     } else {
   1051                         if (currencyNames[M].currencyName[indexInCurrencyNames] < key) {
   1052                             L = M + 1;
   1053                         } else {
   1054 #ifdef UCURR_DEBUG
   1055                             U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
   1056 #endif
   1057                             R = M;
   1058                         }
   1059                     }
   1060                 }
   1061 #ifdef UCURR_DEBUG
   1062                 U_ASSERT(L == R);
   1063 #endif
   1064                 *begin = L;
   1065 #ifdef UCURR_DEBUG
   1066                 printf("begin = %d\n", *begin);
   1067                 U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key);
   1068 #endif
   1069 
   1070                 // Now for the second search, finding the least R such that
   1071                 // key < CurrencyNameStruct[R].
   1072                 L = mid;
   1073                 R = *end;
   1074                 while (L < R) {
   1075                     int32_t M = (L + R) / 2;
   1076 #ifdef UCURR_DEBUG
   1077                     printf("L = %d, R = %d, M = %d\n", L, R, M);
   1078 #endif
   1079                     if (currencyNames[M].currencyNameLen < indexInCurrencyNames) {
   1080                         L = M + 1;
   1081                     } else {
   1082                         if (currencyNames[M].currencyName[indexInCurrencyNames] > key) {
   1083                             R = M;
   1084                         } else {
   1085 #ifdef UCURR_DEBUG
   1086                             U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
   1087 #endif
   1088                             L = M + 1;
   1089                         }
   1090                     }
   1091                 }
   1092 #ifdef UCURR_DEBUG
   1093                 U_ASSERT(L == R);
   1094 #endif
   1095                 if (currencyNames[R].currencyName[indexInCurrencyNames] > key) {
   1096                     *end = R - 1;
   1097                 } else {
   1098                     *end = R;
   1099                 }
   1100 #ifdef UCURR_DEBUG
   1101                 printf("end = %d\n", *end);
   1102 #endif
   1103 
   1104                 // now, found the range. check whether there is exact match
   1105                 if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) {
   1106                     return *begin;  // find range and exact match.
   1107                 }
   1108                 return -1;  // find range, but no exact match.
   1109            }
   1110        }
   1111    }
   1112    *begin = -1;
   1113    *end = -1;
   1114    return -1;    // failed to find range.
   1115 }
   1116 
   1117 
   1118 // Linear search "text" in "currencyNames".
   1119 // @param  begin, end: the begin and end index in currencyNames, within which
   1120 //         range should the search be performed.
   1121 // @param  textLen: the length of the text to be compared
   1122 // @param  maxMatchLen(IN/OUT): passing in the computed max matching length
   1123 //                              pass out the new max  matching length
   1124 // @param  maxMatchIndex: the index in currencyName which has the longest
   1125 //                        match with input text.
   1126 static void
   1127 linearSearch(const CurrencyNameStruct* currencyNames,
   1128              int32_t begin, int32_t end,
   1129              const UChar* text, int32_t textLen,
   1130              int32_t *maxMatchLen, int32_t* maxMatchIndex) {
   1131     for (int32_t index = begin; index <= end; ++index) {
   1132         int32_t len = currencyNames[index].currencyNameLen;
   1133         if (len > *maxMatchLen && len <= textLen &&
   1134             uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
   1135             *maxMatchIndex = index;
   1136             *maxMatchLen = len;
   1137 #ifdef UCURR_DEBUG
   1138             printf("maxMatchIndex = %d, maxMatchLen = %d\n",
   1139                    *maxMatchIndex, *maxMatchLen);
   1140 #endif
   1141         }
   1142     }
   1143 }
   1144 
   1145 #define LINEAR_SEARCH_THRESHOLD 10
   1146 
   1147 // Find longest match between "text" and currency names in "currencyNames".
   1148 // @param  total_currency_count: total number of currency names in CurrencyNames.
   1149 // @param  textLen: the length of the text to be compared
   1150 // @param  maxMatchLen: passing in the computed max matching length
   1151 //                              pass out the new max  matching length
   1152 // @param  maxMatchIndex: the index in currencyName which has the longest
   1153 //                        match with input text.
   1154 static void
   1155 searchCurrencyName(const CurrencyNameStruct* currencyNames,
   1156                    int32_t total_currency_count,
   1157                    const UChar* text, int32_t textLen,
   1158                    int32_t* maxMatchLen, int32_t* maxMatchIndex) {
   1159     *maxMatchIndex = -1;
   1160     *maxMatchLen = 0;
   1161     int32_t matchIndex = -1;
   1162     int32_t binarySearchBegin = 0;
   1163     int32_t binarySearchEnd = total_currency_count - 1;
   1164     // It is a variant of binary search.
   1165     // For example, given the currency names in currencyNames array are:
   1166     // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
   1167     // and the input text is BBEXST
   1168     // The first round binary search search "B" in the text against
   1169     // the first char in currency names, and find the first char matching range
   1170     // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
   1171     // The 2nd round binary search search the second "B" in the text against
   1172     // the 2nd char in currency names, and narrow the matching range to
   1173     // "BB BBEX BBEXYZ" (and the maximum matching "BB").
   1174     // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
   1175     // maximum matching).
   1176     // The 4th round returns the same range (the maximum matching is "BBEX").
   1177     // The 5th round returns no matching range.
   1178     for (int32_t index = 0; index < textLen; ++index) {
   1179         // matchIndex saves the one with exact match till the current point.
   1180         // [binarySearchBegin, binarySearchEnd] saves the matching range.
   1181         matchIndex = binarySearch(currencyNames, index,
   1182                                   text[index],
   1183                                   &binarySearchBegin, &binarySearchEnd);
   1184         if (binarySearchBegin == -1) { // did not find the range
   1185             break;
   1186         }
   1187         if (matchIndex != -1) {
   1188             // find an exact match for text from text[0] to text[index]
   1189             // in currencyNames array.
   1190             *maxMatchLen = index + 1;
   1191             *maxMatchIndex = matchIndex;
   1192         }
   1193         if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
   1194             // linear search if within threshold.
   1195             linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
   1196                          text, textLen,
   1197                          maxMatchLen, maxMatchIndex);
   1198             break;
   1199         }
   1200     }
   1201     return;
   1202 }
   1203 
   1204 //========================= currency name cache =====================
   1205 typedef struct {
   1206     char locale[ULOC_FULLNAME_CAPACITY];  //key
   1207     // currency names, case insensitive
   1208     CurrencyNameStruct* currencyNames;  // value
   1209     int32_t totalCurrencyNameCount;  // currency name count
   1210     // currency symbols and ISO code, case sensitive
   1211     CurrencyNameStruct* currencySymbols; // value
   1212     int32_t totalCurrencySymbolCount;  // count
   1213     // reference count.
   1214     // reference count is set to 1 when an entry is put to cache.
   1215     // it increases by 1 before accessing, and decreased by 1 after accessing.
   1216     // The entry is deleted when ref count is zero, which means
   1217     // the entry is replaced out of cache and no process is accessing it.
   1218     int32_t refCount;
   1219 } CurrencyNameCacheEntry;
   1220 
   1221 
   1222 #define CURRENCY_NAME_CACHE_NUM 10
   1223 
   1224 // Reserve 10 cache entries.
   1225 static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
   1226 // Using an index to indicate which entry to be replaced when cache is full.
   1227 // It is a simple round-robin replacement strategy.
   1228 static int8_t currentCacheEntryIndex = 0;
   1229 
   1230 // Cache deletion
   1231 static void
   1232 deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
   1233     for (int32_t index = 0; index < count; ++index) {
   1234         if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) {
   1235             uprv_free(currencyNames[index].currencyName);
   1236         }
   1237     }
   1238     uprv_free(currencyNames);
   1239 }
   1240 
   1241 
   1242 static void
   1243 deleteCacheEntry(CurrencyNameCacheEntry* entry) {
   1244     deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
   1245     deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
   1246     uprv_free(entry);
   1247 }
   1248 
   1249 
   1250 // Cache clean up
   1251 static UBool U_CALLCONV
   1252 currency_cache_cleanup(void) {
   1253     for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
   1254         if (currCache[i]) {
   1255             deleteCacheEntry(currCache[i]);
   1256             currCache[i] = 0;
   1257         }
   1258     }
   1259     return TRUE;
   1260 }
   1261 
   1262 
   1263 U_CFUNC void
   1264 uprv_parseCurrency(const char* locale,
   1265                    const icu::UnicodeString& text,
   1266                    icu::ParsePosition& pos,
   1267                    int8_t type,
   1268                    UChar* result,
   1269                    UErrorCode& ec)
   1270 {
   1271     U_NAMESPACE_USE
   1272 
   1273     if (U_FAILURE(ec)) {
   1274         return;
   1275     }
   1276 
   1277     int32_t total_currency_name_count = 0;
   1278     CurrencyNameStruct* currencyNames = NULL;
   1279     int32_t total_currency_symbol_count = 0;
   1280     CurrencyNameStruct* currencySymbols = NULL;
   1281     CurrencyNameCacheEntry* cacheEntry = NULL;
   1282 
   1283     umtx_lock(NULL);
   1284     // in order to handle racing correctly,
   1285     // not putting 'search' in a separate function and using UMTX.
   1286     int8_t  found = -1;
   1287     for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
   1288         if (currCache[i]!= NULL &&
   1289             uprv_strcmp(locale, currCache[i]->locale) == 0) {
   1290             found = i;
   1291             break;
   1292         }
   1293     }
   1294     if (found != -1) {
   1295         cacheEntry = currCache[found];
   1296         currencyNames = cacheEntry->currencyNames;
   1297         total_currency_name_count = cacheEntry->totalCurrencyNameCount;
   1298         currencySymbols = cacheEntry->currencySymbols;
   1299         total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
   1300         ++(cacheEntry->refCount);
   1301     }
   1302     umtx_unlock(NULL);
   1303     if (found == -1) {
   1304         collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
   1305         if (U_FAILURE(ec)) {
   1306             return;
   1307         }
   1308         umtx_lock(NULL);
   1309         // check again.
   1310         int8_t  found = -1;
   1311         for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
   1312             if (currCache[i]!= NULL &&
   1313                 uprv_strcmp(locale, currCache[i]->locale) == 0) {
   1314                 found = i;
   1315                 break;
   1316             }
   1317         }
   1318         if (found == -1) {
   1319             // insert new entry to
   1320             // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
   1321             // and remove the existing entry
   1322             // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
   1323             // from cache.
   1324             cacheEntry = currCache[currentCacheEntryIndex];
   1325             if (cacheEntry) {
   1326                 --(cacheEntry->refCount);
   1327                 // delete if the ref count is zero
   1328                 if (cacheEntry->refCount == 0) {
   1329                     deleteCacheEntry(cacheEntry);
   1330                 }
   1331             }
   1332             cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry));
   1333             currCache[currentCacheEntryIndex] = cacheEntry;
   1334             uprv_strcpy(cacheEntry->locale, locale);
   1335             cacheEntry->currencyNames = currencyNames;
   1336             cacheEntry->totalCurrencyNameCount = total_currency_name_count;
   1337             cacheEntry->currencySymbols = currencySymbols;
   1338             cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
   1339             cacheEntry->refCount = 2; // one for cache, one for reference
   1340             currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
   1341             ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup);
   1342 
   1343         } else {
   1344             deleteCurrencyNames(currencyNames, total_currency_name_count);
   1345             deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
   1346             cacheEntry = currCache[found];
   1347             currencyNames = cacheEntry->currencyNames;
   1348             total_currency_name_count = cacheEntry->totalCurrencyNameCount;
   1349             currencySymbols = cacheEntry->currencySymbols;
   1350             total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
   1351             ++(cacheEntry->refCount);
   1352         }
   1353         umtx_unlock(NULL);
   1354     }
   1355 
   1356     int32_t start = pos.getIndex();
   1357 
   1358     UChar inputText[MAX_CURRENCY_NAME_LEN];
   1359     UChar upperText[MAX_CURRENCY_NAME_LEN];
   1360     int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
   1361     text.extract(start, textLen, inputText);
   1362     UErrorCode ec1 = U_ZERO_ERROR;
   1363     textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, locale, &ec1);
   1364 
   1365     int32_t max = 0;
   1366     int32_t matchIndex = -1;
   1367     // case in-sensitive comparision against currency names
   1368     searchCurrencyName(currencyNames, total_currency_name_count,
   1369                        upperText, textLen, &max, &matchIndex);
   1370 
   1371 #ifdef UCURR_DEBUG
   1372     printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
   1373 #endif
   1374 
   1375     int32_t maxInSymbol = 0;
   1376     int32_t matchIndexInSymbol = -1;
   1377     if (type != UCURR_LONG_NAME) {  // not name only
   1378         // case sensitive comparison against currency symbols and ISO code.
   1379         searchCurrencyName(currencySymbols, total_currency_symbol_count,
   1380                            inputText, textLen,
   1381                            &maxInSymbol, &matchIndexInSymbol);
   1382     }
   1383 
   1384 #ifdef UCURR_DEBUG
   1385     printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
   1386 #endif
   1387 
   1388     if (max >= maxInSymbol && matchIndex != -1) {
   1389         u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
   1390         pos.setIndex(start + max);
   1391     } else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
   1392         u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
   1393         pos.setIndex(start + maxInSymbol);
   1394     }
   1395 
   1396     // decrease reference count
   1397     umtx_lock(NULL);
   1398     --(cacheEntry->refCount);
   1399     if (cacheEntry->refCount == 0) {  // remove
   1400         deleteCacheEntry(cacheEntry);
   1401     }
   1402     umtx_unlock(NULL);
   1403 }
   1404 
   1405 
   1406 /**
   1407  * Internal method.  Given a currency ISO code and a locale, return
   1408  * the "static" currency name.  This is usually the same as the
   1409  * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
   1410  * format is applied to the number 2.0 (to yield the more common
   1411  * plural) to return a static name.
   1412  *
   1413  * This is used for backward compatibility with old currency logic in
   1414  * DecimalFormat and DecimalFormatSymbols.
   1415  */
   1416 U_CFUNC void
   1417 uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
   1418                            icu::UnicodeString& result, UErrorCode& ec)
   1419 {
   1420     U_NAMESPACE_USE
   1421 
   1422     UBool isChoiceFormat;
   1423     int32_t len;
   1424     const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
   1425                                           &isChoiceFormat, &len, &ec);
   1426     if (U_SUCCESS(ec)) {
   1427         // If this is a ChoiceFormat currency, then format an
   1428         // arbitrary value; pick something != 1; more common.
   1429         result.truncate(0);
   1430         if (isChoiceFormat) {
   1431             ChoiceFormat f(UnicodeString(TRUE, currname, len), ec);
   1432             if (U_SUCCESS(ec)) {
   1433                 f.format(2.0, result);
   1434             } else {
   1435                 result.setTo(iso, -1);
   1436             }
   1437         } else {
   1438             result.setTo(currname, -1);
   1439         }
   1440     }
   1441 }
   1442 
   1443 U_CAPI int32_t U_EXPORT2
   1444 ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
   1445     return (_findMetaData(currency, *ec))[0];
   1446 }
   1447 
   1448 U_CAPI double U_EXPORT2
   1449 ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
   1450     const int32_t *data = _findMetaData(currency, *ec);
   1451 
   1452     // If the meta data is invalid, return 0.0.
   1453     if (data[0] < 0 || data[0] > MAX_POW10) {
   1454         if (U_SUCCESS(*ec)) {
   1455             *ec = U_INVALID_FORMAT_ERROR;
   1456         }
   1457         return 0.0;
   1458     }
   1459 
   1460     // If there is no rounding, return 0.0 to indicate no rounding.  A
   1461     // rounding value (data[1]) of 0 or 1 indicates no rounding.
   1462     if (data[1] < 2) {
   1463         return 0.0;
   1464     }
   1465 
   1466     // Return data[1] / 10^(data[0]).  The only actual rounding data,
   1467     // as of this writing, is CHF { 2, 5 }.
   1468     return double(data[1]) / POW10[data[0]];
   1469 }
   1470 
   1471 U_CDECL_BEGIN
   1472 
   1473 typedef struct UCurrencyContext {
   1474     uint32_t currType; /* UCurrCurrencyType */
   1475     uint32_t listIdx;
   1476 } UCurrencyContext;
   1477 
   1478 /*
   1479 Please keep this list in alphabetical order.
   1480 You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
   1481 of these items.
   1482 ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
   1483 */
   1484 static const struct CurrencyList {
   1485     const char *currency;
   1486     uint32_t currType;
   1487 } gCurrencyList[] = {
   1488     {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
   1489     {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1490     {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
   1491     {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1492     {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
   1493     {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1494     {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1495     {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1496     {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1497     {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
   1498     {"AON", UCURR_COMMON|UCURR_DEPRECATED},
   1499     {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
   1500     {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
   1501     {"ARL", UCURR_COMMON|UCURR_DEPRECATED},
   1502     {"ARM", UCURR_COMMON|UCURR_DEPRECATED},
   1503     {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
   1504     {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1505     {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
   1506     {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1507     {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1508     {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
   1509     {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1510     {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
   1511     {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1512     {"BAN", UCURR_COMMON|UCURR_DEPRECATED},
   1513     {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1514     {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1515     {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1516     {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
   1517     {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1518     {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
   1519     {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
   1520     {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1521     {"BGO", UCURR_COMMON|UCURR_DEPRECATED},
   1522     {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1523     {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1524     {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1525     {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1526     {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1527     {"BOL", UCURR_COMMON|UCURR_DEPRECATED},
   1528     {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
   1529     {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1530     {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
   1531     {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
   1532     {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
   1533     {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1534     {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
   1535     {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
   1536     {"BRZ", UCURR_COMMON|UCURR_DEPRECATED},
   1537     {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1538     {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1539     {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
   1540     {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1541     {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
   1542     {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1543     {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1544     {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1545     {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1546     {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1547     {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1548     {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1549     {"CLE", UCURR_COMMON|UCURR_DEPRECATED},
   1550     {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1551     {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1552     {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1553     {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1554     {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1555     {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1556     {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1557     {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
   1558     {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
   1559     {"CUC", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1560     {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1561     {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1562     {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
   1563     {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1564     {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
   1565     {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
   1566     {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1567     {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1568     {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1569     {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1570     {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
   1571     {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1572     {"EEK", UCURR_COMMON|UCURR_DEPRECATED},
   1573     {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1574     {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
   1575     {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1576     {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1577     {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1578     {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
   1579     {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1580     {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1581     {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
   1582     {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1583     {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1584     {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
   1585     {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1586     {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
   1587     {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1588     {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
   1589     {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1590     {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1591     {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1592     {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1593     {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
   1594     {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
   1595     {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
   1596     {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1597     {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
   1598     {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1599     {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1600     {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1601     {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1602     {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
   1603     {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1604     {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1605     {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1606     {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1607     {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
   1608     {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
   1609     {"ILR", UCURR_COMMON|UCURR_DEPRECATED},
   1610     {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1611     {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1612     {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1613     {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1614     {"ISJ", UCURR_COMMON|UCURR_DEPRECATED},
   1615     {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1616     {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
   1617     {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1618     {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1619     {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1620     {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1621     {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1622     {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1623     {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1624     {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1625     {"KRH", UCURR_COMMON|UCURR_DEPRECATED},
   1626     {"KRO", UCURR_COMMON|UCURR_DEPRECATED},
   1627     {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1628     {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1629     {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1630     {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1631     {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1632     {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1633     {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1634     {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1635     {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1636     {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
   1637     {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1638     {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
   1639     {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1640     {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
   1641     {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1642     {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1643     {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
   1644     {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1645     {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1646     {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
   1647     {"MCF", UCURR_COMMON|UCURR_DEPRECATED},
   1648     {"MDC", UCURR_COMMON|UCURR_DEPRECATED},
   1649     {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1650     {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1651     {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
   1652     {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1653     {"MKN", UCURR_COMMON|UCURR_DEPRECATED},
   1654     {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
   1655     {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1656     {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1657     {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1658     {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1659     {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
   1660     {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
   1661     {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1662     {"MVP", UCURR_COMMON|UCURR_DEPRECATED},
   1663     {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1664     {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1665     {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1666     {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
   1667     {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1668     {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1669     {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1670     {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
   1671     {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1672     {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1673     {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1674     {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
   1675     {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1676     {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
   1677     {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1678     {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1679     {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1680     {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1681     {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1682     {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
   1683     {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1684     {"PES", UCURR_COMMON|UCURR_DEPRECATED},
   1685     {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1686     {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1687     {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1688     {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1689     {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
   1690     {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
   1691     {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1692     {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1693     {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
   1694     {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
   1695     {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1696     {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1697     {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1698     {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
   1699     {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1700     {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1701     {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1702     {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1703     {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
   1704     {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1705     {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
   1706     {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1707     {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1708     {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1709     {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
   1710     {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1711     {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1712     {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1713     {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1714     {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
   1715     {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1716     {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
   1717     {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1718     {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1719     {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1720     {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1721     {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
   1722     {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1723     {"TMM", UCURR_COMMON|UCURR_DEPRECATED},
   1724     {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1725     {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1726     {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1727     {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
   1728     {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
   1729     {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1730     {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1731     {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1732     {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1733     {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1734     {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
   1735     {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
   1736     {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1737     {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1738     {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1739     {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1740     {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1741     {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
   1742     {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1743     {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1744     {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
   1745     {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1746     {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1747     {"VNN", UCURR_COMMON|UCURR_DEPRECATED},
   1748     {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1749     {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1750     {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1751     {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1752     {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1753     {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1754     {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1755     {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1756     {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1757     {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1758     {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1759     {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1760     {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1761     {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1762     {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1763     {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1764     {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1765     {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1766     {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1767     {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1768     {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1769     {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
   1770     {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1771     {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
   1772     {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
   1773     {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
   1774     {"YUR", UCURR_COMMON|UCURR_DEPRECATED},
   1775     {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1776     {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1777     {"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1778     {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
   1779     {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
   1780     {"ZWL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1781     {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
   1782     {"ZWD", UCURR_COMMON|UCURR_DEPRECATED},
   1783     { NULL, 0 } // Leave here to denote the end of the list.
   1784 };
   1785 
   1786 #define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
   1787     ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
   1788 
   1789 static int32_t U_CALLCONV
   1790 ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
   1791     UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
   1792     uint32_t currType = myContext->currType;
   1793     int32_t count = 0;
   1794 
   1795     /* Count the number of items matching the type we are looking for. */
   1796     for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
   1797         if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
   1798             count++;
   1799         }
   1800     }
   1801     return count;
   1802 }
   1803 
   1804 static const char* U_CALLCONV
   1805 ucurr_nextCurrencyList(UEnumeration *enumerator,
   1806                         int32_t* resultLength,
   1807                         UErrorCode * /*pErrorCode*/)
   1808 {
   1809     UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
   1810 
   1811     /* Find the next in the list that matches the type we are looking for. */
   1812     while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
   1813         const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
   1814         if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
   1815         {
   1816             if (resultLength) {
   1817                 *resultLength = 3; /* Currency codes are only 3 chars long */
   1818             }
   1819             return currItem->currency;
   1820         }
   1821     }
   1822     /* We enumerated too far. */
   1823     if (resultLength) {
   1824         *resultLength = 0;
   1825     }
   1826     return NULL;
   1827 }
   1828 
   1829 static void U_CALLCONV
   1830 ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
   1831     ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
   1832 }
   1833 
   1834 static void U_CALLCONV
   1835 ucurr_closeCurrencyList(UEnumeration *enumerator) {
   1836     uprv_free(enumerator->context);
   1837     uprv_free(enumerator);
   1838 }
   1839 
   1840 static void U_CALLCONV
   1841 ucurr_createCurrencyList(UErrorCode* status){
   1842     UErrorCode localStatus = U_ZERO_ERROR;
   1843 
   1844     // Look up the CurrencyMap element in the root bundle.
   1845     UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   1846     UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   1847 
   1848     if (U_SUCCESS(localStatus)) {
   1849         // process each entry in currency map
   1850         for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) {
   1851             // get the currency resource
   1852             UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus);
   1853             // process each currency
   1854             if (U_SUCCESS(localStatus)) {
   1855                 for (int32_t j=0; j<ures_getSize(currencyArray); j++) {
   1856                     // get the currency resource
   1857                     UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus);
   1858                     IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry));
   1859                     if (entry == NULL) {
   1860                         *status = U_MEMORY_ALLOCATION_ERROR;
   1861                         return;
   1862                     }
   1863 
   1864                     // get the ISO code
   1865                     int32_t isoLength = 0;
   1866                     UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus);
   1867                     if (idRes == NULL) {
   1868                         continue;
   1869                     }
   1870                     const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus);
   1871 
   1872                     // get from date
   1873                     UDate fromDate = U_DATE_MIN;
   1874                     UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   1875 
   1876                     if (U_SUCCESS(localStatus)) {
   1877                         int32_t fromLength = 0;
   1878                         const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   1879                         int64_t currDate64 = (int64_t)fromArray[0] << 32;
   1880                         currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   1881                         fromDate = (UDate)currDate64;
   1882                     }
   1883                     ures_close(fromRes);
   1884 
   1885                     // get to date
   1886                     UDate toDate = U_DATE_MAX;
   1887                     localStatus = U_ZERO_ERROR;
   1888                     UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   1889 
   1890                     if (U_SUCCESS(localStatus)) {
   1891                         int32_t toLength = 0;
   1892                         const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   1893                         int64_t currDate64 = (int64_t)toArray[0] << 32;
   1894                         currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   1895                         toDate = (UDate)currDate64;
   1896                     }
   1897                     ures_close(toRes);
   1898 
   1899                     ures_close(idRes);
   1900                     ures_close(currencyRes);
   1901 
   1902                     entry->isoCode = isoCode;
   1903                     entry->from = fromDate;
   1904                     entry->to = toDate;
   1905 
   1906                     localStatus = U_ZERO_ERROR;
   1907                     uhash_put(gIsoCodes, (UChar *)isoCode, entry, &localStatus);
   1908                 }
   1909             } else {
   1910                 *status = localStatus;
   1911             }
   1912             ures_close(currencyArray);
   1913         }
   1914     } else {
   1915         *status = localStatus;
   1916     }
   1917 
   1918     ures_close(currencyMapArray);
   1919 }
   1920 
   1921 static const UEnumeration gEnumCurrencyList = {
   1922     NULL,
   1923     NULL,
   1924     ucurr_closeCurrencyList,
   1925     ucurr_countCurrencyList,
   1926     uenum_unextDefault,
   1927     ucurr_nextCurrencyList,
   1928     ucurr_resetCurrencyList
   1929 };
   1930 U_CDECL_END
   1931 
   1932 U_CAPI UBool U_EXPORT2
   1933 ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
   1934     UErrorCode status = U_ZERO_ERROR;
   1935     UBool initialized;
   1936     UMTX_CHECK(&gIsoCodesLock, gIsoCodesInitialized, initialized);
   1937 
   1938     if (!initialized) {
   1939         umtx_lock(&gIsoCodesLock);
   1940         gIsoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
   1941         if (U_FAILURE(status)) {
   1942             umtx_unlock(&gIsoCodesLock);
   1943             return FALSE;
   1944         }
   1945         uhash_setValueDeleter(gIsoCodes, deleteIsoCodeEntry);
   1946 
   1947         ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
   1948         ucurr_createCurrencyList(&status);
   1949         if (U_FAILURE(status)) {
   1950             umtx_unlock(&gIsoCodesLock);
   1951             return FALSE;
   1952         }
   1953 
   1954         gIsoCodesInitialized = TRUE;
   1955         umtx_unlock(&gIsoCodesLock);
   1956     }
   1957 
   1958     umtx_lock(&gIsoCodesLock);
   1959     IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
   1960     umtx_unlock(&gIsoCodesLock);
   1961 
   1962     if (result == NULL) {
   1963         return FALSE;
   1964     } else if (from > to) {
   1965         *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
   1966         return FALSE;
   1967     } else if  ((from > result->to) || (to < result->from)) {
   1968         return FALSE;
   1969     }
   1970 
   1971     return TRUE;
   1972 }
   1973 
   1974 U_CAPI UEnumeration * U_EXPORT2
   1975 ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
   1976     UEnumeration *myEnum = NULL;
   1977     UCurrencyContext *myContext;
   1978 
   1979     myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
   1980     if (myEnum == NULL) {
   1981         *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
   1982         return NULL;
   1983     }
   1984     uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
   1985     myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
   1986     if (myContext == NULL) {
   1987         *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
   1988         uprv_free(myEnum);
   1989         return NULL;
   1990     }
   1991     myContext->currType = currType;
   1992     myContext->listIdx = 0;
   1993     myEnum->context = myContext;
   1994     return myEnum;
   1995 }
   1996 
   1997 U_CAPI int32_t U_EXPORT2
   1998 ucurr_countCurrencies(const char* locale,
   1999                  UDate date,
   2000                  UErrorCode* ec)
   2001 {
   2002     int32_t currCount = 0;
   2003 
   2004     if (ec != NULL && U_SUCCESS(*ec))
   2005     {
   2006         // local variables
   2007         UErrorCode localStatus = U_ZERO_ERROR;
   2008         char id[ULOC_FULLNAME_CAPACITY];
   2009         uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
   2010         // get country or country_variant in `id'
   2011         /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
   2012 
   2013         if (U_FAILURE(*ec))
   2014         {
   2015             return 0;
   2016         }
   2017 
   2018         // Remove variants, which is only needed for registration.
   2019         char *idDelim = strchr(id, VAR_DELIM);
   2020         if (idDelim)
   2021         {
   2022             idDelim[0] = 0;
   2023         }
   2024 
   2025         // Look up the CurrencyMap element in the root bundle.
   2026         UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   2027         UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   2028 
   2029         // Using the id derived from the local, get the currency data
   2030         UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
   2031 
   2032         // process each currency to see which one is valid for the given date
   2033         if (U_SUCCESS(localStatus))
   2034         {
   2035             for (int32_t i=0; i<ures_getSize(countryArray); i++)
   2036             {
   2037                 // get the currency resource
   2038                 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
   2039 
   2040                 // get the from date
   2041                 int32_t fromLength = 0;
   2042                 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   2043                 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   2044 
   2045                 int64_t currDate64 = (int64_t)fromArray[0] << 32;
   2046                 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2047                 UDate fromDate = (UDate)currDate64;
   2048 
   2049                 if (ures_getSize(currencyRes)> 2)
   2050                 {
   2051                     int32_t toLength = 0;
   2052                     UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   2053                     const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   2054 
   2055                     currDate64 = (int64_t)toArray[0] << 32;
   2056                     currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2057                     UDate toDate = (UDate)currDate64;
   2058 
   2059                     if ((fromDate <= date) && (date < toDate))
   2060                     {
   2061                         currCount++;
   2062                     }
   2063 
   2064                     ures_close(toRes);
   2065                 }
   2066                 else
   2067                 {
   2068                     if (fromDate <= date)
   2069                     {
   2070                         currCount++;
   2071                     }
   2072                 }
   2073 
   2074                 // close open resources
   2075                 ures_close(currencyRes);
   2076                 ures_close(fromRes);
   2077 
   2078             } // end For loop
   2079         } // end if (U_SUCCESS(localStatus))
   2080 
   2081         ures_close(countryArray);
   2082 
   2083         // Check for errors
   2084         if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
   2085         {
   2086             // There is nothing to fallback to.
   2087             // Report the failure/warning if possible.
   2088             *ec = localStatus;
   2089         }
   2090 
   2091         if (U_SUCCESS(*ec))
   2092         {
   2093             // no errors
   2094             return currCount;
   2095         }
   2096 
   2097     }
   2098 
   2099     // If we got here, either error code is invalid or
   2100     // some argument passed is no good.
   2101     return 0;
   2102 }
   2103 
   2104 U_CAPI int32_t U_EXPORT2
   2105 ucurr_forLocaleAndDate(const char* locale,
   2106                 UDate date,
   2107                 int32_t index,
   2108                 UChar* buff,
   2109                 int32_t buffCapacity,
   2110                 UErrorCode* ec)
   2111 {
   2112     int32_t resLen = 0;
   2113 	int32_t currIndex = 0;
   2114     const UChar* s = NULL;
   2115 
   2116     if (ec != NULL && U_SUCCESS(*ec))
   2117     {
   2118         // check the arguments passed
   2119         if ((buff && buffCapacity) || !buffCapacity )
   2120         {
   2121             // local variables
   2122             UErrorCode localStatus = U_ZERO_ERROR;
   2123             char id[ULOC_FULLNAME_CAPACITY];
   2124             resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
   2125 
   2126             // get country or country_variant in `id'
   2127             /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
   2128             if (U_FAILURE(*ec))
   2129             {
   2130                 return 0;
   2131             }
   2132 
   2133             // Remove variants, which is only needed for registration.
   2134             char *idDelim = strchr(id, VAR_DELIM);
   2135             if (idDelim)
   2136             {
   2137                 idDelim[0] = 0;
   2138             }
   2139 
   2140             // Look up the CurrencyMap element in the root bundle.
   2141             UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   2142             UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   2143 
   2144             // Using the id derived from the local, get the currency data
   2145             UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
   2146 
   2147             // process each currency to see which one is valid for the given date
   2148             bool matchFound = false;
   2149             if (U_SUCCESS(localStatus))
   2150             {
   2151                 if ((index <= 0) || (index> ures_getSize(countryArray)))
   2152                 {
   2153                     // requested index is out of bounds
   2154                     ures_close(countryArray);
   2155                     return 0;
   2156                 }
   2157 
   2158                 for (int32_t i=0; i<ures_getSize(countryArray); i++)
   2159                 {
   2160                     // get the currency resource
   2161                     UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
   2162                     s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
   2163 
   2164                     // get the from date
   2165                     int32_t fromLength = 0;
   2166                     UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   2167                     const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   2168 
   2169                     int64_t currDate64 = (int64_t)fromArray[0] << 32;
   2170                     currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2171                     UDate fromDate = (UDate)currDate64;
   2172 
   2173                     if (ures_getSize(currencyRes)> 2)
   2174                     {
   2175                         int32_t toLength = 0;
   2176                         UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   2177                         const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   2178 
   2179                         currDate64 = (int64_t)toArray[0] << 32;
   2180                         currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2181                         UDate toDate = (UDate)currDate64;
   2182 
   2183                         if ((fromDate <= date) && (date < toDate))
   2184                         {
   2185                             currIndex++;
   2186                             if (currIndex == index)
   2187                             {
   2188                                 matchFound = true;
   2189                             }
   2190                         }
   2191 
   2192                         ures_close(toRes);
   2193                     }
   2194                     else
   2195                     {
   2196                         if (fromDate <= date)
   2197                         {
   2198                             currIndex++;
   2199                             if (currIndex == index)
   2200                             {
   2201                                 matchFound = true;
   2202                             }
   2203                         }
   2204                     }
   2205 
   2206                     // close open resources
   2207                     ures_close(currencyRes);
   2208                     ures_close(fromRes);
   2209 
   2210                     // check for loop exit
   2211                     if (matchFound)
   2212                     {
   2213                         break;
   2214                     }
   2215 
   2216                 } // end For loop
   2217             }
   2218 
   2219             ures_close(countryArray);
   2220 
   2221             // Check for errors
   2222             if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
   2223             {
   2224                 // There is nothing to fallback to.
   2225                 // Report the failure/warning if possible.
   2226                 *ec = localStatus;
   2227             }
   2228 
   2229             if (U_SUCCESS(*ec))
   2230             {
   2231                 // no errors
   2232                 if((buffCapacity> resLen) && matchFound)
   2233                 {
   2234                     // write out the currency value
   2235                     u_strcpy(buff, s);
   2236                 }
   2237                 else
   2238                 {
   2239                     return 0;
   2240                 }
   2241             }
   2242 
   2243             // return null terminated currency string
   2244             return u_terminateUChars(buff, buffCapacity, resLen, ec);
   2245         }
   2246         else
   2247         {
   2248             // illegal argument encountered
   2249             *ec = U_ILLEGAL_ARGUMENT_ERROR;
   2250         }
   2251 
   2252     }
   2253 
   2254     // If we got here, either error code is invalid or
   2255     // some argument passed is no good.
   2256     return resLen;
   2257 }
   2258 
   2259 static const UEnumeration defaultKeywordValues = {
   2260     NULL,
   2261     NULL,
   2262     ulist_close_keyword_values_iterator,
   2263     ulist_count_keyword_values,
   2264     uenum_unextDefault,
   2265     ulist_next_keyword_value,
   2266     ulist_reset_keyword_values_iterator
   2267 };
   2268 
   2269 U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
   2270     // Resolve region
   2271     char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
   2272     int32_t prefRegionLength = 0;
   2273     prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
   2274     if (prefRegionLength == 0) {
   2275         char loc[ULOC_FULLNAME_CAPACITY] = "";
   2276         uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
   2277 
   2278         prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
   2279     }
   2280 
   2281     // Read value from supplementalData
   2282     UList *values = ulist_createEmptyList(status);
   2283     UList *otherValues = ulist_createEmptyList(status);
   2284     UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
   2285     if (U_FAILURE(*status) || en == NULL) {
   2286         if (en == NULL) {
   2287             *status = U_MEMORY_ALLOCATION_ERROR;
   2288         } else {
   2289             uprv_free(en);
   2290         }
   2291         ulist_deleteList(values);
   2292         ulist_deleteList(otherValues);
   2293         return NULL;
   2294     }
   2295     memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
   2296     en->context = values;
   2297 
   2298     UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
   2299     ures_getByKey(bundle, "CurrencyMap", bundle, status);
   2300     UResourceBundle bundlekey, regbndl, curbndl, to;
   2301     ures_initStackObject(&bundlekey);
   2302     ures_initStackObject(&regbndl);
   2303     ures_initStackObject(&curbndl);
   2304     ures_initStackObject(&to);
   2305 
   2306     while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
   2307         ures_getNextResource(bundle, &bundlekey, status);
   2308         if (U_FAILURE(*status)) {
   2309             break;
   2310         }
   2311         const char *region = ures_getKey(&bundlekey);
   2312         UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
   2313         if (!isPrefRegion && commonlyUsed) {
   2314             // With commonlyUsed=true, we do not put
   2315             // currencies for other regions in the
   2316             // result list.
   2317             continue;
   2318         }
   2319         ures_getByKey(bundle, region, &regbndl, status);
   2320         if (U_FAILURE(*status)) {
   2321             break;
   2322         }
   2323         while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
   2324             ures_getNextResource(&regbndl, &curbndl, status);
   2325             if (ures_getType(&curbndl) != URES_TABLE) {
   2326                 // Currently, an empty ARRAY is mixed in.
   2327                 continue;
   2328             }
   2329             char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
   2330             int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
   2331             if (curID == NULL) {
   2332                 *status = U_MEMORY_ALLOCATION_ERROR;
   2333                 break;
   2334             }
   2335 
   2336 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
   2337             ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
   2338             /* optimize - use the utf-8 string */
   2339 #else
   2340             {
   2341                        const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
   2342                        if(U_SUCCESS(*status)) {
   2343 			   if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
   2344 				*status = U_BUFFER_OVERFLOW_ERROR;
   2345 			   } else {
   2346                            	u_UCharsToChars(defString, curID, curIDLength+1);
   2347 			   }
   2348                        }
   2349             }
   2350 #endif
   2351 
   2352             if (U_FAILURE(*status)) {
   2353                 break;
   2354             }
   2355             UBool hasTo = FALSE;
   2356             ures_getByKey(&curbndl, "to", &to, status);
   2357             if (U_FAILURE(*status)) {
   2358                 // Do nothing here...
   2359                 *status = U_ZERO_ERROR;
   2360             } else {
   2361                 hasTo = TRUE;
   2362             }
   2363             if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
   2364                 // Currently active currency for the target country
   2365                 ulist_addItemEndList(values, curID, TRUE, status);
   2366             } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
   2367                 ulist_addItemEndList(otherValues, curID, TRUE, status);
   2368             } else {
   2369                 uprv_free(curID);
   2370             }
   2371         }
   2372 
   2373     }
   2374     if (U_SUCCESS(*status)) {
   2375         if (commonlyUsed) {
   2376             if (ulist_getListSize(values) == 0) {
   2377                 // This could happen if no valid region is supplied in the input
   2378                 // locale. In this case, we use the CLDR's default.
   2379                 uenum_close(en);
   2380                 en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
   2381             }
   2382         } else {
   2383             // Consolidate the list
   2384             char *value = NULL;
   2385             ulist_resetList(otherValues);
   2386             while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
   2387                 if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
   2388                     char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
   2389                     uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
   2390                     ulist_addItemEndList(values, tmpValue, TRUE, status);
   2391                     if (U_FAILURE(*status)) {
   2392                         break;
   2393                     }
   2394                 }
   2395             }
   2396         }
   2397 
   2398         ulist_resetList((UList *)(en->context));
   2399     } else {
   2400         ulist_deleteList(values);
   2401         uprv_free(en);
   2402         values = NULL;
   2403         en = NULL;
   2404     }
   2405     ures_close(&to);
   2406     ures_close(&curbndl);
   2407     ures_close(&regbndl);
   2408     ures_close(&bundlekey);
   2409     ures_close(bundle);
   2410 
   2411     ulist_deleteList(otherValues);
   2412 
   2413     return en;
   2414 }
   2415 
   2416 
   2417 U_CAPI int32_t U_EXPORT2
   2418 ucurr_getNumericCode(const UChar* currency) {
   2419     int32_t code = 0;
   2420     if (currency && u_strlen(currency) == ISO_CURRENCY_CODE_LENGTH) {
   2421         UErrorCode status = U_ZERO_ERROR;
   2422 
   2423         UResourceBundle *bundle = ures_openDirect(0, "currencyNumericCodes", &status);
   2424         ures_getByKey(bundle, "codeMap", bundle, &status);
   2425         if (U_SUCCESS(status)) {
   2426             char alphaCode[ISO_CURRENCY_CODE_LENGTH+1];
   2427             myUCharsToChars(alphaCode, currency);
   2428             T_CString_toUpperCase(alphaCode);
   2429             ures_getByKey(bundle, alphaCode, bundle, &status);
   2430             int tmpCode = ures_getInt(bundle, &status);
   2431             if (U_SUCCESS(status)) {
   2432                 code = tmpCode;
   2433             }
   2434         }
   2435         ures_close(bundle);
   2436     }
   2437     return code;
   2438 }
   2439 #endif /* #if !UCONFIG_NO_FORMATTING */
   2440 
   2441 //eof
   2442