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