Home | History | Annotate | Download | only in i18n
      1 /*
      2 **********************************************************************
      3 * Copyright (c) 2002-2013, 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     {"SSP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1716     {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1717     {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
   1718     {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1719     {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1720     {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1721     {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1722     {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
   1723     {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1724     {"TMM", UCURR_COMMON|UCURR_DEPRECATED},
   1725     {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1726     {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1727     {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1728     {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
   1729     {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
   1730     {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1731     {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1732     {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1733     {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1734     {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1735     {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
   1736     {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
   1737     {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1738     {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1739     {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1740     {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1741     {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1742     {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
   1743     {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1744     {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1745     {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
   1746     {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1747     {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1748     {"VNN", UCURR_COMMON|UCURR_DEPRECATED},
   1749     {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1750     {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1751     {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1752     {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1753     {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1754     {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1755     {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1756     {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1757     {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1758     {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1759     {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1760     {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1761     {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1762     {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1763     {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1764     {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1765     {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1766     {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1767     {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1768     {"XSU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1769     {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1770     {"XUA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1771     {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1772     {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
   1773     {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1774     {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
   1775     {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
   1776     {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
   1777     {"YUR", UCURR_COMMON|UCURR_DEPRECATED},
   1778     {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1779     {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1780     {"ZMK", UCURR_COMMON|UCURR_DEPRECATED},
   1781     {"ZMW", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1782     {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
   1783     {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
   1784     {"ZWL", UCURR_COMMON|UCURR_DEPRECATED},
   1785     {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
   1786     {"ZWD", UCURR_COMMON|UCURR_DEPRECATED},
   1787     { NULL, 0 } // Leave here to denote the end of the list.
   1788 };
   1789 
   1790 #define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
   1791     ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
   1792 
   1793 static int32_t U_CALLCONV
   1794 ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
   1795     UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
   1796     uint32_t currType = myContext->currType;
   1797     int32_t count = 0;
   1798 
   1799     /* Count the number of items matching the type we are looking for. */
   1800     for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
   1801         if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
   1802             count++;
   1803         }
   1804     }
   1805     return count;
   1806 }
   1807 
   1808 static const char* U_CALLCONV
   1809 ucurr_nextCurrencyList(UEnumeration *enumerator,
   1810                         int32_t* resultLength,
   1811                         UErrorCode * /*pErrorCode*/)
   1812 {
   1813     UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
   1814 
   1815     /* Find the next in the list that matches the type we are looking for. */
   1816     while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
   1817         const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
   1818         if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
   1819         {
   1820             if (resultLength) {
   1821                 *resultLength = 3; /* Currency codes are only 3 chars long */
   1822             }
   1823             return currItem->currency;
   1824         }
   1825     }
   1826     /* We enumerated too far. */
   1827     if (resultLength) {
   1828         *resultLength = 0;
   1829     }
   1830     return NULL;
   1831 }
   1832 
   1833 static void U_CALLCONV
   1834 ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
   1835     ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
   1836 }
   1837 
   1838 static void U_CALLCONV
   1839 ucurr_closeCurrencyList(UEnumeration *enumerator) {
   1840     uprv_free(enumerator->context);
   1841     uprv_free(enumerator);
   1842 }
   1843 
   1844 static void U_CALLCONV
   1845 ucurr_createCurrencyList(UErrorCode* status){
   1846     UErrorCode localStatus = U_ZERO_ERROR;
   1847 
   1848     // Look up the CurrencyMap element in the root bundle.
   1849     UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   1850     UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   1851 
   1852     if (U_SUCCESS(localStatus)) {
   1853         // process each entry in currency map
   1854         for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) {
   1855             // get the currency resource
   1856             UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus);
   1857             // process each currency
   1858             if (U_SUCCESS(localStatus)) {
   1859                 for (int32_t j=0; j<ures_getSize(currencyArray); j++) {
   1860                     // get the currency resource
   1861                     UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus);
   1862                     IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry));
   1863                     if (entry == NULL) {
   1864                         *status = U_MEMORY_ALLOCATION_ERROR;
   1865                         return;
   1866                     }
   1867 
   1868                     // get the ISO code
   1869                     int32_t isoLength = 0;
   1870                     UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus);
   1871                     if (idRes == NULL) {
   1872                         continue;
   1873                     }
   1874                     const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus);
   1875 
   1876                     // get from date
   1877                     UDate fromDate = U_DATE_MIN;
   1878                     UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   1879 
   1880                     if (U_SUCCESS(localStatus)) {
   1881                         int32_t fromLength = 0;
   1882                         const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   1883                         int64_t currDate64 = (int64_t)fromArray[0] << 32;
   1884                         currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   1885                         fromDate = (UDate)currDate64;
   1886                     }
   1887                     ures_close(fromRes);
   1888 
   1889                     // get to date
   1890                     UDate toDate = U_DATE_MAX;
   1891                     localStatus = U_ZERO_ERROR;
   1892                     UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   1893 
   1894                     if (U_SUCCESS(localStatus)) {
   1895                         int32_t toLength = 0;
   1896                         const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   1897                         int64_t currDate64 = (int64_t)toArray[0] << 32;
   1898                         currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   1899                         toDate = (UDate)currDate64;
   1900                     }
   1901                     ures_close(toRes);
   1902 
   1903                     ures_close(idRes);
   1904                     ures_close(currencyRes);
   1905 
   1906                     entry->isoCode = isoCode;
   1907                     entry->from = fromDate;
   1908                     entry->to = toDate;
   1909 
   1910                     localStatus = U_ZERO_ERROR;
   1911                     uhash_put(gIsoCodes, (UChar *)isoCode, entry, &localStatus);
   1912                 }
   1913             } else {
   1914                 *status = localStatus;
   1915             }
   1916             ures_close(currencyArray);
   1917         }
   1918     } else {
   1919         *status = localStatus;
   1920     }
   1921 
   1922     ures_close(currencyMapArray);
   1923 }
   1924 
   1925 static const UEnumeration gEnumCurrencyList = {
   1926     NULL,
   1927     NULL,
   1928     ucurr_closeCurrencyList,
   1929     ucurr_countCurrencyList,
   1930     uenum_unextDefault,
   1931     ucurr_nextCurrencyList,
   1932     ucurr_resetCurrencyList
   1933 };
   1934 U_CDECL_END
   1935 
   1936 U_CAPI UBool U_EXPORT2
   1937 ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
   1938     UErrorCode status = U_ZERO_ERROR;
   1939     UBool initialized;
   1940     UMTX_CHECK(&gIsoCodesLock, gIsoCodesInitialized, initialized);
   1941 
   1942     if (!initialized) {
   1943         umtx_lock(&gIsoCodesLock);
   1944         gIsoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
   1945         if (U_FAILURE(status)) {
   1946             umtx_unlock(&gIsoCodesLock);
   1947             return FALSE;
   1948         }
   1949         uhash_setValueDeleter(gIsoCodes, deleteIsoCodeEntry);
   1950 
   1951         ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
   1952         ucurr_createCurrencyList(&status);
   1953         if (U_FAILURE(status)) {
   1954             umtx_unlock(&gIsoCodesLock);
   1955             return FALSE;
   1956         }
   1957 
   1958         gIsoCodesInitialized = TRUE;
   1959         umtx_unlock(&gIsoCodesLock);
   1960     }
   1961 
   1962     umtx_lock(&gIsoCodesLock);
   1963     IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
   1964     umtx_unlock(&gIsoCodesLock);
   1965 
   1966     if (result == NULL) {
   1967         return FALSE;
   1968     } else if (from > to) {
   1969         *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
   1970         return FALSE;
   1971     } else if  ((from > result->to) || (to < result->from)) {
   1972         return FALSE;
   1973     }
   1974 
   1975     return TRUE;
   1976 }
   1977 
   1978 U_CAPI UEnumeration * U_EXPORT2
   1979 ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
   1980     UEnumeration *myEnum = NULL;
   1981     UCurrencyContext *myContext;
   1982 
   1983     myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
   1984     if (myEnum == NULL) {
   1985         *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
   1986         return NULL;
   1987     }
   1988     uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
   1989     myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
   1990     if (myContext == NULL) {
   1991         *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
   1992         uprv_free(myEnum);
   1993         return NULL;
   1994     }
   1995     myContext->currType = currType;
   1996     myContext->listIdx = 0;
   1997     myEnum->context = myContext;
   1998     return myEnum;
   1999 }
   2000 
   2001 U_CAPI int32_t U_EXPORT2
   2002 ucurr_countCurrencies(const char* locale,
   2003                  UDate date,
   2004                  UErrorCode* ec)
   2005 {
   2006     int32_t currCount = 0;
   2007 
   2008     if (ec != NULL && U_SUCCESS(*ec))
   2009     {
   2010         // local variables
   2011         UErrorCode localStatus = U_ZERO_ERROR;
   2012         char id[ULOC_FULLNAME_CAPACITY];
   2013         uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
   2014         // get country or country_variant in `id'
   2015         /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
   2016 
   2017         if (U_FAILURE(*ec))
   2018         {
   2019             return 0;
   2020         }
   2021 
   2022         // Remove variants, which is only needed for registration.
   2023         char *idDelim = strchr(id, VAR_DELIM);
   2024         if (idDelim)
   2025         {
   2026             idDelim[0] = 0;
   2027         }
   2028 
   2029         // Look up the CurrencyMap element in the root bundle.
   2030         UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   2031         UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   2032 
   2033         // Using the id derived from the local, get the currency data
   2034         UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
   2035 
   2036         // process each currency to see which one is valid for the given date
   2037         if (U_SUCCESS(localStatus))
   2038         {
   2039             for (int32_t i=0; i<ures_getSize(countryArray); i++)
   2040             {
   2041                 // get the currency resource
   2042                 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
   2043 
   2044                 // get the from date
   2045                 int32_t fromLength = 0;
   2046                 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   2047                 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   2048 
   2049                 int64_t currDate64 = (int64_t)fromArray[0] << 32;
   2050                 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2051                 UDate fromDate = (UDate)currDate64;
   2052 
   2053                 if (ures_getSize(currencyRes)> 2)
   2054                 {
   2055                     int32_t toLength = 0;
   2056                     UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   2057                     const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   2058 
   2059                     currDate64 = (int64_t)toArray[0] << 32;
   2060                     currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2061                     UDate toDate = (UDate)currDate64;
   2062 
   2063                     if ((fromDate <= date) && (date < toDate))
   2064                     {
   2065                         currCount++;
   2066                     }
   2067 
   2068                     ures_close(toRes);
   2069                 }
   2070                 else
   2071                 {
   2072                     if (fromDate <= date)
   2073                     {
   2074                         currCount++;
   2075                     }
   2076                 }
   2077 
   2078                 // close open resources
   2079                 ures_close(currencyRes);
   2080                 ures_close(fromRes);
   2081 
   2082             } // end For loop
   2083         } // end if (U_SUCCESS(localStatus))
   2084 
   2085         ures_close(countryArray);
   2086 
   2087         // Check for errors
   2088         if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
   2089         {
   2090             // There is nothing to fallback to.
   2091             // Report the failure/warning if possible.
   2092             *ec = localStatus;
   2093         }
   2094 
   2095         if (U_SUCCESS(*ec))
   2096         {
   2097             // no errors
   2098             return currCount;
   2099         }
   2100 
   2101     }
   2102 
   2103     // If we got here, either error code is invalid or
   2104     // some argument passed is no good.
   2105     return 0;
   2106 }
   2107 
   2108 U_CAPI int32_t U_EXPORT2
   2109 ucurr_forLocaleAndDate(const char* locale,
   2110                 UDate date,
   2111                 int32_t index,
   2112                 UChar* buff,
   2113                 int32_t buffCapacity,
   2114                 UErrorCode* ec)
   2115 {
   2116     int32_t resLen = 0;
   2117 	int32_t currIndex = 0;
   2118     const UChar* s = NULL;
   2119 
   2120     if (ec != NULL && U_SUCCESS(*ec))
   2121     {
   2122         // check the arguments passed
   2123         if ((buff && buffCapacity) || !buffCapacity )
   2124         {
   2125             // local variables
   2126             UErrorCode localStatus = U_ZERO_ERROR;
   2127             char id[ULOC_FULLNAME_CAPACITY];
   2128             resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
   2129 
   2130             // get country or country_variant in `id'
   2131             /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
   2132             if (U_FAILURE(*ec))
   2133             {
   2134                 return 0;
   2135             }
   2136 
   2137             // Remove variants, which is only needed for registration.
   2138             char *idDelim = strchr(id, VAR_DELIM);
   2139             if (idDelim)
   2140             {
   2141                 idDelim[0] = 0;
   2142             }
   2143 
   2144             // Look up the CurrencyMap element in the root bundle.
   2145             UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   2146             UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   2147 
   2148             // Using the id derived from the local, get the currency data
   2149             UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
   2150 
   2151             // process each currency to see which one is valid for the given date
   2152             bool matchFound = false;
   2153             if (U_SUCCESS(localStatus))
   2154             {
   2155                 if ((index <= 0) || (index> ures_getSize(countryArray)))
   2156                 {
   2157                     // requested index is out of bounds
   2158                     ures_close(countryArray);
   2159                     return 0;
   2160                 }
   2161 
   2162                 for (int32_t i=0; i<ures_getSize(countryArray); i++)
   2163                 {
   2164                     // get the currency resource
   2165                     UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
   2166                     s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
   2167 
   2168                     // get the from date
   2169                     int32_t fromLength = 0;
   2170                     UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   2171                     const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   2172 
   2173                     int64_t currDate64 = (int64_t)fromArray[0] << 32;
   2174                     currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2175                     UDate fromDate = (UDate)currDate64;
   2176 
   2177                     if (ures_getSize(currencyRes)> 2)
   2178                     {
   2179                         int32_t toLength = 0;
   2180                         UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   2181                         const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   2182 
   2183                         currDate64 = (int64_t)toArray[0] << 32;
   2184                         currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2185                         UDate toDate = (UDate)currDate64;
   2186 
   2187                         if ((fromDate <= date) && (date < toDate))
   2188                         {
   2189                             currIndex++;
   2190                             if (currIndex == index)
   2191                             {
   2192                                 matchFound = true;
   2193                             }
   2194                         }
   2195 
   2196                         ures_close(toRes);
   2197                     }
   2198                     else
   2199                     {
   2200                         if (fromDate <= date)
   2201                         {
   2202                             currIndex++;
   2203                             if (currIndex == index)
   2204                             {
   2205                                 matchFound = true;
   2206                             }
   2207                         }
   2208                     }
   2209 
   2210                     // close open resources
   2211                     ures_close(currencyRes);
   2212                     ures_close(fromRes);
   2213 
   2214                     // check for loop exit
   2215                     if (matchFound)
   2216                     {
   2217                         break;
   2218                     }
   2219 
   2220                 } // end For loop
   2221             }
   2222 
   2223             ures_close(countryArray);
   2224 
   2225             // Check for errors
   2226             if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
   2227             {
   2228                 // There is nothing to fallback to.
   2229                 // Report the failure/warning if possible.
   2230                 *ec = localStatus;
   2231             }
   2232 
   2233             if (U_SUCCESS(*ec))
   2234             {
   2235                 // no errors
   2236                 if((buffCapacity> resLen) && matchFound)
   2237                 {
   2238                     // write out the currency value
   2239                     u_strcpy(buff, s);
   2240                 }
   2241                 else
   2242                 {
   2243                     return 0;
   2244                 }
   2245             }
   2246 
   2247             // return null terminated currency string
   2248             return u_terminateUChars(buff, buffCapacity, resLen, ec);
   2249         }
   2250         else
   2251         {
   2252             // illegal argument encountered
   2253             *ec = U_ILLEGAL_ARGUMENT_ERROR;
   2254         }
   2255 
   2256     }
   2257 
   2258     // If we got here, either error code is invalid or
   2259     // some argument passed is no good.
   2260     return resLen;
   2261 }
   2262 
   2263 static const UEnumeration defaultKeywordValues = {
   2264     NULL,
   2265     NULL,
   2266     ulist_close_keyword_values_iterator,
   2267     ulist_count_keyword_values,
   2268     uenum_unextDefault,
   2269     ulist_next_keyword_value,
   2270     ulist_reset_keyword_values_iterator
   2271 };
   2272 
   2273 U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
   2274     // Resolve region
   2275     char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
   2276     int32_t prefRegionLength = 0;
   2277     prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
   2278     if (prefRegionLength == 0) {
   2279         char loc[ULOC_FULLNAME_CAPACITY] = "";
   2280         uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
   2281 
   2282         prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
   2283     }
   2284 
   2285     // Read value from supplementalData
   2286     UList *values = ulist_createEmptyList(status);
   2287     UList *otherValues = ulist_createEmptyList(status);
   2288     UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
   2289     if (U_FAILURE(*status) || en == NULL) {
   2290         if (en == NULL) {
   2291             *status = U_MEMORY_ALLOCATION_ERROR;
   2292         } else {
   2293             uprv_free(en);
   2294         }
   2295         ulist_deleteList(values);
   2296         ulist_deleteList(otherValues);
   2297         return NULL;
   2298     }
   2299     memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
   2300     en->context = values;
   2301 
   2302     UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
   2303     ures_getByKey(bundle, "CurrencyMap", bundle, status);
   2304     UResourceBundle bundlekey, regbndl, curbndl, to;
   2305     ures_initStackObject(&bundlekey);
   2306     ures_initStackObject(&regbndl);
   2307     ures_initStackObject(&curbndl);
   2308     ures_initStackObject(&to);
   2309 
   2310     while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
   2311         ures_getNextResource(bundle, &bundlekey, status);
   2312         if (U_FAILURE(*status)) {
   2313             break;
   2314         }
   2315         const char *region = ures_getKey(&bundlekey);
   2316         UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
   2317         if (!isPrefRegion && commonlyUsed) {
   2318             // With commonlyUsed=true, we do not put
   2319             // currencies for other regions in the
   2320             // result list.
   2321             continue;
   2322         }
   2323         ures_getByKey(bundle, region, &regbndl, status);
   2324         if (U_FAILURE(*status)) {
   2325             break;
   2326         }
   2327         while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
   2328             ures_getNextResource(&regbndl, &curbndl, status);
   2329             if (ures_getType(&curbndl) != URES_TABLE) {
   2330                 // Currently, an empty ARRAY is mixed in.
   2331                 continue;
   2332             }
   2333             char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
   2334             int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
   2335             if (curID == NULL) {
   2336                 *status = U_MEMORY_ALLOCATION_ERROR;
   2337                 break;
   2338             }
   2339 
   2340 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
   2341             ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
   2342             /* optimize - use the utf-8 string */
   2343 #else
   2344             {
   2345                        const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
   2346                        if(U_SUCCESS(*status)) {
   2347 			   if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
   2348 				*status = U_BUFFER_OVERFLOW_ERROR;
   2349 			   } else {
   2350                            	u_UCharsToChars(defString, curID, curIDLength+1);
   2351 			   }
   2352                        }
   2353             }
   2354 #endif
   2355 
   2356             if (U_FAILURE(*status)) {
   2357                 break;
   2358             }
   2359             UBool hasTo = FALSE;
   2360             ures_getByKey(&curbndl, "to", &to, status);
   2361             if (U_FAILURE(*status)) {
   2362                 // Do nothing here...
   2363                 *status = U_ZERO_ERROR;
   2364             } else {
   2365                 hasTo = TRUE;
   2366             }
   2367             if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
   2368                 // Currently active currency for the target country
   2369                 ulist_addItemEndList(values, curID, TRUE, status);
   2370             } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
   2371                 ulist_addItemEndList(otherValues, curID, TRUE, status);
   2372             } else {
   2373                 uprv_free(curID);
   2374             }
   2375         }
   2376 
   2377     }
   2378     if (U_SUCCESS(*status)) {
   2379         if (commonlyUsed) {
   2380             if (ulist_getListSize(values) == 0) {
   2381                 // This could happen if no valid region is supplied in the input
   2382                 // locale. In this case, we use the CLDR's default.
   2383                 uenum_close(en);
   2384                 en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
   2385             }
   2386         } else {
   2387             // Consolidate the list
   2388             char *value = NULL;
   2389             ulist_resetList(otherValues);
   2390             while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
   2391                 if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
   2392                     char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
   2393                     uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
   2394                     ulist_addItemEndList(values, tmpValue, TRUE, status);
   2395                     if (U_FAILURE(*status)) {
   2396                         break;
   2397                     }
   2398                 }
   2399             }
   2400         }
   2401 
   2402         ulist_resetList((UList *)(en->context));
   2403     } else {
   2404         ulist_deleteList(values);
   2405         uprv_free(en);
   2406         values = NULL;
   2407         en = NULL;
   2408     }
   2409     ures_close(&to);
   2410     ures_close(&curbndl);
   2411     ures_close(&regbndl);
   2412     ures_close(&bundlekey);
   2413     ures_close(bundle);
   2414 
   2415     ulist_deleteList(otherValues);
   2416 
   2417     return en;
   2418 }
   2419 
   2420 
   2421 U_CAPI int32_t U_EXPORT2
   2422 ucurr_getNumericCode(const UChar* currency) {
   2423     int32_t code = 0;
   2424     if (currency && u_strlen(currency) == ISO_CURRENCY_CODE_LENGTH) {
   2425         UErrorCode status = U_ZERO_ERROR;
   2426 
   2427         UResourceBundle *bundle = ures_openDirect(0, "currencyNumericCodes", &status);
   2428         ures_getByKey(bundle, "codeMap", bundle, &status);
   2429         if (U_SUCCESS(status)) {
   2430             char alphaCode[ISO_CURRENCY_CODE_LENGTH+1];
   2431             myUCharsToChars(alphaCode, currency);
   2432             T_CString_toUpperCase(alphaCode);
   2433             ures_getByKey(bundle, alphaCode, bundle, &status);
   2434             int tmpCode = ures_getInt(bundle, &status);
   2435             if (U_SUCCESS(status)) {
   2436                 code = tmpCode;
   2437             }
   2438         }
   2439         ures_close(bundle);
   2440     }
   2441     return code;
   2442 }
   2443 #endif /* #if !UCONFIG_NO_FORMATTING */
   2444 
   2445 //eof
   2446