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