1/*
2**********************************************************************
3* Copyright (c) 2002-2013, International Business Machines
4* Corporation and others.  All Rights Reserved.
5**********************************************************************
6*/
7
8#include "unicode/utypes.h"
9
10#if !UCONFIG_NO_FORMATTING
11
12#include "unicode/ucurr.h"
13#include "unicode/locid.h"
14#include "unicode/ures.h"
15#include "unicode/ustring.h"
16#include "unicode/choicfmt.h"
17#include "unicode/parsepos.h"
18#include "ustr_imp.h"
19#include "cmemory.h"
20#include "cstring.h"
21#include "uassert.h"
22#include "umutex.h"
23#include "ucln_in.h"
24#include "uenumimp.h"
25#include "uhash.h"
26#include "hash.h"
27#include "uresimp.h"
28#include "ulist.h"
29#include "ureslocs.h"
30
31//#define UCURR_DEBUG_EQUIV 1
32#ifdef UCURR_DEBUG_EQUIV
33#include "stdio.h"
34#endif
35//#define UCURR_DEBUG 1
36#ifdef UCURR_DEBUG
37#include "stdio.h"
38#endif
39
40typedef struct IsoCodeEntry {
41    const UChar *isoCode; /* const because it's a reference to a resource bundle string. */
42    UDate from;
43    UDate to;
44} IsoCodeEntry;
45
46//------------------------------------------------------------
47// Constants
48
49// Default currency meta data of last resort.  We try to use the
50// defaults encoded in the meta data resource bundle.  If there is a
51// configuration/build error and these are not available, we use these
52// hard-coded defaults (which should be identical).
53static const int32_t LAST_RESORT_DATA[] = { 2, 0, 2, 0 };
54
55// POW10[i] = 10^i, i=0..MAX_POW10
56static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
57                                 1000000, 10000000, 100000000, 1000000000 };
58
59static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
60
61// Defines equivalent currency symbols.
62static const char *EQUIV_CURRENCY_SYMBOLS[][2] = {
63    {"\\u00a5", "\\uffe5"},
64    {"$", "\\ufe69"},
65    {"$", "\\uff04"},
66    {"\\u20a8", "\\u20b9"},
67    {"\\u00a3", "\\u20a4"}};
68
69#define ISO_CURRENCY_CODE_LENGTH 3
70
71//------------------------------------------------------------
72// Resource tags
73//
74
75static const char CURRENCY_DATA[] = "supplementalData";
76// Tag for meta-data, in root.
77static const char CURRENCY_META[] = "CurrencyMeta";
78
79// Tag for map from countries to currencies, in root.
80static const char CURRENCY_MAP[] = "CurrencyMap";
81
82// Tag for default meta-data, in CURRENCY_META
83static const char DEFAULT_META[] = "DEFAULT";
84
85// Variant for legacy pre-euro mapping in CurrencyMap
86static const char VAR_PRE_EURO[] = "PREEURO";
87
88// Variant for legacy euro mapping in CurrencyMap
89static const char VAR_EURO[] = "EURO";
90
91// Variant delimiter
92static const char VAR_DELIM = '_';
93static const char VAR_DELIM_STR[] = "_";
94
95// Variant for legacy euro mapping in CurrencyMap
96//static const char VAR_DELIM_EURO[] = "_EURO";
97
98#define VARIANT_IS_EMPTY    0
99#define VARIANT_IS_EURO     0x1
100#define VARIANT_IS_PREEURO  0x2
101
102// Tag for localized display names (symbols) of currencies
103static const char CURRENCIES[] = "Currencies";
104static const char CURRENCYPLURALS[] = "CurrencyPlurals";
105
106// Marker character indicating that a display name is a ChoiceFormat
107// pattern.  Strings that start with one mark are ChoiceFormat
108// patterns.  Strings that start with 2 marks are static strings, and
109// the first mark is deleted.
110static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
111
112static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
113
114// ISO codes mapping table
115static const UHashtable* gIsoCodes = NULL;
116static icu::UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER;
117
118// Currency symbol equivalances
119static const icu::Hashtable* gCurrSymbolsEquiv = NULL;
120static icu::UInitOnce gCurrSymbolsEquivInitOnce = U_INITONCE_INITIALIZER;
121
122// EquivIterator iterates over all strings that are equivalent to a given
123// string, s. Note that EquivIterator will never yield s itself.
124class EquivIterator : icu::UMemory {
125public:
126    // Constructor. hash stores the equivalence relationships; s is the string
127    // for which we find equivalent strings.
128    inline EquivIterator(const icu::Hashtable& hash, const icu::UnicodeString& s)
129        : _hash(hash) {
130        _start = _current = &s;
131    }
132    inline ~EquivIterator() { }
133
134    // next returns the next equivalent string or NULL if there are no more.
135    // If s has no equivalent strings, next returns NULL on the first call.
136    const icu::UnicodeString *next();
137private:
138    const icu::Hashtable& _hash;
139    const icu::UnicodeString* _start;
140    const icu::UnicodeString* _current;
141};
142
143const icu::UnicodeString *
144EquivIterator::next() {
145    const icu::UnicodeString* _next = (const icu::UnicodeString*) _hash.get(*_current);
146    if (_next == NULL) {
147        U_ASSERT(_current == _start);
148        return NULL;
149    }
150    if (*_next == *_start) {
151        return NULL;
152    }
153    _current = _next;
154    return _next;
155}
156
157// 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    EquivIterator leftIter(*hash, lhs);
171    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    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    uloc_getCountry(locale, 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        uprv_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH * sizeof(const UChar));
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_i18n_registerCleanup(UCLN_I18N_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_i18n_registerCleanup(UCLN_I18N_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    // Determine if this is a ChoiceFormat pattern.  One leading mark
740    // indicates a ChoiceFormat.  Two indicates a static string that
741    // starts with a mark.  In either case, the first mark is ignored,
742    // if present.  Marks in the rest of the string have no special
743    // meaning.
744    *isChoiceFormat = FALSE;
745    if (U_SUCCESS(ec2)) {
746        U_ASSERT(s != NULL);
747        int32_t i=0;
748        while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
749            ++i;
750        }
751        *isChoiceFormat = (i == 1);
752        if (i != 0) ++s; // Skip over first mark
753        return s;
754    }
755
756    // If we fail to find a match, use the ISO 4217 code
757    *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
758    *ec = U_USING_DEFAULT_WARNING;
759    return currency;
760}
761
762U_CAPI const UChar* U_EXPORT2
763ucurr_getPluralName(const UChar* currency,
764                    const char* locale,
765                    UBool* isChoiceFormat,
766                    const char* pluralCount,
767                    int32_t* len, // fillin
768                    UErrorCode* ec) {
769    // Look up the Currencies resource for the given locale.  The
770    // Currencies locale data looks like this:
771    //|en {
772    //|  CurrencyPlurals {
773    //|    USD{
774    //|      one{"US dollar"}
775    //|      other{"US dollars"}
776    //|    }
777    //|  }
778    //|}
779
780    if (U_FAILURE(*ec)) {
781        return 0;
782    }
783
784    // Use a separate UErrorCode here that does not propagate out of
785    // this function.
786    UErrorCode ec2 = U_ZERO_ERROR;
787
788    char loc[ULOC_FULLNAME_CAPACITY];
789    uloc_getName(locale, loc, sizeof(loc), &ec2);
790    if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
791        *ec = U_ILLEGAL_ARGUMENT_ERROR;
792        return 0;
793    }
794
795    char buf[ISO_CURRENCY_CODE_LENGTH+1];
796    myUCharsToChars(buf, currency);
797
798    const UChar* s = NULL;
799    ec2 = U_ZERO_ERROR;
800    UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
801
802    rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
803
804    // Fetch resource with multi-level resource inheritance fallback
805    rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
806
807    s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
808    if (U_FAILURE(ec2)) {
809        //  fall back to "other"
810        ec2 = U_ZERO_ERROR;
811        s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);
812        if (U_FAILURE(ec2)) {
813            ures_close(rb);
814            // fall back to long name in Currencies
815            return ucurr_getName(currency, locale, UCURR_LONG_NAME,
816                                 isChoiceFormat, len, ec);
817        }
818    }
819    ures_close(rb);
820
821    // If we've succeeded we're done.  Otherwise, try to fallback.
822    // If that fails (because we are already at root) then exit.
823    if (U_SUCCESS(ec2)) {
824        if (ec2 == U_USING_DEFAULT_WARNING
825            || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
826            *ec = ec2;
827        }
828        U_ASSERT(s != NULL);
829        return s;
830    }
831
832    // If we fail to find a match, use the ISO 4217 code
833    *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
834    *ec = U_USING_DEFAULT_WARNING;
835    return currency;
836}
837
838
839//========================================================================
840// Following are structure and function for parsing currency names
841
842#define NEED_TO_BE_DELETED 0x1
843
844// TODO: a better way to define this?
845#define MAX_CURRENCY_NAME_LEN 100
846
847typedef struct {
848    const char* IsoCode;  // key
849    UChar* currencyName;  // value
850    int32_t currencyNameLen;  // value length
851    int32_t flag;  // flags
852} CurrencyNameStruct;
853
854
855#ifndef MIN
856#define MIN(a,b) (((a)<(b)) ? (a) : (b))
857#endif
858
859#ifndef MAX
860#define MAX(a,b) (((a)<(b)) ? (b) : (a))
861#endif
862
863
864// Comparason function used in quick sort.
865static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
866    const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
867    const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
868    for (int32_t i = 0;
869         i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen);
870         ++i) {
871        if (currName_1->currencyName[i] < currName_2->currencyName[i]) {
872            return -1;
873        }
874        if (currName_1->currencyName[i] > currName_2->currencyName[i]) {
875            return 1;
876        }
877    }
878    if (currName_1->currencyNameLen < currName_2->currencyNameLen) {
879        return -1;
880    } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) {
881        return 1;
882    }
883    return 0;
884}
885
886
887// Give a locale, return the maximum number of currency names associated with
888// this locale.
889// It gets currency names from resource bundles using fallback.
890// It is the maximum number because in the fallback chain, some of the
891// currency names are duplicated.
892// For example, given locale as "en_US", the currency names get from resource
893// bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
894// all currency names in "en_US" and "en".
895static void
896getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) {
897    U_NAMESPACE_USE
898    *total_currency_name_count = 0;
899    *total_currency_symbol_count = 0;
900    const UChar* s = NULL;
901    char locale[ULOC_FULLNAME_CAPACITY];
902    uprv_strcpy(locale, loc);
903    const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
904    for (;;) {
905        UErrorCode ec2 = U_ZERO_ERROR;
906        // TODO: ures_openDirect?
907        UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2);
908        UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
909        int32_t n = ures_getSize(curr);
910        for (int32_t i=0; i<n; ++i) {
911            UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
912            int32_t len;
913            s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
914            UBool isChoice = FALSE;
915            if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
916                ++s;
917                --len;
918                if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
919                    isChoice = TRUE;
920                }
921            }
922            if (isChoice) {
923                ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2);
924                int32_t fmt_count;
925                fmt.getFormats(fmt_count);
926                *total_currency_symbol_count += fmt_count;
927            } else {
928                ++(*total_currency_symbol_count);  // currency symbol
929                if (currencySymbolsEquiv != NULL) {
930                    *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
931                }
932            }
933
934            ++(*total_currency_symbol_count); // iso code
935            ++(*total_currency_name_count); // long name
936            ures_close(names);
937        }
938
939        // currency plurals
940        UErrorCode ec3 = U_ZERO_ERROR;
941        UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
942        n = ures_getSize(curr_p);
943        for (int32_t i=0; i<n; ++i) {
944            UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
945            *total_currency_name_count += ures_getSize(names);
946            ures_close(names);
947        }
948        ures_close(curr_p);
949        ures_close(curr);
950        ures_close(rb);
951
952        if (!fallback(locale)) {
953            break;
954        }
955    }
956}
957
958static UChar*
959toUpperCase(const UChar* source, int32_t len, const char* locale) {
960    UChar* dest = NULL;
961    UErrorCode ec = U_ZERO_ERROR;
962    int32_t destLen = u_strToUpper(dest, 0, source, len, locale, &ec);
963
964    ec = U_ZERO_ERROR;
965    dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
966    u_strToUpper(dest, destLen, source, len, locale, &ec);
967    if (U_FAILURE(ec)) {
968        uprv_memcpy(dest, source, sizeof(UChar) * len);
969    }
970    return dest;
971}
972
973
974// Collect all available currency names associated with the given locale
975// (enable fallback chain).
976// Read currenc names defined in resource bundle "Currencies" and
977// "CurrencyPlural", enable fallback chain.
978// return the malloc-ed currency name arrays and the total number of currency
979// names in the array.
980static void
981collectCurrencyNames(const char* locale,
982                     CurrencyNameStruct** currencyNames,
983                     int32_t* total_currency_name_count,
984                     CurrencyNameStruct** currencySymbols,
985                     int32_t* total_currency_symbol_count,
986                     UErrorCode& ec) {
987    U_NAMESPACE_USE
988    const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
989    // Look up the Currencies resource for the given locale.
990    UErrorCode ec2 = U_ZERO_ERROR;
991
992    char loc[ULOC_FULLNAME_CAPACITY];
993    uloc_getName(locale, loc, sizeof(loc), &ec2);
994    if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
995        ec = U_ILLEGAL_ARGUMENT_ERROR;
996    }
997
998    // Get maximum currency name count first.
999    getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
1000
1001    *currencyNames = (CurrencyNameStruct*)uprv_malloc
1002        (sizeof(CurrencyNameStruct) * (*total_currency_name_count));
1003    *currencySymbols = (CurrencyNameStruct*)uprv_malloc
1004        (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
1005
1006    const UChar* s = NULL;  // currency name
1007    char* iso = NULL;  // currency ISO code
1008
1009    *total_currency_name_count = 0;
1010    *total_currency_symbol_count = 0;
1011
1012    UErrorCode ec3 = U_ZERO_ERROR;
1013    UErrorCode ec4 = U_ZERO_ERROR;
1014
1015    // Using hash to remove duplicates caused by locale fallback
1016    UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3);
1017    UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4);
1018    for (int32_t localeLevel = 0; ; ++localeLevel) {
1019        ec2 = U_ZERO_ERROR;
1020        // TODO: ures_openDirect
1021        UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
1022        UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
1023        int32_t n = ures_getSize(curr);
1024        for (int32_t i=0; i<n; ++i) {
1025            UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
1026            int32_t len;
1027            s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
1028            // TODO: uhash_put wont change key/value?
1029            iso = (char*)ures_getKey(names);
1030            if (localeLevel == 0) {
1031                uhash_put(currencyIsoCodes, iso, iso, &ec3);
1032            } else {
1033                if (uhash_get(currencyIsoCodes, iso) != NULL) {
1034                    ures_close(names);
1035                    continue;
1036                } else {
1037                    uhash_put(currencyIsoCodes, iso, iso, &ec3);
1038                }
1039            }
1040            UBool isChoice = FALSE;
1041            if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
1042                ++s;
1043                --len;
1044                if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
1045                    isChoice = TRUE;
1046                }
1047            }
1048            if (isChoice) {
1049                ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2);
1050                int32_t fmt_count;
1051                const UnicodeString* formats = fmt.getFormats(fmt_count);
1052                for (int i = 0; i < fmt_count; ++i) {
1053                    // put iso, formats[i]; into array
1054                    int32_t length = formats[i].length();
1055                    UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length);
1056                    formats[i].extract(0, length, name);
1057                    (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
1058                    (*currencySymbols)[*total_currency_symbol_count].currencyName = name;
1059                    (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
1060                    (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length;
1061                }
1062            } else {
1063                // Add currency symbol.
1064                (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
1065                (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
1066                (*currencySymbols)[*total_currency_symbol_count].flag = 0;
1067                (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
1068                // Add equivalent symbols
1069                if (currencySymbolsEquiv != NULL) {
1070                    EquivIterator iter(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
1071                    const UnicodeString *symbol;
1072                    while ((symbol = iter.next()) != NULL) {
1073                        (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
1074                        (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*) symbol->getBuffer();
1075                        (*currencySymbols)[*total_currency_symbol_count].flag = 0;
1076                        (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = symbol->length();
1077                    }
1078                }
1079            }
1080
1081            // Add currency long name.
1082            s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
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            // put (iso, 3, and iso) in to array
1090            // Add currency ISO code.
1091            (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
1092            (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
1093            // Must convert iso[] into Unicode
1094            u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
1095            (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
1096            (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
1097
1098            ures_close(names);
1099        }
1100
1101        // currency plurals
1102        UErrorCode ec3 = U_ZERO_ERROR;
1103        UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
1104        n = ures_getSize(curr_p);
1105        for (int32_t i=0; i<n; ++i) {
1106            UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
1107            iso = (char*)ures_getKey(names);
1108            // Using hash to remove duplicated ISO codes in fallback chain.
1109            if (localeLevel == 0) {
1110                uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
1111            } else {
1112                if (uhash_get(currencyPluralIsoCodes, iso) != NULL) {
1113                    ures_close(names);
1114                    continue;
1115                } else {
1116                    uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
1117                }
1118            }
1119            int32_t num = ures_getSize(names);
1120            int32_t len;
1121            for (int32_t j = 0; j < num; ++j) {
1122                // TODO: remove duplicates between singular name and
1123                // currency long name?
1124                s = ures_getStringByIndex(names, j, &len, &ec3);
1125                (*currencyNames)[*total_currency_name_count].IsoCode = iso;
1126                UChar* upperName = toUpperCase(s, len, locale);
1127                (*currencyNames)[*total_currency_name_count].currencyName = upperName;
1128                (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
1129                (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
1130            }
1131            ures_close(names);
1132        }
1133        ures_close(curr_p);
1134        ures_close(curr);
1135        ures_close(rb);
1136
1137        if (!fallback(loc)) {
1138            break;
1139        }
1140    }
1141
1142    uhash_close(currencyIsoCodes);
1143    uhash_close(currencyPluralIsoCodes);
1144
1145    // quick sort the struct
1146    qsort(*currencyNames, *total_currency_name_count,
1147          sizeof(CurrencyNameStruct), currencyNameComparator);
1148    qsort(*currencySymbols, *total_currency_symbol_count,
1149          sizeof(CurrencyNameStruct), currencyNameComparator);
1150
1151#ifdef UCURR_DEBUG
1152    printf("currency name count: %d\n", *total_currency_name_count);
1153    for (int32_t index = 0; index < *total_currency_name_count; ++index) {
1154        printf("index: %d\n", index);
1155        printf("iso: %s\n", (*currencyNames)[index].IsoCode);
1156        char curNameBuf[1024];
1157        memset(curNameBuf, 0, 1024);
1158        u_austrncpy(curNameBuf, (*currencyNames)[index].currencyName, (*currencyNames)[index].currencyNameLen);
1159        printf("currencyName: %s\n", curNameBuf);
1160        printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
1161    }
1162    printf("currency symbol count: %d\n", *total_currency_symbol_count);
1163    for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
1164        printf("index: %d\n", index);
1165        printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
1166        char curNameBuf[1024];
1167        memset(curNameBuf, 0, 1024);
1168        u_austrncpy(curNameBuf, (*currencySymbols)[index].currencyName, (*currencySymbols)[index].currencyNameLen);
1169        printf("currencySymbol: %s\n", curNameBuf);
1170        printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
1171    }
1172#endif
1173}
1174
1175// @param  currencyNames: currency names array
1176// @param  indexInCurrencyNames: the index of the character in currency names
1177//         array against which the comparison is done
1178// @param  key: input text char to compare against
1179// @param  begin(IN/OUT): the begin index of matching range in currency names array
1180// @param  end(IN/OUT): the end index of matching range in currency names array.
1181static int32_t
1182binarySearch(const CurrencyNameStruct* currencyNames,
1183             int32_t indexInCurrencyNames,
1184             const UChar key,
1185             int32_t* begin, int32_t* end) {
1186#ifdef UCURR_DEBUG
1187    printf("key = %x\n", key);
1188#endif
1189   int32_t first = *begin;
1190   int32_t last = *end;
1191   while (first <= last) {
1192       int32_t mid = (first + last) / 2;  // compute mid point.
1193       if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) {
1194           first = mid + 1;
1195       } else {
1196           if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) {
1197               first = mid + 1;
1198           }
1199           else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) {
1200               last = mid - 1;
1201           }
1202           else {
1203                // Find a match, and looking for ranges
1204                // Now do two more binary searches. First, on the left side for
1205                // the greatest L such that CurrencyNameStruct[L] < key.
1206                int32_t L = *begin;
1207                int32_t R = mid;
1208
1209#ifdef UCURR_DEBUG
1210                printf("mid = %d\n", mid);
1211#endif
1212                while (L < R) {
1213                    int32_t M = (L + R) / 2;
1214#ifdef UCURR_DEBUG
1215                    printf("L = %d, R = %d, M = %d\n", L, R, M);
1216#endif
1217                    if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) {
1218                        L = M + 1;
1219                    } else {
1220                        if (currencyNames[M].currencyName[indexInCurrencyNames] < key) {
1221                            L = M + 1;
1222                        } else {
1223#ifdef UCURR_DEBUG
1224                            U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
1225#endif
1226                            R = M;
1227                        }
1228                    }
1229                }
1230#ifdef UCURR_DEBUG
1231                U_ASSERT(L == R);
1232#endif
1233                *begin = L;
1234#ifdef UCURR_DEBUG
1235                printf("begin = %d\n", *begin);
1236                U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key);
1237#endif
1238
1239                // Now for the second search, finding the least R such that
1240                // key < CurrencyNameStruct[R].
1241                L = mid;
1242                R = *end;
1243                while (L < R) {
1244                    int32_t M = (L + R) / 2;
1245#ifdef UCURR_DEBUG
1246                    printf("L = %d, R = %d, M = %d\n", L, R, M);
1247#endif
1248                    if (currencyNames[M].currencyNameLen < indexInCurrencyNames) {
1249                        L = M + 1;
1250                    } else {
1251                        if (currencyNames[M].currencyName[indexInCurrencyNames] > key) {
1252                            R = M;
1253                        } else {
1254#ifdef UCURR_DEBUG
1255                            U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
1256#endif
1257                            L = M + 1;
1258                        }
1259                    }
1260                }
1261#ifdef UCURR_DEBUG
1262                U_ASSERT(L == R);
1263#endif
1264                if (currencyNames[R].currencyName[indexInCurrencyNames] > key) {
1265                    *end = R - 1;
1266                } else {
1267                    *end = R;
1268                }
1269#ifdef UCURR_DEBUG
1270                printf("end = %d\n", *end);
1271#endif
1272
1273                // now, found the range. check whether there is exact match
1274                if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) {
1275                    return *begin;  // find range and exact match.
1276                }
1277                return -1;  // find range, but no exact match.
1278           }
1279       }
1280   }
1281   *begin = -1;
1282   *end = -1;
1283   return -1;    // failed to find range.
1284}
1285
1286
1287// Linear search "text" in "currencyNames".
1288// @param  begin, end: the begin and end index in currencyNames, within which
1289//         range should the search be performed.
1290// @param  textLen: the length of the text to be compared
1291// @param  maxMatchLen(IN/OUT): passing in the computed max matching length
1292//                              pass out the new max  matching length
1293// @param  maxMatchIndex: the index in currencyName which has the longest
1294//                        match with input text.
1295static void
1296linearSearch(const CurrencyNameStruct* currencyNames,
1297             int32_t begin, int32_t end,
1298             const UChar* text, int32_t textLen,
1299             int32_t *maxMatchLen, int32_t* maxMatchIndex) {
1300    for (int32_t index = begin; index <= end; ++index) {
1301        int32_t len = currencyNames[index].currencyNameLen;
1302        if (len > *maxMatchLen && len <= textLen &&
1303            uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
1304            *maxMatchIndex = index;
1305            *maxMatchLen = len;
1306#ifdef UCURR_DEBUG
1307            printf("maxMatchIndex = %d, maxMatchLen = %d\n",
1308                   *maxMatchIndex, *maxMatchLen);
1309#endif
1310        }
1311    }
1312}
1313
1314#define LINEAR_SEARCH_THRESHOLD 10
1315
1316// Find longest match between "text" and currency names in "currencyNames".
1317// @param  total_currency_count: total number of currency names in CurrencyNames.
1318// @param  textLen: the length of the text to be compared
1319// @param  maxMatchLen: passing in the computed max matching length
1320//                              pass out the new max  matching length
1321// @param  maxMatchIndex: the index in currencyName which has the longest
1322//                        match with input text.
1323static void
1324searchCurrencyName(const CurrencyNameStruct* currencyNames,
1325                   int32_t total_currency_count,
1326                   const UChar* text, int32_t textLen,
1327                   int32_t* maxMatchLen, int32_t* maxMatchIndex) {
1328    *maxMatchIndex = -1;
1329    *maxMatchLen = 0;
1330    int32_t matchIndex = -1;
1331    int32_t binarySearchBegin = 0;
1332    int32_t binarySearchEnd = total_currency_count - 1;
1333    // It is a variant of binary search.
1334    // For example, given the currency names in currencyNames array are:
1335    // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
1336    // and the input text is BBEXST
1337    // The first round binary search search "B" in the text against
1338    // the first char in currency names, and find the first char matching range
1339    // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
1340    // The 2nd round binary search search the second "B" in the text against
1341    // the 2nd char in currency names, and narrow the matching range to
1342    // "BB BBEX BBEXYZ" (and the maximum matching "BB").
1343    // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
1344    // maximum matching).
1345    // The 4th round returns the same range (the maximum matching is "BBEX").
1346    // The 5th round returns no matching range.
1347    for (int32_t index = 0; index < textLen; ++index) {
1348        // matchIndex saves the one with exact match till the current point.
1349        // [binarySearchBegin, binarySearchEnd] saves the matching range.
1350        matchIndex = binarySearch(currencyNames, index,
1351                                  text[index],
1352                                  &binarySearchBegin, &binarySearchEnd);
1353        if (binarySearchBegin == -1) { // did not find the range
1354            break;
1355        }
1356        if (matchIndex != -1) {
1357            // find an exact match for text from text[0] to text[index]
1358            // in currencyNames array.
1359            *maxMatchLen = index + 1;
1360            *maxMatchIndex = matchIndex;
1361        }
1362        if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
1363            // linear search if within threshold.
1364            linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
1365                         text, textLen,
1366                         maxMatchLen, maxMatchIndex);
1367            break;
1368        }
1369    }
1370    return;
1371}
1372
1373//========================= currency name cache =====================
1374typedef struct {
1375    char locale[ULOC_FULLNAME_CAPACITY];  //key
1376    // currency names, case insensitive
1377    CurrencyNameStruct* currencyNames;  // value
1378    int32_t totalCurrencyNameCount;  // currency name count
1379    // currency symbols and ISO code, case sensitive
1380    CurrencyNameStruct* currencySymbols; // value
1381    int32_t totalCurrencySymbolCount;  // count
1382    // reference count.
1383    // reference count is set to 1 when an entry is put to cache.
1384    // it increases by 1 before accessing, and decreased by 1 after accessing.
1385    // The entry is deleted when ref count is zero, which means
1386    // the entry is replaced out of cache and no process is accessing it.
1387    int32_t refCount;
1388} CurrencyNameCacheEntry;
1389
1390
1391#define CURRENCY_NAME_CACHE_NUM 10
1392
1393// Reserve 10 cache entries.
1394static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
1395// Using an index to indicate which entry to be replaced when cache is full.
1396// It is a simple round-robin replacement strategy.
1397static int8_t currentCacheEntryIndex = 0;
1398
1399static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER;
1400
1401// Cache deletion
1402static void
1403deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
1404    for (int32_t index = 0; index < count; ++index) {
1405        if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) {
1406            uprv_free(currencyNames[index].currencyName);
1407        }
1408    }
1409    uprv_free(currencyNames);
1410}
1411
1412
1413static void
1414deleteCacheEntry(CurrencyNameCacheEntry* entry) {
1415    deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
1416    deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
1417    uprv_free(entry);
1418}
1419
1420
1421// Cache clean up
1422static UBool U_CALLCONV
1423currency_cache_cleanup(void) {
1424    for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1425        if (currCache[i]) {
1426            deleteCacheEntry(currCache[i]);
1427            currCache[i] = 0;
1428        }
1429    }
1430    return TRUE;
1431}
1432
1433
1434U_CFUNC void
1435uprv_parseCurrency(const char* locale,
1436                   const icu::UnicodeString& text,
1437                   icu::ParsePosition& pos,
1438                   int8_t type,
1439                   UChar* result,
1440                   UErrorCode& ec)
1441{
1442    U_NAMESPACE_USE
1443
1444    if (U_FAILURE(ec)) {
1445        return;
1446    }
1447
1448    int32_t total_currency_name_count = 0;
1449    CurrencyNameStruct* currencyNames = NULL;
1450    int32_t total_currency_symbol_count = 0;
1451    CurrencyNameStruct* currencySymbols = NULL;
1452    CurrencyNameCacheEntry* cacheEntry = NULL;
1453
1454    umtx_lock(&gCurrencyCacheMutex);
1455    // in order to handle racing correctly,
1456    // not putting 'search' in a separate function.
1457    int8_t  found = -1;
1458    for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1459        if (currCache[i]!= NULL &&
1460            uprv_strcmp(locale, currCache[i]->locale) == 0) {
1461            found = i;
1462            break;
1463        }
1464    }
1465    if (found != -1) {
1466        cacheEntry = currCache[found];
1467        currencyNames = cacheEntry->currencyNames;
1468        total_currency_name_count = cacheEntry->totalCurrencyNameCount;
1469        currencySymbols = cacheEntry->currencySymbols;
1470        total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
1471        ++(cacheEntry->refCount);
1472    }
1473    umtx_unlock(&gCurrencyCacheMutex);
1474    if (found == -1) {
1475        collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
1476        if (U_FAILURE(ec)) {
1477            return;
1478        }
1479        umtx_lock(&gCurrencyCacheMutex);
1480        // check again.
1481        int8_t  found = -1;
1482        for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1483            if (currCache[i]!= NULL &&
1484                uprv_strcmp(locale, currCache[i]->locale) == 0) {
1485                found = i;
1486                break;
1487            }
1488        }
1489        if (found == -1) {
1490            // insert new entry to
1491            // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1492            // and remove the existing entry
1493            // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1494            // from cache.
1495            cacheEntry = currCache[currentCacheEntryIndex];
1496            if (cacheEntry) {
1497                --(cacheEntry->refCount);
1498                // delete if the ref count is zero
1499                if (cacheEntry->refCount == 0) {
1500                    deleteCacheEntry(cacheEntry);
1501                }
1502            }
1503            cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry));
1504            currCache[currentCacheEntryIndex] = cacheEntry;
1505            uprv_strcpy(cacheEntry->locale, locale);
1506            cacheEntry->currencyNames = currencyNames;
1507            cacheEntry->totalCurrencyNameCount = total_currency_name_count;
1508            cacheEntry->currencySymbols = currencySymbols;
1509            cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
1510            cacheEntry->refCount = 2; // one for cache, one for reference
1511            currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
1512            ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup);
1513
1514        } else {
1515            deleteCurrencyNames(currencyNames, total_currency_name_count);
1516            deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
1517            cacheEntry = currCache[found];
1518            currencyNames = cacheEntry->currencyNames;
1519            total_currency_name_count = cacheEntry->totalCurrencyNameCount;
1520            currencySymbols = cacheEntry->currencySymbols;
1521            total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
1522            ++(cacheEntry->refCount);
1523        }
1524        umtx_unlock(&gCurrencyCacheMutex);
1525    }
1526
1527    int32_t start = pos.getIndex();
1528
1529    UChar inputText[MAX_CURRENCY_NAME_LEN];
1530    UChar upperText[MAX_CURRENCY_NAME_LEN];
1531    int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
1532    text.extract(start, textLen, inputText);
1533    UErrorCode ec1 = U_ZERO_ERROR;
1534    textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, locale, &ec1);
1535
1536    int32_t max = 0;
1537    int32_t matchIndex = -1;
1538    // case in-sensitive comparision against currency names
1539    searchCurrencyName(currencyNames, total_currency_name_count,
1540                       upperText, textLen, &max, &matchIndex);
1541
1542#ifdef UCURR_DEBUG
1543    printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
1544#endif
1545
1546    int32_t maxInSymbol = 0;
1547    int32_t matchIndexInSymbol = -1;
1548    if (type != UCURR_LONG_NAME) {  // not name only
1549        // case sensitive comparison against currency symbols and ISO code.
1550        searchCurrencyName(currencySymbols, total_currency_symbol_count,
1551                           inputText, textLen,
1552                           &maxInSymbol, &matchIndexInSymbol);
1553    }
1554
1555#ifdef UCURR_DEBUG
1556    printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
1557    if(matchIndexInSymbol != -1) {
1558      printf("== ISO=%s\n", currencySymbols[matchIndexInSymbol].IsoCode);
1559    }
1560#endif
1561
1562    if (max >= maxInSymbol && matchIndex != -1) {
1563        u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
1564        pos.setIndex(start + max);
1565    } else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
1566        u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
1567        pos.setIndex(start + maxInSymbol);
1568    }
1569
1570    // decrease reference count
1571    umtx_lock(&gCurrencyCacheMutex);
1572    --(cacheEntry->refCount);
1573    if (cacheEntry->refCount == 0) {  // remove
1574        deleteCacheEntry(cacheEntry);
1575    }
1576    umtx_unlock(&gCurrencyCacheMutex);
1577}
1578
1579
1580/**
1581 * Internal method.  Given a currency ISO code and a locale, return
1582 * the "static" currency name.  This is usually the same as the
1583 * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
1584 * format is applied to the number 2.0 (to yield the more common
1585 * plural) to return a static name.
1586 *
1587 * This is used for backward compatibility with old currency logic in
1588 * DecimalFormat and DecimalFormatSymbols.
1589 */
1590U_CFUNC void
1591uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
1592                           icu::UnicodeString& result, UErrorCode& ec)
1593{
1594    U_NAMESPACE_USE
1595
1596    UBool isChoiceFormat;
1597    int32_t len;
1598    const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
1599                                          &isChoiceFormat, &len, &ec);
1600    if (U_SUCCESS(ec)) {
1601        // If this is a ChoiceFormat currency, then format an
1602        // arbitrary value; pick something != 1; more common.
1603        result.truncate(0);
1604        if (isChoiceFormat) {
1605            ChoiceFormat f(UnicodeString(TRUE, currname, len), ec);
1606            if (U_SUCCESS(ec)) {
1607                f.format(2.0, result);
1608            } else {
1609                result.setTo(iso, -1);
1610            }
1611        } else {
1612            result.setTo(currname, -1);
1613        }
1614    }
1615}
1616
1617U_CAPI int32_t U_EXPORT2
1618ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
1619    return (_findMetaData(currency, *ec))[0];
1620}
1621
1622U_CAPI double U_EXPORT2
1623ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
1624    const int32_t *data = _findMetaData(currency, *ec);
1625
1626    // If the meta data is invalid, return 0.0.
1627    if (data[0] < 0 || data[0] > MAX_POW10) {
1628        if (U_SUCCESS(*ec)) {
1629            *ec = U_INVALID_FORMAT_ERROR;
1630        }
1631        return 0.0;
1632    }
1633
1634    // If there is no rounding, return 0.0 to indicate no rounding.  A
1635    // rounding value (data[1]) of 0 or 1 indicates no rounding.
1636    if (data[1] < 2) {
1637        return 0.0;
1638    }
1639
1640    // Return data[1] / 10^(data[0]).  The only actual rounding data,
1641    // as of this writing, is CHF { 2, 5 }.
1642    return double(data[1]) / POW10[data[0]];
1643}
1644
1645U_CDECL_BEGIN
1646
1647typedef struct UCurrencyContext {
1648    uint32_t currType; /* UCurrCurrencyType */
1649    uint32_t listIdx;
1650} UCurrencyContext;
1651
1652/*
1653Please keep this list in alphabetical order.
1654You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
1655of these items.
1656ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
1657*/
1658static const struct CurrencyList {
1659    const char *currency;
1660    uint32_t currType;
1661} gCurrencyList[] = {
1662    {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
1663    {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
1664    {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
1665    {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1666    {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
1667    {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1668    {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1669    {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1670    {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
1671    {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
1672    {"AON", UCURR_COMMON|UCURR_DEPRECATED},
1673    {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
1674    {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
1675    {"ARL", UCURR_COMMON|UCURR_DEPRECATED},
1676    {"ARM", UCURR_COMMON|UCURR_DEPRECATED},
1677    {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
1678    {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1679    {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
1680    {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1681    {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1682    {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
1683    {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1684    {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
1685    {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
1686    {"BAN", UCURR_COMMON|UCURR_DEPRECATED},
1687    {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1688    {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1689    {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
1690    {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
1691    {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
1692    {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
1693    {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
1694    {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1695    {"BGO", UCURR_COMMON|UCURR_DEPRECATED},
1696    {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1697    {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1698    {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1699    {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1700    {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1701    {"BOL", UCURR_COMMON|UCURR_DEPRECATED},
1702    {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
1703    {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1704    {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
1705    {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
1706    {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
1707    {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1708    {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
1709    {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
1710    {"BRZ", UCURR_COMMON|UCURR_DEPRECATED},
1711    {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1712    {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1713    {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
1714    {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1715    {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
1716    {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1717    {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1718    {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1719    {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1720    {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1721    {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1722    {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1723    {"CLE", UCURR_COMMON|UCURR_DEPRECATED},
1724    {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1725    {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1726    {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
1727    {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1728    {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1729    {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1730    {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
1731    {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
1732    {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
1733    {"CUC", UCURR_COMMON|UCURR_NON_DEPRECATED},
1734    {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1735    {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
1736    {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
1737    {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1738    {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
1739    {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
1740    {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1741    {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1742    {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1743    {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1744    {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
1745    {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
1746    {"EEK", UCURR_COMMON|UCURR_DEPRECATED},
1747    {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1748    {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
1749    {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1750    {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
1751    {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
1752    {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
1753    {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1754    {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1755    {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
1756    {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1757    {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1758    {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
1759    {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1760    {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
1761    {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1762    {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
1763    {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1764    {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1765    {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1766    {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1767    {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
1768    {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
1769    {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
1770    {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
1771    {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
1772    {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1773    {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1774    {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1775    {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1776    {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
1777    {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1778    {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1779    {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1780    {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1781    {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
1782    {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
1783    {"ILR", UCURR_COMMON|UCURR_DEPRECATED},
1784    {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1785    {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1786    {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1787    {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1788    {"ISJ", UCURR_COMMON|UCURR_DEPRECATED},
1789    {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1790    {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
1791    {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1792    {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1793    {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1794    {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
1795    {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1796    {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1797    {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1798    {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
1799    {"KRH", UCURR_COMMON|UCURR_DEPRECATED},
1800    {"KRO", UCURR_COMMON|UCURR_DEPRECATED},
1801    {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
1802    {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1803    {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1804    {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1805    {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1806    {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1807    {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1808    {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1809    {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1810    {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
1811    {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1812    {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
1813    {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
1814    {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
1815    {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
1816    {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1817    {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
1818    {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1819    {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1820    {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
1821    {"MCF", UCURR_COMMON|UCURR_DEPRECATED},
1822    {"MDC", UCURR_COMMON|UCURR_DEPRECATED},
1823    {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1824    {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
1825    {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
1826    {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1827    {"MKN", UCURR_COMMON|UCURR_DEPRECATED},
1828    {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
1829    {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1830    {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1831    {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1832    {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
1833    {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
1834    {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
1835    {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1836    {"MVP", UCURR_COMMON|UCURR_DEPRECATED},
1837    {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1838    {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1839    {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1840    {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
1841    {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1842    {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1843    {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
1844    {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
1845    {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1846    {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1847    {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1848    {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
1849    {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
1850    {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
1851    {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1852    {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1853    {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1854    {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1855    {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1856    {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
1857    {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1858    {"PES", UCURR_COMMON|UCURR_DEPRECATED},
1859    {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1860    {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1861    {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1862    {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1863    {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
1864    {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
1865    {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1866    {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1867    {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
1868    {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
1869    {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
1870    {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1871    {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1872    {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
1873    {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1874    {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1875    {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1876    {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1877    {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
1878    {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1879    {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
1880    {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1881    {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1882    {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1883    {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
1884    {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1885    {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1886    {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1887    {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1888    {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
1889    {"SSP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1890    {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1891    {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
1892    {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
1893    {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1894    {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1895    {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1896    {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
1897    {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1898    {"TMM", UCURR_COMMON|UCURR_DEPRECATED},
1899    {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1900    {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1901    {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1902    {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
1903    {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
1904    {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1905    {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1906    {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1907    {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1908    {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
1909    {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
1910    {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
1911    {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
1912    {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1913    {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1914    {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1915    {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1916    {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
1917    {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
1918    {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1919    {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
1920    {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1921    {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1922    {"VNN", UCURR_COMMON|UCURR_DEPRECATED},
1923    {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
1924    {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
1925    {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1926    {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1927    {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1928    {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1929    {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1930    {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1931    {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1932    {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1933    {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1934    {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
1935    {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1936    {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1937    {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1938    {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1939    {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1940    {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1941    {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1942    {"XSU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1943    {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1944    {"XUA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1945    {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1946    {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
1947    {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
1948    {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
1949    {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
1950    {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
1951    {"YUR", UCURR_COMMON|UCURR_DEPRECATED},
1952    {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1953    {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1954    {"ZMK", UCURR_COMMON|UCURR_DEPRECATED},
1955    {"ZMW", UCURR_COMMON|UCURR_NON_DEPRECATED},
1956    {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
1957    {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
1958    {"ZWL", UCURR_COMMON|UCURR_DEPRECATED},
1959    {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
1960    {"ZWD", UCURR_COMMON|UCURR_DEPRECATED},
1961    { NULL, 0 } // Leave here to denote the end of the list.
1962};
1963
1964#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
1965    ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
1966
1967static int32_t U_CALLCONV
1968ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1969    UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1970    uint32_t currType = myContext->currType;
1971    int32_t count = 0;
1972
1973    /* Count the number of items matching the type we are looking for. */
1974    for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
1975        if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
1976            count++;
1977        }
1978    }
1979    return count;
1980}
1981
1982static const char* U_CALLCONV
1983ucurr_nextCurrencyList(UEnumeration *enumerator,
1984                        int32_t* resultLength,
1985                        UErrorCode * /*pErrorCode*/)
1986{
1987    UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1988
1989    /* Find the next in the list that matches the type we are looking for. */
1990    while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
1991        const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
1992        if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
1993        {
1994            if (resultLength) {
1995                *resultLength = 3; /* Currency codes are only 3 chars long */
1996            }
1997            return currItem->currency;
1998        }
1999    }
2000    /* We enumerated too far. */
2001    if (resultLength) {
2002        *resultLength = 0;
2003    }
2004    return NULL;
2005}
2006
2007static void U_CALLCONV
2008ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
2009    ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
2010}
2011
2012static void U_CALLCONV
2013ucurr_closeCurrencyList(UEnumeration *enumerator) {
2014    uprv_free(enumerator->context);
2015    uprv_free(enumerator);
2016}
2017
2018static void U_CALLCONV
2019ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){
2020    UErrorCode localStatus = U_ZERO_ERROR;
2021
2022    // Look up the CurrencyMap element in the root bundle.
2023    UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
2024    UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
2025
2026    if (U_SUCCESS(localStatus)) {
2027        // process each entry in currency map
2028        for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) {
2029            // get the currency resource
2030            UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus);
2031            // process each currency
2032            if (U_SUCCESS(localStatus)) {
2033                for (int32_t j=0; j<ures_getSize(currencyArray); j++) {
2034                    // get the currency resource
2035                    UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus);
2036                    IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry));
2037                    if (entry == NULL) {
2038                        *status = U_MEMORY_ALLOCATION_ERROR;
2039                        return;
2040                    }
2041
2042                    // get the ISO code
2043                    int32_t isoLength = 0;
2044                    UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus);
2045                    if (idRes == NULL) {
2046                        continue;
2047                    }
2048                    const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus);
2049
2050                    // get from date
2051                    UDate fromDate = U_DATE_MIN;
2052                    UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
2053
2054                    if (U_SUCCESS(localStatus)) {
2055                        int32_t fromLength = 0;
2056                        const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
2057                        int64_t currDate64 = (int64_t)fromArray[0] << 32;
2058                        currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2059                        fromDate = (UDate)currDate64;
2060                    }
2061                    ures_close(fromRes);
2062
2063                    // get to date
2064                    UDate toDate = U_DATE_MAX;
2065                    localStatus = U_ZERO_ERROR;
2066                    UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
2067
2068                    if (U_SUCCESS(localStatus)) {
2069                        int32_t toLength = 0;
2070                        const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
2071                        int64_t currDate64 = (int64_t)toArray[0] << 32;
2072                        currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2073                        toDate = (UDate)currDate64;
2074                    }
2075                    ures_close(toRes);
2076
2077                    ures_close(idRes);
2078                    ures_close(currencyRes);
2079
2080                    entry->isoCode = isoCode;
2081                    entry->from = fromDate;
2082                    entry->to = toDate;
2083
2084                    localStatus = U_ZERO_ERROR;
2085                    uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus);
2086                }
2087            } else {
2088                *status = localStatus;
2089            }
2090            ures_close(currencyArray);
2091        }
2092    } else {
2093        *status = localStatus;
2094    }
2095
2096    ures_close(currencyMapArray);
2097}
2098
2099static const UEnumeration gEnumCurrencyList = {
2100    NULL,
2101    NULL,
2102    ucurr_closeCurrencyList,
2103    ucurr_countCurrencyList,
2104    uenum_unextDefault,
2105    ucurr_nextCurrencyList,
2106    ucurr_resetCurrencyList
2107};
2108U_CDECL_END
2109
2110
2111static void U_CALLCONV initIsoCodes(UErrorCode &status) {
2112    U_ASSERT(gIsoCodes == NULL);
2113    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
2114
2115    UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
2116    if (U_FAILURE(status)) {
2117        return;
2118    }
2119    uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry);
2120
2121    ucurr_createCurrencyList(isoCodes, &status);
2122    if (U_FAILURE(status)) {
2123        uhash_close(isoCodes);
2124        return;
2125    }
2126    gIsoCodes = isoCodes;  // Note: gIsoCodes is const. Once set up here it is never altered,
2127                           //       and read only access is safe without synchronization.
2128}
2129
2130static void populateCurrSymbolsEquiv(icu::Hashtable *hash, UErrorCode &status) {
2131    if (U_FAILURE(status)) {
2132        return;
2133    }
2134    int32_t length = sizeof(EQUIV_CURRENCY_SYMBOLS) / sizeof(EQUIV_CURRENCY_SYMBOLS[0]);
2135    for (int32_t i = 0; i < length; ++i) {
2136        icu::UnicodeString lhs(EQUIV_CURRENCY_SYMBOLS[i][0], -1, US_INV);
2137        icu::UnicodeString rhs(EQUIV_CURRENCY_SYMBOLS[i][1], -1, US_INV);
2138        makeEquivalent(lhs.unescape(), rhs.unescape(), hash, status);
2139        if (U_FAILURE(status)) {
2140            return;
2141        }
2142    }
2143}
2144
2145static void U_CALLCONV initCurrSymbolsEquiv() {
2146    U_ASSERT(gCurrSymbolsEquiv == NULL);
2147    UErrorCode status = U_ZERO_ERROR;
2148    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
2149    icu::Hashtable *temp = new icu::Hashtable(status);
2150    if (temp == NULL) {
2151        return;
2152    }
2153    if (U_FAILURE(status)) {
2154        delete temp;
2155        return;
2156    }
2157    temp->setValueDeleter(deleteUnicode);
2158    populateCurrSymbolsEquiv(temp, status);
2159    if (U_FAILURE(status)) {
2160        delete temp;
2161        return;
2162    }
2163    gCurrSymbolsEquiv = temp;
2164}
2165
2166U_CAPI UBool U_EXPORT2
2167ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
2168    umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
2169    if (U_FAILURE(*eErrorCode)) {
2170        return FALSE;
2171    }
2172
2173    IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
2174    if (result == NULL) {
2175        return FALSE;
2176    } else if (from > to) {
2177        *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
2178        return FALSE;
2179    } else if  ((from > result->to) || (to < result->from)) {
2180        return FALSE;
2181    }
2182    return TRUE;
2183}
2184
2185static const icu::Hashtable* getCurrSymbolsEquiv() {
2186    umtx_initOnce(gCurrSymbolsEquivInitOnce, &initCurrSymbolsEquiv);
2187    return gCurrSymbolsEquiv;
2188}
2189
2190U_CAPI UEnumeration * U_EXPORT2
2191ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
2192    UEnumeration *myEnum = NULL;
2193    UCurrencyContext *myContext;
2194
2195    myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
2196    if (myEnum == NULL) {
2197        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
2198        return NULL;
2199    }
2200    uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
2201    myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
2202    if (myContext == NULL) {
2203        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
2204        uprv_free(myEnum);
2205        return NULL;
2206    }
2207    myContext->currType = currType;
2208    myContext->listIdx = 0;
2209    myEnum->context = myContext;
2210    return myEnum;
2211}
2212
2213U_CAPI int32_t U_EXPORT2
2214ucurr_countCurrencies(const char* locale,
2215                 UDate date,
2216                 UErrorCode* ec)
2217{
2218    int32_t currCount = 0;
2219
2220    if (ec != NULL && U_SUCCESS(*ec))
2221    {
2222        // local variables
2223        UErrorCode localStatus = U_ZERO_ERROR;
2224        char id[ULOC_FULLNAME_CAPACITY];
2225        uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
2226        // get country or country_variant in `id'
2227        /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
2228
2229        if (U_FAILURE(*ec))
2230        {
2231            return 0;
2232        }
2233
2234        // Remove variants, which is only needed for registration.
2235        char *idDelim = strchr(id, VAR_DELIM);
2236        if (idDelim)
2237        {
2238            idDelim[0] = 0;
2239        }
2240
2241        // Look up the CurrencyMap element in the root bundle.
2242        UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
2243        UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
2244
2245        // Using the id derived from the local, get the currency data
2246        UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
2247
2248        // process each currency to see which one is valid for the given date
2249        if (U_SUCCESS(localStatus))
2250        {
2251            for (int32_t i=0; i<ures_getSize(countryArray); i++)
2252            {
2253                // get the currency resource
2254                UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
2255
2256                // get the from date
2257                int32_t fromLength = 0;
2258                UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
2259                const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
2260
2261                int64_t currDate64 = (int64_t)fromArray[0] << 32;
2262                currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2263                UDate fromDate = (UDate)currDate64;
2264
2265                if (ures_getSize(currencyRes)> 2)
2266                {
2267                    int32_t toLength = 0;
2268                    UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
2269                    const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
2270
2271                    currDate64 = (int64_t)toArray[0] << 32;
2272                    currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2273                    UDate toDate = (UDate)currDate64;
2274
2275                    if ((fromDate <= date) && (date < toDate))
2276                    {
2277                        currCount++;
2278                    }
2279
2280                    ures_close(toRes);
2281                }
2282                else
2283                {
2284                    if (fromDate <= date)
2285                    {
2286                        currCount++;
2287                    }
2288                }
2289
2290                // close open resources
2291                ures_close(currencyRes);
2292                ures_close(fromRes);
2293
2294            } // end For loop
2295        } // end if (U_SUCCESS(localStatus))
2296
2297        ures_close(countryArray);
2298
2299        // Check for errors
2300        if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
2301        {
2302            // There is nothing to fallback to.
2303            // Report the failure/warning if possible.
2304            *ec = localStatus;
2305        }
2306
2307        if (U_SUCCESS(*ec))
2308        {
2309            // no errors
2310            return currCount;
2311        }
2312
2313    }
2314
2315    // If we got here, either error code is invalid or
2316    // some argument passed is no good.
2317    return 0;
2318}
2319
2320U_CAPI int32_t U_EXPORT2
2321ucurr_forLocaleAndDate(const char* locale,
2322                UDate date,
2323                int32_t index,
2324                UChar* buff,
2325                int32_t buffCapacity,
2326                UErrorCode* ec)
2327{
2328    int32_t resLen = 0;
2329	int32_t currIndex = 0;
2330    const UChar* s = NULL;
2331
2332    if (ec != NULL && U_SUCCESS(*ec))
2333    {
2334        // check the arguments passed
2335        if ((buff && buffCapacity) || !buffCapacity )
2336        {
2337            // local variables
2338            UErrorCode localStatus = U_ZERO_ERROR;
2339            char id[ULOC_FULLNAME_CAPACITY];
2340            resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
2341
2342            // get country or country_variant in `id'
2343            /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
2344            if (U_FAILURE(*ec))
2345            {
2346                return 0;
2347            }
2348
2349            // Remove variants, which is only needed for registration.
2350            char *idDelim = strchr(id, VAR_DELIM);
2351            if (idDelim)
2352            {
2353                idDelim[0] = 0;
2354            }
2355
2356            // Look up the CurrencyMap element in the root bundle.
2357            UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
2358            UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
2359
2360            // Using the id derived from the local, get the currency data
2361            UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
2362
2363            // process each currency to see which one is valid for the given date
2364            bool matchFound = false;
2365            if (U_SUCCESS(localStatus))
2366            {
2367                if ((index <= 0) || (index> ures_getSize(countryArray)))
2368                {
2369                    // requested index is out of bounds
2370                    ures_close(countryArray);
2371                    return 0;
2372                }
2373
2374                for (int32_t i=0; i<ures_getSize(countryArray); i++)
2375                {
2376                    // get the currency resource
2377                    UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
2378                    s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
2379
2380                    // get the from date
2381                    int32_t fromLength = 0;
2382                    UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
2383                    const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
2384
2385                    int64_t currDate64 = (int64_t)fromArray[0] << 32;
2386                    currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2387                    UDate fromDate = (UDate)currDate64;
2388
2389                    if (ures_getSize(currencyRes)> 2)
2390                    {
2391                        int32_t toLength = 0;
2392                        UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
2393                        const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
2394
2395                        currDate64 = (int64_t)toArray[0] << 32;
2396                        currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2397                        UDate toDate = (UDate)currDate64;
2398
2399                        if ((fromDate <= date) && (date < toDate))
2400                        {
2401                            currIndex++;
2402                            if (currIndex == index)
2403                            {
2404                                matchFound = true;
2405                            }
2406                        }
2407
2408                        ures_close(toRes);
2409                    }
2410                    else
2411                    {
2412                        if (fromDate <= date)
2413                        {
2414                            currIndex++;
2415                            if (currIndex == index)
2416                            {
2417                                matchFound = true;
2418                            }
2419                        }
2420                    }
2421
2422                    // close open resources
2423                    ures_close(currencyRes);
2424                    ures_close(fromRes);
2425
2426                    // check for loop exit
2427                    if (matchFound)
2428                    {
2429                        break;
2430                    }
2431
2432                } // end For loop
2433            }
2434
2435            ures_close(countryArray);
2436
2437            // Check for errors
2438            if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
2439            {
2440                // There is nothing to fallback to.
2441                // Report the failure/warning if possible.
2442                *ec = localStatus;
2443            }
2444
2445            if (U_SUCCESS(*ec))
2446            {
2447                // no errors
2448                if((buffCapacity> resLen) && matchFound)
2449                {
2450                    // write out the currency value
2451                    u_strcpy(buff, s);
2452                }
2453                else
2454                {
2455                    return 0;
2456                }
2457            }
2458
2459            // return null terminated currency string
2460            return u_terminateUChars(buff, buffCapacity, resLen, ec);
2461        }
2462        else
2463        {
2464            // illegal argument encountered
2465            *ec = U_ILLEGAL_ARGUMENT_ERROR;
2466        }
2467
2468    }
2469
2470    // If we got here, either error code is invalid or
2471    // some argument passed is no good.
2472    return resLen;
2473}
2474
2475static const UEnumeration defaultKeywordValues = {
2476    NULL,
2477    NULL,
2478    ulist_close_keyword_values_iterator,
2479    ulist_count_keyword_values,
2480    uenum_unextDefault,
2481    ulist_next_keyword_value,
2482    ulist_reset_keyword_values_iterator
2483};
2484
2485U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
2486    // Resolve region
2487    char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
2488    int32_t prefRegionLength = 0;
2489    prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
2490    if (prefRegionLength == 0) {
2491        char loc[ULOC_FULLNAME_CAPACITY] = "";
2492        uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
2493
2494        prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
2495    }
2496
2497    // Read value from supplementalData
2498    UList *values = ulist_createEmptyList(status);
2499    UList *otherValues = ulist_createEmptyList(status);
2500    UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
2501    if (U_FAILURE(*status) || en == NULL) {
2502        if (en == NULL) {
2503            *status = U_MEMORY_ALLOCATION_ERROR;
2504        } else {
2505            uprv_free(en);
2506        }
2507        ulist_deleteList(values);
2508        ulist_deleteList(otherValues);
2509        return NULL;
2510    }
2511    memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
2512    en->context = values;
2513
2514    UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
2515    ures_getByKey(bundle, "CurrencyMap", bundle, status);
2516    UResourceBundle bundlekey, regbndl, curbndl, to;
2517    ures_initStackObject(&bundlekey);
2518    ures_initStackObject(&regbndl);
2519    ures_initStackObject(&curbndl);
2520    ures_initStackObject(&to);
2521
2522    while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
2523        ures_getNextResource(bundle, &bundlekey, status);
2524        if (U_FAILURE(*status)) {
2525            break;
2526        }
2527        const char *region = ures_getKey(&bundlekey);
2528        UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
2529        if (!isPrefRegion && commonlyUsed) {
2530            // With commonlyUsed=true, we do not put
2531            // currencies for other regions in the
2532            // result list.
2533            continue;
2534        }
2535        ures_getByKey(bundle, region, &regbndl, status);
2536        if (U_FAILURE(*status)) {
2537            break;
2538        }
2539        while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
2540            ures_getNextResource(&regbndl, &curbndl, status);
2541            if (ures_getType(&curbndl) != URES_TABLE) {
2542                // Currently, an empty ARRAY is mixed in.
2543                continue;
2544            }
2545            char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
2546            int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
2547            if (curID == NULL) {
2548                *status = U_MEMORY_ALLOCATION_ERROR;
2549                break;
2550            }
2551
2552#if U_CHARSET_FAMILY==U_ASCII_FAMILY
2553            ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
2554            /* optimize - use the utf-8 string */
2555#else
2556            {
2557                       const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
2558                       if(U_SUCCESS(*status)) {
2559			   if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
2560				*status = U_BUFFER_OVERFLOW_ERROR;
2561			   } else {
2562                           	u_UCharsToChars(defString, curID, curIDLength+1);
2563			   }
2564                       }
2565            }
2566#endif
2567
2568            if (U_FAILURE(*status)) {
2569                break;
2570            }
2571            UBool hasTo = FALSE;
2572            ures_getByKey(&curbndl, "to", &to, status);
2573            if (U_FAILURE(*status)) {
2574                // Do nothing here...
2575                *status = U_ZERO_ERROR;
2576            } else {
2577                hasTo = TRUE;
2578            }
2579            if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
2580                // Currently active currency for the target country
2581                ulist_addItemEndList(values, curID, TRUE, status);
2582            } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
2583                ulist_addItemEndList(otherValues, curID, TRUE, status);
2584            } else {
2585                uprv_free(curID);
2586            }
2587        }
2588
2589    }
2590    if (U_SUCCESS(*status)) {
2591        if (commonlyUsed) {
2592            if (ulist_getListSize(values) == 0) {
2593                // This could happen if no valid region is supplied in the input
2594                // locale. In this case, we use the CLDR's default.
2595                uenum_close(en);
2596                en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
2597            }
2598        } else {
2599            // Consolidate the list
2600            char *value = NULL;
2601            ulist_resetList(otherValues);
2602            while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
2603                if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
2604                    char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
2605                    uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
2606                    ulist_addItemEndList(values, tmpValue, TRUE, status);
2607                    if (U_FAILURE(*status)) {
2608                        break;
2609                    }
2610                }
2611            }
2612        }
2613
2614        ulist_resetList((UList *)(en->context));
2615    } else {
2616        ulist_deleteList(values);
2617        uprv_free(en);
2618        values = NULL;
2619        en = NULL;
2620    }
2621    ures_close(&to);
2622    ures_close(&curbndl);
2623    ures_close(&regbndl);
2624    ures_close(&bundlekey);
2625    ures_close(bundle);
2626
2627    ulist_deleteList(otherValues);
2628
2629    return en;
2630}
2631
2632
2633U_CAPI int32_t U_EXPORT2
2634ucurr_getNumericCode(const UChar* currency) {
2635    int32_t code = 0;
2636    if (currency && u_strlen(currency) == ISO_CURRENCY_CODE_LENGTH) {
2637        UErrorCode status = U_ZERO_ERROR;
2638
2639        UResourceBundle *bundle = ures_openDirect(0, "currencyNumericCodes", &status);
2640        ures_getByKey(bundle, "codeMap", bundle, &status);
2641        if (U_SUCCESS(status)) {
2642            char alphaCode[ISO_CURRENCY_CODE_LENGTH+1];
2643            myUCharsToChars(alphaCode, currency);
2644            T_CString_toUpperCase(alphaCode);
2645            ures_getByKey(bundle, alphaCode, bundle, &status);
2646            int tmpCode = ures_getInt(bundle, &status);
2647            if (U_SUCCESS(status)) {
2648                code = tmpCode;
2649            }
2650        }
2651        ures_close(bundle);
2652    }
2653    return code;
2654}
2655#endif /* #if !UCONFIG_NO_FORMATTING */
2656
2657//eof
2658