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