LCOV - code coverage report
Current view: top level - intl/icu/source/common - ucurr.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1006 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 55 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13