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