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