1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/ucurr.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2657 @@ 1.4 +/* 1.5 +********************************************************************** 1.6 +* Copyright (c) 2002-2013, International Business Machines 1.7 +* Corporation and others. All Rights Reserved. 1.8 +********************************************************************** 1.9 +*/ 1.10 + 1.11 +#include "unicode/utypes.h" 1.12 + 1.13 +#if !UCONFIG_NO_FORMATTING 1.14 + 1.15 +#include "unicode/ucurr.h" 1.16 +#include "unicode/locid.h" 1.17 +#include "unicode/ures.h" 1.18 +#include "unicode/ustring.h" 1.19 +#include "unicode/choicfmt.h" 1.20 +#include "unicode/parsepos.h" 1.21 +#include "ustr_imp.h" 1.22 +#include "cmemory.h" 1.23 +#include "cstring.h" 1.24 +#include "uassert.h" 1.25 +#include "umutex.h" 1.26 +#include "ucln_in.h" 1.27 +#include "uenumimp.h" 1.28 +#include "uhash.h" 1.29 +#include "hash.h" 1.30 +#include "uresimp.h" 1.31 +#include "ulist.h" 1.32 +#include "ureslocs.h" 1.33 + 1.34 +//#define UCURR_DEBUG_EQUIV 1 1.35 +#ifdef UCURR_DEBUG_EQUIV 1.36 +#include "stdio.h" 1.37 +#endif 1.38 +//#define UCURR_DEBUG 1 1.39 +#ifdef UCURR_DEBUG 1.40 +#include "stdio.h" 1.41 +#endif 1.42 + 1.43 +typedef struct IsoCodeEntry { 1.44 + const UChar *isoCode; /* const because it's a reference to a resource bundle string. */ 1.45 + UDate from; 1.46 + UDate to; 1.47 +} IsoCodeEntry; 1.48 + 1.49 +//------------------------------------------------------------ 1.50 +// Constants 1.51 + 1.52 +// Default currency meta data of last resort. We try to use the 1.53 +// defaults encoded in the meta data resource bundle. If there is a 1.54 +// configuration/build error and these are not available, we use these 1.55 +// hard-coded defaults (which should be identical). 1.56 +static const int32_t LAST_RESORT_DATA[] = { 2, 0, 2, 0 }; 1.57 + 1.58 +// POW10[i] = 10^i, i=0..MAX_POW10 1.59 +static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000, 1.60 + 1000000, 10000000, 100000000, 1000000000 }; 1.61 + 1.62 +static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1; 1.63 + 1.64 +// Defines equivalent currency symbols. 1.65 +static const char *EQUIV_CURRENCY_SYMBOLS[][2] = { 1.66 + {"\\u00a5", "\\uffe5"}, 1.67 + {"$", "\\ufe69"}, 1.68 + {"$", "\\uff04"}, 1.69 + {"\\u20a8", "\\u20b9"}, 1.70 + {"\\u00a3", "\\u20a4"}}; 1.71 + 1.72 +#define ISO_CURRENCY_CODE_LENGTH 3 1.73 + 1.74 +//------------------------------------------------------------ 1.75 +// Resource tags 1.76 +// 1.77 + 1.78 +static const char CURRENCY_DATA[] = "supplementalData"; 1.79 +// Tag for meta-data, in root. 1.80 +static const char CURRENCY_META[] = "CurrencyMeta"; 1.81 + 1.82 +// Tag for map from countries to currencies, in root. 1.83 +static const char CURRENCY_MAP[] = "CurrencyMap"; 1.84 + 1.85 +// Tag for default meta-data, in CURRENCY_META 1.86 +static const char DEFAULT_META[] = "DEFAULT"; 1.87 + 1.88 +// Variant for legacy pre-euro mapping in CurrencyMap 1.89 +static const char VAR_PRE_EURO[] = "PREEURO"; 1.90 + 1.91 +// Variant for legacy euro mapping in CurrencyMap 1.92 +static const char VAR_EURO[] = "EURO"; 1.93 + 1.94 +// Variant delimiter 1.95 +static const char VAR_DELIM = '_'; 1.96 +static const char VAR_DELIM_STR[] = "_"; 1.97 + 1.98 +// Variant for legacy euro mapping in CurrencyMap 1.99 +//static const char VAR_DELIM_EURO[] = "_EURO"; 1.100 + 1.101 +#define VARIANT_IS_EMPTY 0 1.102 +#define VARIANT_IS_EURO 0x1 1.103 +#define VARIANT_IS_PREEURO 0x2 1.104 + 1.105 +// Tag for localized display names (symbols) of currencies 1.106 +static const char CURRENCIES[] = "Currencies"; 1.107 +static const char CURRENCYPLURALS[] = "CurrencyPlurals"; 1.108 + 1.109 +// Marker character indicating that a display name is a ChoiceFormat 1.110 +// pattern. Strings that start with one mark are ChoiceFormat 1.111 +// patterns. Strings that start with 2 marks are static strings, and 1.112 +// the first mark is deleted. 1.113 +static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign 1.114 + 1.115 +static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0}; 1.116 + 1.117 +// ISO codes mapping table 1.118 +static const UHashtable* gIsoCodes = NULL; 1.119 +static icu::UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER; 1.120 + 1.121 +// Currency symbol equivalances 1.122 +static const icu::Hashtable* gCurrSymbolsEquiv = NULL; 1.123 +static icu::UInitOnce gCurrSymbolsEquivInitOnce = U_INITONCE_INITIALIZER; 1.124 + 1.125 +// EquivIterator iterates over all strings that are equivalent to a given 1.126 +// string, s. Note that EquivIterator will never yield s itself. 1.127 +class EquivIterator : icu::UMemory { 1.128 +public: 1.129 + // Constructor. hash stores the equivalence relationships; s is the string 1.130 + // for which we find equivalent strings. 1.131 + inline EquivIterator(const icu::Hashtable& hash, const icu::UnicodeString& s) 1.132 + : _hash(hash) { 1.133 + _start = _current = &s; 1.134 + } 1.135 + inline ~EquivIterator() { } 1.136 + 1.137 + // next returns the next equivalent string or NULL if there are no more. 1.138 + // If s has no equivalent strings, next returns NULL on the first call. 1.139 + const icu::UnicodeString *next(); 1.140 +private: 1.141 + const icu::Hashtable& _hash; 1.142 + const icu::UnicodeString* _start; 1.143 + const icu::UnicodeString* _current; 1.144 +}; 1.145 + 1.146 +const icu::UnicodeString * 1.147 +EquivIterator::next() { 1.148 + const icu::UnicodeString* _next = (const icu::UnicodeString*) _hash.get(*_current); 1.149 + if (_next == NULL) { 1.150 + U_ASSERT(_current == _start); 1.151 + return NULL; 1.152 + } 1.153 + if (*_next == *_start) { 1.154 + return NULL; 1.155 + } 1.156 + _current = _next; 1.157 + return _next; 1.158 +} 1.159 + 1.160 +// makeEquivalent makes lhs and rhs equivalent by updating the equivalence 1.161 +// relations in hash accordingly. 1.162 +static void makeEquivalent( 1.163 + const icu::UnicodeString &lhs, 1.164 + const icu::UnicodeString &rhs, 1.165 + icu::Hashtable* hash, UErrorCode &status) { 1.166 + if (U_FAILURE(status)) { 1.167 + return; 1.168 + } 1.169 + if (lhs == rhs) { 1.170 + // already equivalent 1.171 + return; 1.172 + } 1.173 + EquivIterator leftIter(*hash, lhs); 1.174 + EquivIterator rightIter(*hash, rhs); 1.175 + const icu::UnicodeString *firstLeft = leftIter.next(); 1.176 + const icu::UnicodeString *firstRight = rightIter.next(); 1.177 + const icu::UnicodeString *nextLeft = firstLeft; 1.178 + const icu::UnicodeString *nextRight = firstRight; 1.179 + while (nextLeft != NULL && nextRight != NULL) { 1.180 + if (*nextLeft == rhs || *nextRight == lhs) { 1.181 + // Already equivalent 1.182 + return; 1.183 + } 1.184 + nextLeft = leftIter.next(); 1.185 + nextRight = rightIter.next(); 1.186 + } 1.187 + // Not equivalent. Must join. 1.188 + icu::UnicodeString *newFirstLeft; 1.189 + icu::UnicodeString *newFirstRight; 1.190 + if (firstRight == NULL && firstLeft == NULL) { 1.191 + // Neither lhs or rhs belong to an equivalence circle, so we form 1.192 + // a new equivalnce circle of just lhs and rhs. 1.193 + newFirstLeft = new icu::UnicodeString(rhs); 1.194 + newFirstRight = new icu::UnicodeString(lhs); 1.195 + } else if (firstRight == NULL) { 1.196 + // lhs belongs to an equivalence circle, but rhs does not, so we link 1.197 + // rhs into lhs' circle. 1.198 + newFirstLeft = new icu::UnicodeString(rhs); 1.199 + newFirstRight = new icu::UnicodeString(*firstLeft); 1.200 + } else if (firstLeft == NULL) { 1.201 + // rhs belongs to an equivlance circle, but lhs does not, so we link 1.202 + // lhs into rhs' circle. 1.203 + newFirstLeft = new icu::UnicodeString(*firstRight); 1.204 + newFirstRight = new icu::UnicodeString(lhs); 1.205 + } else { 1.206 + // Both lhs and rhs belong to different equivalnce circles. We link 1.207 + // them together to form one single, larger equivalnce circle. 1.208 + newFirstLeft = new icu::UnicodeString(*firstRight); 1.209 + newFirstRight = new icu::UnicodeString(*firstLeft); 1.210 + } 1.211 + if (newFirstLeft == NULL || newFirstRight == NULL) { 1.212 + delete newFirstLeft; 1.213 + delete newFirstRight; 1.214 + status = U_MEMORY_ALLOCATION_ERROR; 1.215 + return; 1.216 + } 1.217 + hash->put(lhs, (void *) newFirstLeft, status); 1.218 + hash->put(rhs, (void *) newFirstRight, status); 1.219 +} 1.220 + 1.221 +// countEquivalent counts how many strings are equivalent to s. 1.222 +// hash stores all the equivalnce relations. 1.223 +// countEquivalent does not include s itself in the count. 1.224 +static int32_t countEquivalent(const icu::Hashtable &hash, const icu::UnicodeString &s) { 1.225 + int32_t result = 0; 1.226 + EquivIterator iter(hash, s); 1.227 + while (iter.next() != NULL) { 1.228 + ++result; 1.229 + } 1.230 +#ifdef UCURR_DEBUG_EQUIV 1.231 + { 1.232 + char tmp[200]; 1.233 + s.extract(0,s.length(),tmp, "UTF-8"); 1.234 + printf("CountEquivalent('%s') = %d\n", tmp, result); 1.235 + } 1.236 +#endif 1.237 + return result; 1.238 +} 1.239 + 1.240 +static const icu::Hashtable* getCurrSymbolsEquiv(); 1.241 + 1.242 +//------------------------------------------------------------ 1.243 +// Code 1.244 + 1.245 +/** 1.246 + * Cleanup callback func 1.247 + */ 1.248 +static UBool U_CALLCONV 1.249 +isoCodes_cleanup(void) 1.250 +{ 1.251 + if (gIsoCodes != NULL) { 1.252 + uhash_close(const_cast<UHashtable *>(gIsoCodes)); 1.253 + gIsoCodes = NULL; 1.254 + } 1.255 + gIsoCodesInitOnce.reset(); 1.256 + return TRUE; 1.257 +} 1.258 + 1.259 +/** 1.260 + * Cleanup callback func 1.261 + */ 1.262 +static UBool U_CALLCONV 1.263 +currSymbolsEquiv_cleanup(void) 1.264 +{ 1.265 + delete const_cast<icu::Hashtable *>(gCurrSymbolsEquiv); 1.266 + gCurrSymbolsEquiv = NULL; 1.267 + gCurrSymbolsEquivInitOnce.reset(); 1.268 + return TRUE; 1.269 +} 1.270 + 1.271 +/** 1.272 + * Deleter for OlsonToMetaMappingEntry 1.273 + */ 1.274 +static void U_CALLCONV 1.275 +deleteIsoCodeEntry(void *obj) { 1.276 + IsoCodeEntry *entry = (IsoCodeEntry*)obj; 1.277 + uprv_free(entry); 1.278 +} 1.279 + 1.280 +/** 1.281 + * Deleter for gCurrSymbolsEquiv. 1.282 + */ 1.283 +static void U_CALLCONV 1.284 +deleteUnicode(void *obj) { 1.285 + icu::UnicodeString *entry = (icu::UnicodeString*)obj; 1.286 + delete entry; 1.287 +} 1.288 + 1.289 +/** 1.290 + * Unfortunately, we have to convert the UChar* currency code to char* 1.291 + * to use it as a resource key. 1.292 + */ 1.293 +static inline char* 1.294 +myUCharsToChars(char* resultOfLen4, const UChar* currency) { 1.295 + u_UCharsToChars(currency, resultOfLen4, ISO_CURRENCY_CODE_LENGTH); 1.296 + resultOfLen4[ISO_CURRENCY_CODE_LENGTH] = 0; 1.297 + return resultOfLen4; 1.298 +} 1.299 + 1.300 +/** 1.301 + * Internal function to look up currency data. Result is an array of 1.302 + * four integers. The first is the fraction digits. The second is the 1.303 + * rounding increment, or 0 if none. The rounding increment is in 1.304 + * units of 10^(-fraction_digits). The third and fourth are the same 1.305 + * except that they are those used in cash transations ( cashDigits 1.306 + * and cashRounding ). 1.307 + */ 1.308 +static const int32_t* 1.309 +_findMetaData(const UChar* currency, UErrorCode& ec) { 1.310 + 1.311 + if (currency == 0 || *currency == 0) { 1.312 + if (U_SUCCESS(ec)) { 1.313 + ec = U_ILLEGAL_ARGUMENT_ERROR; 1.314 + } 1.315 + return LAST_RESORT_DATA; 1.316 + } 1.317 + 1.318 + // Get CurrencyMeta resource out of root locale file. [This may 1.319 + // move out of the root locale file later; if it does, update this 1.320 + // code.] 1.321 + UResourceBundle* currencyData = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &ec); 1.322 + UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec); 1.323 + 1.324 + if (U_FAILURE(ec)) { 1.325 + ures_close(currencyMeta); 1.326 + // Config/build error; return hard-coded defaults 1.327 + return LAST_RESORT_DATA; 1.328 + } 1.329 + 1.330 + // Look up our currency, or if that's not available, then DEFAULT 1.331 + char buf[ISO_CURRENCY_CODE_LENGTH+1]; 1.332 + UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure 1.333 + UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2); 1.334 + if (U_FAILURE(ec2)) { 1.335 + ures_close(rb); 1.336 + rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec); 1.337 + if (U_FAILURE(ec)) { 1.338 + ures_close(currencyMeta); 1.339 + ures_close(rb); 1.340 + // Config/build error; return hard-coded defaults 1.341 + return LAST_RESORT_DATA; 1.342 + } 1.343 + } 1.344 + 1.345 + int32_t len; 1.346 + const int32_t *data = ures_getIntVector(rb, &len, &ec); 1.347 + if (U_FAILURE(ec) || len != 4) { 1.348 + // Config/build error; return hard-coded defaults 1.349 + if (U_SUCCESS(ec)) { 1.350 + ec = U_INVALID_FORMAT_ERROR; 1.351 + } 1.352 + ures_close(currencyMeta); 1.353 + ures_close(rb); 1.354 + return LAST_RESORT_DATA; 1.355 + } 1.356 + 1.357 + ures_close(currencyMeta); 1.358 + ures_close(rb); 1.359 + return data; 1.360 +} 1.361 + 1.362 +// ------------------------------------- 1.363 + 1.364 +/** 1.365 + * @see VARIANT_IS_EURO 1.366 + * @see VARIANT_IS_PREEURO 1.367 + */ 1.368 +static uint32_t 1.369 +idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec) 1.370 +{ 1.371 + uint32_t variantType = 0; 1.372 + // !!! this is internal only, assumes buffer is not null and capacity is sufficient 1.373 + // Extract the country name and variant name. We only 1.374 + // recognize two variant names, EURO and PREEURO. 1.375 + char variant[ULOC_FULLNAME_CAPACITY]; 1.376 + uloc_getCountry(locale, countryAndVariant, capacity, ec); 1.377 + uloc_getVariant(locale, variant, sizeof(variant), ec); 1.378 + if (variant[0] != 0) { 1.379 + variantType = (uint32_t)(0 == uprv_strcmp(variant, VAR_EURO)) 1.380 + | ((uint32_t)(0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1); 1.381 + if (variantType) 1.382 + { 1.383 + uprv_strcat(countryAndVariant, VAR_DELIM_STR); 1.384 + uprv_strcat(countryAndVariant, variant); 1.385 + } 1.386 + } 1.387 + return variantType; 1.388 +} 1.389 + 1.390 +// ------------------------------------------ 1.391 +// 1.392 +// Registration 1.393 +// 1.394 +//------------------------------------------- 1.395 + 1.396 +// don't use ICUService since we don't need fallback 1.397 + 1.398 +U_CDECL_BEGIN 1.399 +static UBool U_CALLCONV currency_cleanup(void); 1.400 +U_CDECL_END 1.401 + 1.402 +#if !UCONFIG_NO_SERVICE 1.403 +struct CReg; 1.404 + 1.405 +static UMutex gCRegLock = U_MUTEX_INITIALIZER; 1.406 +static CReg* gCRegHead = 0; 1.407 + 1.408 +struct CReg : public icu::UMemory { 1.409 + CReg *next; 1.410 + UChar iso[ISO_CURRENCY_CODE_LENGTH+1]; 1.411 + char id[ULOC_FULLNAME_CAPACITY]; 1.412 + 1.413 + CReg(const UChar* _iso, const char* _id) 1.414 + : next(0) 1.415 + { 1.416 + int32_t len = (int32_t)uprv_strlen(_id); 1.417 + if (len > (int32_t)(sizeof(id)-1)) { 1.418 + len = (sizeof(id)-1); 1.419 + } 1.420 + uprv_strncpy(id, _id, len); 1.421 + id[len] = 0; 1.422 + uprv_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH * sizeof(const UChar)); 1.423 + iso[ISO_CURRENCY_CODE_LENGTH] = 0; 1.424 + } 1.425 + 1.426 + static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status) 1.427 + { 1.428 + if (status && U_SUCCESS(*status) && _iso && _id) { 1.429 + CReg* n = new CReg(_iso, _id); 1.430 + if (n) { 1.431 + umtx_lock(&gCRegLock); 1.432 + if (!gCRegHead) { 1.433 + /* register for the first time */ 1.434 + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); 1.435 + } 1.436 + n->next = gCRegHead; 1.437 + gCRegHead = n; 1.438 + umtx_unlock(&gCRegLock); 1.439 + return n; 1.440 + } 1.441 + *status = U_MEMORY_ALLOCATION_ERROR; 1.442 + } 1.443 + return 0; 1.444 + } 1.445 + 1.446 + static UBool unreg(UCurrRegistryKey key) { 1.447 + UBool found = FALSE; 1.448 + umtx_lock(&gCRegLock); 1.449 + 1.450 + CReg** p = &gCRegHead; 1.451 + while (*p) { 1.452 + if (*p == key) { 1.453 + *p = ((CReg*)key)->next; 1.454 + delete (CReg*)key; 1.455 + found = TRUE; 1.456 + break; 1.457 + } 1.458 + p = &((*p)->next); 1.459 + } 1.460 + 1.461 + umtx_unlock(&gCRegLock); 1.462 + return found; 1.463 + } 1.464 + 1.465 + static const UChar* get(const char* id) { 1.466 + const UChar* result = NULL; 1.467 + umtx_lock(&gCRegLock); 1.468 + CReg* p = gCRegHead; 1.469 + 1.470 + /* register cleanup of the mutex */ 1.471 + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); 1.472 + while (p) { 1.473 + if (uprv_strcmp(id, p->id) == 0) { 1.474 + result = p->iso; 1.475 + break; 1.476 + } 1.477 + p = p->next; 1.478 + } 1.479 + umtx_unlock(&gCRegLock); 1.480 + return result; 1.481 + } 1.482 + 1.483 + /* This doesn't need to be thread safe. It's for u_cleanup only. */ 1.484 + static void cleanup(void) { 1.485 + while (gCRegHead) { 1.486 + CReg* n = gCRegHead; 1.487 + gCRegHead = gCRegHead->next; 1.488 + delete n; 1.489 + } 1.490 + } 1.491 +}; 1.492 + 1.493 +// ------------------------------------- 1.494 + 1.495 +U_CAPI UCurrRegistryKey U_EXPORT2 1.496 +ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status) 1.497 +{ 1.498 + if (status && U_SUCCESS(*status)) { 1.499 + char id[ULOC_FULLNAME_CAPACITY]; 1.500 + idForLocale(locale, id, sizeof(id), status); 1.501 + return CReg::reg(isoCode, id, status); 1.502 + } 1.503 + return NULL; 1.504 +} 1.505 + 1.506 +// ------------------------------------- 1.507 + 1.508 +U_CAPI UBool U_EXPORT2 1.509 +ucurr_unregister(UCurrRegistryKey key, UErrorCode* status) 1.510 +{ 1.511 + if (status && U_SUCCESS(*status)) { 1.512 + return CReg::unreg(key); 1.513 + } 1.514 + return FALSE; 1.515 +} 1.516 +#endif /* UCONFIG_NO_SERVICE */ 1.517 + 1.518 +// ------------------------------------- 1.519 + 1.520 +/** 1.521 + * Release all static memory held by currency. 1.522 + */ 1.523 +/*The declaration here is needed so currency_cleanup(void) 1.524 + * can call this function. 1.525 + */ 1.526 +static UBool U_CALLCONV 1.527 +currency_cache_cleanup(void); 1.528 + 1.529 +U_CDECL_BEGIN 1.530 +static UBool U_CALLCONV currency_cleanup(void) { 1.531 +#if !UCONFIG_NO_SERVICE 1.532 + CReg::cleanup(); 1.533 +#endif 1.534 + /* 1.535 + * There might be some cached currency data or isoCodes data. 1.536 + */ 1.537 + currency_cache_cleanup(); 1.538 + isoCodes_cleanup(); 1.539 + currSymbolsEquiv_cleanup(); 1.540 + 1.541 + return TRUE; 1.542 +} 1.543 +U_CDECL_END 1.544 + 1.545 +// ------------------------------------- 1.546 + 1.547 +U_CAPI int32_t U_EXPORT2 1.548 +ucurr_forLocale(const char* locale, 1.549 + UChar* buff, 1.550 + int32_t buffCapacity, 1.551 + UErrorCode* ec) 1.552 +{ 1.553 + int32_t resLen = 0; 1.554 + const UChar* s = NULL; 1.555 + if (ec != NULL && U_SUCCESS(*ec)) { 1.556 + if ((buff && buffCapacity) || !buffCapacity) { 1.557 + UErrorCode localStatus = U_ZERO_ERROR; 1.558 + char id[ULOC_FULLNAME_CAPACITY]; 1.559 + if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) { 1.560 + // there is a currency keyword. Try to see if it's valid 1.561 + if(buffCapacity > resLen) { 1.562 + /* Normalize the currency keyword value to upper case. */ 1.563 + T_CString_toUpperCase(id); 1.564 + u_charsToUChars(id, buff, resLen); 1.565 + } 1.566 + } else { 1.567 + // get country or country_variant in `id' 1.568 + uint32_t variantType = idForLocale(locale, id, sizeof(id), ec); 1.569 + 1.570 + if (U_FAILURE(*ec)) { 1.571 + return 0; 1.572 + } 1.573 + 1.574 +#if !UCONFIG_NO_SERVICE 1.575 + const UChar* result = CReg::get(id); 1.576 + if (result) { 1.577 + if(buffCapacity > u_strlen(result)) { 1.578 + u_strcpy(buff, result); 1.579 + } 1.580 + return u_strlen(result); 1.581 + } 1.582 +#endif 1.583 + // Remove variants, which is only needed for registration. 1.584 + char *idDelim = strchr(id, VAR_DELIM); 1.585 + if (idDelim) { 1.586 + idDelim[0] = 0; 1.587 + } 1.588 + 1.589 + // Look up the CurrencyMap element in the root bundle. 1.590 + UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus); 1.591 + UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); 1.592 + UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus); 1.593 + UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus); 1.594 + s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus); 1.595 + 1.596 + /* 1.597 + Get the second item when PREEURO is requested, and this is a known Euro country. 1.598 + If the requested variant is PREEURO, and this isn't a Euro country, assume 1.599 + that the country changed over to the Euro in the future. This is probably 1.600 + an old version of ICU that hasn't been updated yet. The latest currency is 1.601 + probably correct. 1.602 + */ 1.603 + if (U_SUCCESS(localStatus)) { 1.604 + if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) { 1.605 + currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus); 1.606 + s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus); 1.607 + } 1.608 + else if ((variantType & VARIANT_IS_EURO)) { 1.609 + s = EUR_STR; 1.610 + } 1.611 + } 1.612 + ures_close(countryArray); 1.613 + ures_close(currencyReq); 1.614 + 1.615 + if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0) 1.616 + { 1.617 + // We don't know about it. Check to see if we support the variant. 1.618 + uloc_getParent(locale, id, sizeof(id), ec); 1.619 + *ec = U_USING_FALLBACK_WARNING; 1.620 + return ucurr_forLocale(id, buff, buffCapacity, ec); 1.621 + } 1.622 + else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) { 1.623 + // There is nothing to fallback to. Report the failure/warning if possible. 1.624 + *ec = localStatus; 1.625 + } 1.626 + if (U_SUCCESS(*ec)) { 1.627 + if(buffCapacity > resLen) { 1.628 + u_strcpy(buff, s); 1.629 + } 1.630 + } 1.631 + } 1.632 + return u_terminateUChars(buff, buffCapacity, resLen, ec); 1.633 + } else { 1.634 + *ec = U_ILLEGAL_ARGUMENT_ERROR; 1.635 + } 1.636 + } 1.637 + return resLen; 1.638 +} 1.639 + 1.640 +// end registration 1.641 + 1.642 +/** 1.643 + * Modify the given locale name by removing the rightmost _-delimited 1.644 + * element. If there is none, empty the string ("" == root). 1.645 + * NOTE: The string "root" is not recognized; do not use it. 1.646 + * @return TRUE if the fallback happened; FALSE if locale is already 1.647 + * root (""). 1.648 + */ 1.649 +static UBool fallback(char *loc) { 1.650 + if (!*loc) { 1.651 + return FALSE; 1.652 + } 1.653 + UErrorCode status = U_ZERO_ERROR; 1.654 + uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status); 1.655 + /* 1.656 + char *i = uprv_strrchr(loc, '_'); 1.657 + if (i == NULL) { 1.658 + i = loc; 1.659 + } 1.660 + *i = 0; 1.661 + */ 1.662 + return TRUE; 1.663 +} 1.664 + 1.665 + 1.666 +U_CAPI const UChar* U_EXPORT2 1.667 +ucurr_getName(const UChar* currency, 1.668 + const char* locale, 1.669 + UCurrNameStyle nameStyle, 1.670 + UBool* isChoiceFormat, // fillin 1.671 + int32_t* len, // fillin 1.672 + UErrorCode* ec) { 1.673 + 1.674 + // Look up the Currencies resource for the given locale. The 1.675 + // Currencies locale data looks like this: 1.676 + //|en { 1.677 + //| Currencies { 1.678 + //| USD { "US$", "US Dollar" } 1.679 + //| CHF { "Sw F", "Swiss Franc" } 1.680 + //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" } 1.681 + //| //... 1.682 + //| } 1.683 + //|} 1.684 + 1.685 + if (U_FAILURE(*ec)) { 1.686 + return 0; 1.687 + } 1.688 + 1.689 + int32_t choice = (int32_t) nameStyle; 1.690 + if (choice < 0 || choice > 1) { 1.691 + *ec = U_ILLEGAL_ARGUMENT_ERROR; 1.692 + return 0; 1.693 + } 1.694 + 1.695 + // In the future, resource bundles may implement multi-level 1.696 + // fallback. That is, if a currency is not found in the en_US 1.697 + // Currencies data, then the en Currencies data will be searched. 1.698 + // Currently, if a Currencies datum exists in en_US and en, the 1.699 + // en_US entry hides that in en. 1.700 + 1.701 + // We want multi-level fallback for this resource, so we implement 1.702 + // it manually. 1.703 + 1.704 + // Use a separate UErrorCode here that does not propagate out of 1.705 + // this function. 1.706 + UErrorCode ec2 = U_ZERO_ERROR; 1.707 + 1.708 + char loc[ULOC_FULLNAME_CAPACITY]; 1.709 + uloc_getName(locale, loc, sizeof(loc), &ec2); 1.710 + if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) { 1.711 + *ec = U_ILLEGAL_ARGUMENT_ERROR; 1.712 + return 0; 1.713 + } 1.714 + 1.715 + char buf[ISO_CURRENCY_CODE_LENGTH+1]; 1.716 + myUCharsToChars(buf, currency); 1.717 + 1.718 + /* Normalize the keyword value to uppercase */ 1.719 + T_CString_toUpperCase(buf); 1.720 + 1.721 + const UChar* s = NULL; 1.722 + ec2 = U_ZERO_ERROR; 1.723 + UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2); 1.724 + 1.725 + rb = ures_getByKey(rb, CURRENCIES, rb, &ec2); 1.726 + 1.727 + // Fetch resource with multi-level resource inheritance fallback 1.728 + rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2); 1.729 + 1.730 + s = ures_getStringByIndex(rb, choice, len, &ec2); 1.731 + ures_close(rb); 1.732 + 1.733 + // If we've succeeded we're done. Otherwise, try to fallback. 1.734 + // If that fails (because we are already at root) then exit. 1.735 + if (U_SUCCESS(ec2)) { 1.736 + if (ec2 == U_USING_DEFAULT_WARNING 1.737 + || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) { 1.738 + *ec = ec2; 1.739 + } 1.740 + } 1.741 + 1.742 + // Determine if this is a ChoiceFormat pattern. One leading mark 1.743 + // indicates a ChoiceFormat. Two indicates a static string that 1.744 + // starts with a mark. In either case, the first mark is ignored, 1.745 + // if present. Marks in the rest of the string have no special 1.746 + // meaning. 1.747 + *isChoiceFormat = FALSE; 1.748 + if (U_SUCCESS(ec2)) { 1.749 + U_ASSERT(s != NULL); 1.750 + int32_t i=0; 1.751 + while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) { 1.752 + ++i; 1.753 + } 1.754 + *isChoiceFormat = (i == 1); 1.755 + if (i != 0) ++s; // Skip over first mark 1.756 + return s; 1.757 + } 1.758 + 1.759 + // If we fail to find a match, use the ISO 4217 code 1.760 + *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...? 1.761 + *ec = U_USING_DEFAULT_WARNING; 1.762 + return currency; 1.763 +} 1.764 + 1.765 +U_CAPI const UChar* U_EXPORT2 1.766 +ucurr_getPluralName(const UChar* currency, 1.767 + const char* locale, 1.768 + UBool* isChoiceFormat, 1.769 + const char* pluralCount, 1.770 + int32_t* len, // fillin 1.771 + UErrorCode* ec) { 1.772 + // Look up the Currencies resource for the given locale. The 1.773 + // Currencies locale data looks like this: 1.774 + //|en { 1.775 + //| CurrencyPlurals { 1.776 + //| USD{ 1.777 + //| one{"US dollar"} 1.778 + //| other{"US dollars"} 1.779 + //| } 1.780 + //| } 1.781 + //|} 1.782 + 1.783 + if (U_FAILURE(*ec)) { 1.784 + return 0; 1.785 + } 1.786 + 1.787 + // Use a separate UErrorCode here that does not propagate out of 1.788 + // this function. 1.789 + UErrorCode ec2 = U_ZERO_ERROR; 1.790 + 1.791 + char loc[ULOC_FULLNAME_CAPACITY]; 1.792 + uloc_getName(locale, loc, sizeof(loc), &ec2); 1.793 + if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) { 1.794 + *ec = U_ILLEGAL_ARGUMENT_ERROR; 1.795 + return 0; 1.796 + } 1.797 + 1.798 + char buf[ISO_CURRENCY_CODE_LENGTH+1]; 1.799 + myUCharsToChars(buf, currency); 1.800 + 1.801 + const UChar* s = NULL; 1.802 + ec2 = U_ZERO_ERROR; 1.803 + UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2); 1.804 + 1.805 + rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2); 1.806 + 1.807 + // Fetch resource with multi-level resource inheritance fallback 1.808 + rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2); 1.809 + 1.810 + s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2); 1.811 + if (U_FAILURE(ec2)) { 1.812 + // fall back to "other" 1.813 + ec2 = U_ZERO_ERROR; 1.814 + s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2); 1.815 + if (U_FAILURE(ec2)) { 1.816 + ures_close(rb); 1.817 + // fall back to long name in Currencies 1.818 + return ucurr_getName(currency, locale, UCURR_LONG_NAME, 1.819 + isChoiceFormat, len, ec); 1.820 + } 1.821 + } 1.822 + ures_close(rb); 1.823 + 1.824 + // If we've succeeded we're done. Otherwise, try to fallback. 1.825 + // If that fails (because we are already at root) then exit. 1.826 + if (U_SUCCESS(ec2)) { 1.827 + if (ec2 == U_USING_DEFAULT_WARNING 1.828 + || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) { 1.829 + *ec = ec2; 1.830 + } 1.831 + U_ASSERT(s != NULL); 1.832 + return s; 1.833 + } 1.834 + 1.835 + // If we fail to find a match, use the ISO 4217 code 1.836 + *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...? 1.837 + *ec = U_USING_DEFAULT_WARNING; 1.838 + return currency; 1.839 +} 1.840 + 1.841 + 1.842 +//======================================================================== 1.843 +// Following are structure and function for parsing currency names 1.844 + 1.845 +#define NEED_TO_BE_DELETED 0x1 1.846 + 1.847 +// TODO: a better way to define this? 1.848 +#define MAX_CURRENCY_NAME_LEN 100 1.849 + 1.850 +typedef struct { 1.851 + const char* IsoCode; // key 1.852 + UChar* currencyName; // value 1.853 + int32_t currencyNameLen; // value length 1.854 + int32_t flag; // flags 1.855 +} CurrencyNameStruct; 1.856 + 1.857 + 1.858 +#ifndef MIN 1.859 +#define MIN(a,b) (((a)<(b)) ? (a) : (b)) 1.860 +#endif 1.861 + 1.862 +#ifndef MAX 1.863 +#define MAX(a,b) (((a)<(b)) ? (b) : (a)) 1.864 +#endif 1.865 + 1.866 + 1.867 +// Comparason function used in quick sort. 1.868 +static int U_CALLCONV currencyNameComparator(const void* a, const void* b) { 1.869 + const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a; 1.870 + const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b; 1.871 + for (int32_t i = 0; 1.872 + i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen); 1.873 + ++i) { 1.874 + if (currName_1->currencyName[i] < currName_2->currencyName[i]) { 1.875 + return -1; 1.876 + } 1.877 + if (currName_1->currencyName[i] > currName_2->currencyName[i]) { 1.878 + return 1; 1.879 + } 1.880 + } 1.881 + if (currName_1->currencyNameLen < currName_2->currencyNameLen) { 1.882 + return -1; 1.883 + } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) { 1.884 + return 1; 1.885 + } 1.886 + return 0; 1.887 +} 1.888 + 1.889 + 1.890 +// Give a locale, return the maximum number of currency names associated with 1.891 +// this locale. 1.892 +// It gets currency names from resource bundles using fallback. 1.893 +// It is the maximum number because in the fallback chain, some of the 1.894 +// currency names are duplicated. 1.895 +// For example, given locale as "en_US", the currency names get from resource 1.896 +// bundle in "en_US" and "en" are duplicated. The fallback mechanism will count 1.897 +// all currency names in "en_US" and "en". 1.898 +static void 1.899 +getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) { 1.900 + U_NAMESPACE_USE 1.901 + *total_currency_name_count = 0; 1.902 + *total_currency_symbol_count = 0; 1.903 + const UChar* s = NULL; 1.904 + char locale[ULOC_FULLNAME_CAPACITY]; 1.905 + uprv_strcpy(locale, loc); 1.906 + const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv(); 1.907 + for (;;) { 1.908 + UErrorCode ec2 = U_ZERO_ERROR; 1.909 + // TODO: ures_openDirect? 1.910 + UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2); 1.911 + UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2); 1.912 + int32_t n = ures_getSize(curr); 1.913 + for (int32_t i=0; i<n; ++i) { 1.914 + UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2); 1.915 + int32_t len; 1.916 + s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2); 1.917 + UBool isChoice = FALSE; 1.918 + if (len > 0 && s[0] == CHOICE_FORMAT_MARK) { 1.919 + ++s; 1.920 + --len; 1.921 + if (len > 0 && s[0] != CHOICE_FORMAT_MARK) { 1.922 + isChoice = TRUE; 1.923 + } 1.924 + } 1.925 + if (isChoice) { 1.926 + ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2); 1.927 + int32_t fmt_count; 1.928 + fmt.getFormats(fmt_count); 1.929 + *total_currency_symbol_count += fmt_count; 1.930 + } else { 1.931 + ++(*total_currency_symbol_count); // currency symbol 1.932 + if (currencySymbolsEquiv != NULL) { 1.933 + *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(TRUE, s, len)); 1.934 + } 1.935 + } 1.936 + 1.937 + ++(*total_currency_symbol_count); // iso code 1.938 + ++(*total_currency_name_count); // long name 1.939 + ures_close(names); 1.940 + } 1.941 + 1.942 + // currency plurals 1.943 + UErrorCode ec3 = U_ZERO_ERROR; 1.944 + UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3); 1.945 + n = ures_getSize(curr_p); 1.946 + for (int32_t i=0; i<n; ++i) { 1.947 + UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3); 1.948 + *total_currency_name_count += ures_getSize(names); 1.949 + ures_close(names); 1.950 + } 1.951 + ures_close(curr_p); 1.952 + ures_close(curr); 1.953 + ures_close(rb); 1.954 + 1.955 + if (!fallback(locale)) { 1.956 + break; 1.957 + } 1.958 + } 1.959 +} 1.960 + 1.961 +static UChar* 1.962 +toUpperCase(const UChar* source, int32_t len, const char* locale) { 1.963 + UChar* dest = NULL; 1.964 + UErrorCode ec = U_ZERO_ERROR; 1.965 + int32_t destLen = u_strToUpper(dest, 0, source, len, locale, &ec); 1.966 + 1.967 + ec = U_ZERO_ERROR; 1.968 + dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len)); 1.969 + u_strToUpper(dest, destLen, source, len, locale, &ec); 1.970 + if (U_FAILURE(ec)) { 1.971 + uprv_memcpy(dest, source, sizeof(UChar) * len); 1.972 + } 1.973 + return dest; 1.974 +} 1.975 + 1.976 + 1.977 +// Collect all available currency names associated with the given locale 1.978 +// (enable fallback chain). 1.979 +// Read currenc names defined in resource bundle "Currencies" and 1.980 +// "CurrencyPlural", enable fallback chain. 1.981 +// return the malloc-ed currency name arrays and the total number of currency 1.982 +// names in the array. 1.983 +static void 1.984 +collectCurrencyNames(const char* locale, 1.985 + CurrencyNameStruct** currencyNames, 1.986 + int32_t* total_currency_name_count, 1.987 + CurrencyNameStruct** currencySymbols, 1.988 + int32_t* total_currency_symbol_count, 1.989 + UErrorCode& ec) { 1.990 + U_NAMESPACE_USE 1.991 + const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv(); 1.992 + // Look up the Currencies resource for the given locale. 1.993 + UErrorCode ec2 = U_ZERO_ERROR; 1.994 + 1.995 + char loc[ULOC_FULLNAME_CAPACITY]; 1.996 + uloc_getName(locale, loc, sizeof(loc), &ec2); 1.997 + if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) { 1.998 + ec = U_ILLEGAL_ARGUMENT_ERROR; 1.999 + } 1.1000 + 1.1001 + // Get maximum currency name count first. 1.1002 + getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count); 1.1003 + 1.1004 + *currencyNames = (CurrencyNameStruct*)uprv_malloc 1.1005 + (sizeof(CurrencyNameStruct) * (*total_currency_name_count)); 1.1006 + *currencySymbols = (CurrencyNameStruct*)uprv_malloc 1.1007 + (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count)); 1.1008 + 1.1009 + const UChar* s = NULL; // currency name 1.1010 + char* iso = NULL; // currency ISO code 1.1011 + 1.1012 + *total_currency_name_count = 0; 1.1013 + *total_currency_symbol_count = 0; 1.1014 + 1.1015 + UErrorCode ec3 = U_ZERO_ERROR; 1.1016 + UErrorCode ec4 = U_ZERO_ERROR; 1.1017 + 1.1018 + // Using hash to remove duplicates caused by locale fallback 1.1019 + UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3); 1.1020 + UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4); 1.1021 + for (int32_t localeLevel = 0; ; ++localeLevel) { 1.1022 + ec2 = U_ZERO_ERROR; 1.1023 + // TODO: ures_openDirect 1.1024 + UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2); 1.1025 + UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2); 1.1026 + int32_t n = ures_getSize(curr); 1.1027 + for (int32_t i=0; i<n; ++i) { 1.1028 + UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2); 1.1029 + int32_t len; 1.1030 + s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2); 1.1031 + // TODO: uhash_put wont change key/value? 1.1032 + iso = (char*)ures_getKey(names); 1.1033 + if (localeLevel == 0) { 1.1034 + uhash_put(currencyIsoCodes, iso, iso, &ec3); 1.1035 + } else { 1.1036 + if (uhash_get(currencyIsoCodes, iso) != NULL) { 1.1037 + ures_close(names); 1.1038 + continue; 1.1039 + } else { 1.1040 + uhash_put(currencyIsoCodes, iso, iso, &ec3); 1.1041 + } 1.1042 + } 1.1043 + UBool isChoice = FALSE; 1.1044 + if (len > 0 && s[0] == CHOICE_FORMAT_MARK) { 1.1045 + ++s; 1.1046 + --len; 1.1047 + if (len > 0 && s[0] != CHOICE_FORMAT_MARK) { 1.1048 + isChoice = TRUE; 1.1049 + } 1.1050 + } 1.1051 + if (isChoice) { 1.1052 + ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2); 1.1053 + int32_t fmt_count; 1.1054 + const UnicodeString* formats = fmt.getFormats(fmt_count); 1.1055 + for (int i = 0; i < fmt_count; ++i) { 1.1056 + // put iso, formats[i]; into array 1.1057 + int32_t length = formats[i].length(); 1.1058 + UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length); 1.1059 + formats[i].extract(0, length, name); 1.1060 + (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso; 1.1061 + (*currencySymbols)[*total_currency_symbol_count].currencyName = name; 1.1062 + (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED; 1.1063 + (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length; 1.1064 + } 1.1065 + } else { 1.1066 + // Add currency symbol. 1.1067 + (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso; 1.1068 + (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s; 1.1069 + (*currencySymbols)[*total_currency_symbol_count].flag = 0; 1.1070 + (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len; 1.1071 + // Add equivalent symbols 1.1072 + if (currencySymbolsEquiv != NULL) { 1.1073 + EquivIterator iter(*currencySymbolsEquiv, UnicodeString(TRUE, s, len)); 1.1074 + const UnicodeString *symbol; 1.1075 + while ((symbol = iter.next()) != NULL) { 1.1076 + (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso; 1.1077 + (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*) symbol->getBuffer(); 1.1078 + (*currencySymbols)[*total_currency_symbol_count].flag = 0; 1.1079 + (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = symbol->length(); 1.1080 + } 1.1081 + } 1.1082 + } 1.1083 + 1.1084 + // Add currency long name. 1.1085 + s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2); 1.1086 + (*currencyNames)[*total_currency_name_count].IsoCode = iso; 1.1087 + UChar* upperName = toUpperCase(s, len, locale); 1.1088 + (*currencyNames)[*total_currency_name_count].currencyName = upperName; 1.1089 + (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED; 1.1090 + (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len; 1.1091 + 1.1092 + // put (iso, 3, and iso) in to array 1.1093 + // Add currency ISO code. 1.1094 + (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso; 1.1095 + (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3); 1.1096 + // Must convert iso[] into Unicode 1.1097 + u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3); 1.1098 + (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED; 1.1099 + (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3; 1.1100 + 1.1101 + ures_close(names); 1.1102 + } 1.1103 + 1.1104 + // currency plurals 1.1105 + UErrorCode ec3 = U_ZERO_ERROR; 1.1106 + UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3); 1.1107 + n = ures_getSize(curr_p); 1.1108 + for (int32_t i=0; i<n; ++i) { 1.1109 + UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3); 1.1110 + iso = (char*)ures_getKey(names); 1.1111 + // Using hash to remove duplicated ISO codes in fallback chain. 1.1112 + if (localeLevel == 0) { 1.1113 + uhash_put(currencyPluralIsoCodes, iso, iso, &ec4); 1.1114 + } else { 1.1115 + if (uhash_get(currencyPluralIsoCodes, iso) != NULL) { 1.1116 + ures_close(names); 1.1117 + continue; 1.1118 + } else { 1.1119 + uhash_put(currencyPluralIsoCodes, iso, iso, &ec4); 1.1120 + } 1.1121 + } 1.1122 + int32_t num = ures_getSize(names); 1.1123 + int32_t len; 1.1124 + for (int32_t j = 0; j < num; ++j) { 1.1125 + // TODO: remove duplicates between singular name and 1.1126 + // currency long name? 1.1127 + s = ures_getStringByIndex(names, j, &len, &ec3); 1.1128 + (*currencyNames)[*total_currency_name_count].IsoCode = iso; 1.1129 + UChar* upperName = toUpperCase(s, len, locale); 1.1130 + (*currencyNames)[*total_currency_name_count].currencyName = upperName; 1.1131 + (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED; 1.1132 + (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len; 1.1133 + } 1.1134 + ures_close(names); 1.1135 + } 1.1136 + ures_close(curr_p); 1.1137 + ures_close(curr); 1.1138 + ures_close(rb); 1.1139 + 1.1140 + if (!fallback(loc)) { 1.1141 + break; 1.1142 + } 1.1143 + } 1.1144 + 1.1145 + uhash_close(currencyIsoCodes); 1.1146 + uhash_close(currencyPluralIsoCodes); 1.1147 + 1.1148 + // quick sort the struct 1.1149 + qsort(*currencyNames, *total_currency_name_count, 1.1150 + sizeof(CurrencyNameStruct), currencyNameComparator); 1.1151 + qsort(*currencySymbols, *total_currency_symbol_count, 1.1152 + sizeof(CurrencyNameStruct), currencyNameComparator); 1.1153 + 1.1154 +#ifdef UCURR_DEBUG 1.1155 + printf("currency name count: %d\n", *total_currency_name_count); 1.1156 + for (int32_t index = 0; index < *total_currency_name_count; ++index) { 1.1157 + printf("index: %d\n", index); 1.1158 + printf("iso: %s\n", (*currencyNames)[index].IsoCode); 1.1159 + char curNameBuf[1024]; 1.1160 + memset(curNameBuf, 0, 1024); 1.1161 + u_austrncpy(curNameBuf, (*currencyNames)[index].currencyName, (*currencyNames)[index].currencyNameLen); 1.1162 + printf("currencyName: %s\n", curNameBuf); 1.1163 + printf("len: %d\n", (*currencyNames)[index].currencyNameLen); 1.1164 + } 1.1165 + printf("currency symbol count: %d\n", *total_currency_symbol_count); 1.1166 + for (int32_t index = 0; index < *total_currency_symbol_count; ++index) { 1.1167 + printf("index: %d\n", index); 1.1168 + printf("iso: %s\n", (*currencySymbols)[index].IsoCode); 1.1169 + char curNameBuf[1024]; 1.1170 + memset(curNameBuf, 0, 1024); 1.1171 + u_austrncpy(curNameBuf, (*currencySymbols)[index].currencyName, (*currencySymbols)[index].currencyNameLen); 1.1172 + printf("currencySymbol: %s\n", curNameBuf); 1.1173 + printf("len: %d\n", (*currencySymbols)[index].currencyNameLen); 1.1174 + } 1.1175 +#endif 1.1176 +} 1.1177 + 1.1178 +// @param currencyNames: currency names array 1.1179 +// @param indexInCurrencyNames: the index of the character in currency names 1.1180 +// array against which the comparison is done 1.1181 +// @param key: input text char to compare against 1.1182 +// @param begin(IN/OUT): the begin index of matching range in currency names array 1.1183 +// @param end(IN/OUT): the end index of matching range in currency names array. 1.1184 +static int32_t 1.1185 +binarySearch(const CurrencyNameStruct* currencyNames, 1.1186 + int32_t indexInCurrencyNames, 1.1187 + const UChar key, 1.1188 + int32_t* begin, int32_t* end) { 1.1189 +#ifdef UCURR_DEBUG 1.1190 + printf("key = %x\n", key); 1.1191 +#endif 1.1192 + int32_t first = *begin; 1.1193 + int32_t last = *end; 1.1194 + while (first <= last) { 1.1195 + int32_t mid = (first + last) / 2; // compute mid point. 1.1196 + if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) { 1.1197 + first = mid + 1; 1.1198 + } else { 1.1199 + if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) { 1.1200 + first = mid + 1; 1.1201 + } 1.1202 + else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) { 1.1203 + last = mid - 1; 1.1204 + } 1.1205 + else { 1.1206 + // Find a match, and looking for ranges 1.1207 + // Now do two more binary searches. First, on the left side for 1.1208 + // the greatest L such that CurrencyNameStruct[L] < key. 1.1209 + int32_t L = *begin; 1.1210 + int32_t R = mid; 1.1211 + 1.1212 +#ifdef UCURR_DEBUG 1.1213 + printf("mid = %d\n", mid); 1.1214 +#endif 1.1215 + while (L < R) { 1.1216 + int32_t M = (L + R) / 2; 1.1217 +#ifdef UCURR_DEBUG 1.1218 + printf("L = %d, R = %d, M = %d\n", L, R, M); 1.1219 +#endif 1.1220 + if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) { 1.1221 + L = M + 1; 1.1222 + } else { 1.1223 + if (currencyNames[M].currencyName[indexInCurrencyNames] < key) { 1.1224 + L = M + 1; 1.1225 + } else { 1.1226 +#ifdef UCURR_DEBUG 1.1227 + U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key); 1.1228 +#endif 1.1229 + R = M; 1.1230 + } 1.1231 + } 1.1232 + } 1.1233 +#ifdef UCURR_DEBUG 1.1234 + U_ASSERT(L == R); 1.1235 +#endif 1.1236 + *begin = L; 1.1237 +#ifdef UCURR_DEBUG 1.1238 + printf("begin = %d\n", *begin); 1.1239 + U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key); 1.1240 +#endif 1.1241 + 1.1242 + // Now for the second search, finding the least R such that 1.1243 + // key < CurrencyNameStruct[R]. 1.1244 + L = mid; 1.1245 + R = *end; 1.1246 + while (L < R) { 1.1247 + int32_t M = (L + R) / 2; 1.1248 +#ifdef UCURR_DEBUG 1.1249 + printf("L = %d, R = %d, M = %d\n", L, R, M); 1.1250 +#endif 1.1251 + if (currencyNames[M].currencyNameLen < indexInCurrencyNames) { 1.1252 + L = M + 1; 1.1253 + } else { 1.1254 + if (currencyNames[M].currencyName[indexInCurrencyNames] > key) { 1.1255 + R = M; 1.1256 + } else { 1.1257 +#ifdef UCURR_DEBUG 1.1258 + U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key); 1.1259 +#endif 1.1260 + L = M + 1; 1.1261 + } 1.1262 + } 1.1263 + } 1.1264 +#ifdef UCURR_DEBUG 1.1265 + U_ASSERT(L == R); 1.1266 +#endif 1.1267 + if (currencyNames[R].currencyName[indexInCurrencyNames] > key) { 1.1268 + *end = R - 1; 1.1269 + } else { 1.1270 + *end = R; 1.1271 + } 1.1272 +#ifdef UCURR_DEBUG 1.1273 + printf("end = %d\n", *end); 1.1274 +#endif 1.1275 + 1.1276 + // now, found the range. check whether there is exact match 1.1277 + if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) { 1.1278 + return *begin; // find range and exact match. 1.1279 + } 1.1280 + return -1; // find range, but no exact match. 1.1281 + } 1.1282 + } 1.1283 + } 1.1284 + *begin = -1; 1.1285 + *end = -1; 1.1286 + return -1; // failed to find range. 1.1287 +} 1.1288 + 1.1289 + 1.1290 +// Linear search "text" in "currencyNames". 1.1291 +// @param begin, end: the begin and end index in currencyNames, within which 1.1292 +// range should the search be performed. 1.1293 +// @param textLen: the length of the text to be compared 1.1294 +// @param maxMatchLen(IN/OUT): passing in the computed max matching length 1.1295 +// pass out the new max matching length 1.1296 +// @param maxMatchIndex: the index in currencyName which has the longest 1.1297 +// match with input text. 1.1298 +static void 1.1299 +linearSearch(const CurrencyNameStruct* currencyNames, 1.1300 + int32_t begin, int32_t end, 1.1301 + const UChar* text, int32_t textLen, 1.1302 + int32_t *maxMatchLen, int32_t* maxMatchIndex) { 1.1303 + for (int32_t index = begin; index <= end; ++index) { 1.1304 + int32_t len = currencyNames[index].currencyNameLen; 1.1305 + if (len > *maxMatchLen && len <= textLen && 1.1306 + uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) { 1.1307 + *maxMatchIndex = index; 1.1308 + *maxMatchLen = len; 1.1309 +#ifdef UCURR_DEBUG 1.1310 + printf("maxMatchIndex = %d, maxMatchLen = %d\n", 1.1311 + *maxMatchIndex, *maxMatchLen); 1.1312 +#endif 1.1313 + } 1.1314 + } 1.1315 +} 1.1316 + 1.1317 +#define LINEAR_SEARCH_THRESHOLD 10 1.1318 + 1.1319 +// Find longest match between "text" and currency names in "currencyNames". 1.1320 +// @param total_currency_count: total number of currency names in CurrencyNames. 1.1321 +// @param textLen: the length of the text to be compared 1.1322 +// @param maxMatchLen: passing in the computed max matching length 1.1323 +// pass out the new max matching length 1.1324 +// @param maxMatchIndex: the index in currencyName which has the longest 1.1325 +// match with input text. 1.1326 +static void 1.1327 +searchCurrencyName(const CurrencyNameStruct* currencyNames, 1.1328 + int32_t total_currency_count, 1.1329 + const UChar* text, int32_t textLen, 1.1330 + int32_t* maxMatchLen, int32_t* maxMatchIndex) { 1.1331 + *maxMatchIndex = -1; 1.1332 + *maxMatchLen = 0; 1.1333 + int32_t matchIndex = -1; 1.1334 + int32_t binarySearchBegin = 0; 1.1335 + int32_t binarySearchEnd = total_currency_count - 1; 1.1336 + // It is a variant of binary search. 1.1337 + // For example, given the currency names in currencyNames array are: 1.1338 + // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E.... 1.1339 + // and the input text is BBEXST 1.1340 + // The first round binary search search "B" in the text against 1.1341 + // the first char in currency names, and find the first char matching range 1.1342 + // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B"). 1.1343 + // The 2nd round binary search search the second "B" in the text against 1.1344 + // the 2nd char in currency names, and narrow the matching range to 1.1345 + // "BB BBEX BBEXYZ" (and the maximum matching "BB"). 1.1346 + // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing 1.1347 + // maximum matching). 1.1348 + // The 4th round returns the same range (the maximum matching is "BBEX"). 1.1349 + // The 5th round returns no matching range. 1.1350 + for (int32_t index = 0; index < textLen; ++index) { 1.1351 + // matchIndex saves the one with exact match till the current point. 1.1352 + // [binarySearchBegin, binarySearchEnd] saves the matching range. 1.1353 + matchIndex = binarySearch(currencyNames, index, 1.1354 + text[index], 1.1355 + &binarySearchBegin, &binarySearchEnd); 1.1356 + if (binarySearchBegin == -1) { // did not find the range 1.1357 + break; 1.1358 + } 1.1359 + if (matchIndex != -1) { 1.1360 + // find an exact match for text from text[0] to text[index] 1.1361 + // in currencyNames array. 1.1362 + *maxMatchLen = index + 1; 1.1363 + *maxMatchIndex = matchIndex; 1.1364 + } 1.1365 + if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) { 1.1366 + // linear search if within threshold. 1.1367 + linearSearch(currencyNames, binarySearchBegin, binarySearchEnd, 1.1368 + text, textLen, 1.1369 + maxMatchLen, maxMatchIndex); 1.1370 + break; 1.1371 + } 1.1372 + } 1.1373 + return; 1.1374 +} 1.1375 + 1.1376 +//========================= currency name cache ===================== 1.1377 +typedef struct { 1.1378 + char locale[ULOC_FULLNAME_CAPACITY]; //key 1.1379 + // currency names, case insensitive 1.1380 + CurrencyNameStruct* currencyNames; // value 1.1381 + int32_t totalCurrencyNameCount; // currency name count 1.1382 + // currency symbols and ISO code, case sensitive 1.1383 + CurrencyNameStruct* currencySymbols; // value 1.1384 + int32_t totalCurrencySymbolCount; // count 1.1385 + // reference count. 1.1386 + // reference count is set to 1 when an entry is put to cache. 1.1387 + // it increases by 1 before accessing, and decreased by 1 after accessing. 1.1388 + // The entry is deleted when ref count is zero, which means 1.1389 + // the entry is replaced out of cache and no process is accessing it. 1.1390 + int32_t refCount; 1.1391 +} CurrencyNameCacheEntry; 1.1392 + 1.1393 + 1.1394 +#define CURRENCY_NAME_CACHE_NUM 10 1.1395 + 1.1396 +// Reserve 10 cache entries. 1.1397 +static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL}; 1.1398 +// Using an index to indicate which entry to be replaced when cache is full. 1.1399 +// It is a simple round-robin replacement strategy. 1.1400 +static int8_t currentCacheEntryIndex = 0; 1.1401 + 1.1402 +static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER; 1.1403 + 1.1404 +// Cache deletion 1.1405 +static void 1.1406 +deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) { 1.1407 + for (int32_t index = 0; index < count; ++index) { 1.1408 + if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) { 1.1409 + uprv_free(currencyNames[index].currencyName); 1.1410 + } 1.1411 + } 1.1412 + uprv_free(currencyNames); 1.1413 +} 1.1414 + 1.1415 + 1.1416 +static void 1.1417 +deleteCacheEntry(CurrencyNameCacheEntry* entry) { 1.1418 + deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount); 1.1419 + deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount); 1.1420 + uprv_free(entry); 1.1421 +} 1.1422 + 1.1423 + 1.1424 +// Cache clean up 1.1425 +static UBool U_CALLCONV 1.1426 +currency_cache_cleanup(void) { 1.1427 + for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) { 1.1428 + if (currCache[i]) { 1.1429 + deleteCacheEntry(currCache[i]); 1.1430 + currCache[i] = 0; 1.1431 + } 1.1432 + } 1.1433 + return TRUE; 1.1434 +} 1.1435 + 1.1436 + 1.1437 +U_CFUNC void 1.1438 +uprv_parseCurrency(const char* locale, 1.1439 + const icu::UnicodeString& text, 1.1440 + icu::ParsePosition& pos, 1.1441 + int8_t type, 1.1442 + UChar* result, 1.1443 + UErrorCode& ec) 1.1444 +{ 1.1445 + U_NAMESPACE_USE 1.1446 + 1.1447 + if (U_FAILURE(ec)) { 1.1448 + return; 1.1449 + } 1.1450 + 1.1451 + int32_t total_currency_name_count = 0; 1.1452 + CurrencyNameStruct* currencyNames = NULL; 1.1453 + int32_t total_currency_symbol_count = 0; 1.1454 + CurrencyNameStruct* currencySymbols = NULL; 1.1455 + CurrencyNameCacheEntry* cacheEntry = NULL; 1.1456 + 1.1457 + umtx_lock(&gCurrencyCacheMutex); 1.1458 + // in order to handle racing correctly, 1.1459 + // not putting 'search' in a separate function. 1.1460 + int8_t found = -1; 1.1461 + for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) { 1.1462 + if (currCache[i]!= NULL && 1.1463 + uprv_strcmp(locale, currCache[i]->locale) == 0) { 1.1464 + found = i; 1.1465 + break; 1.1466 + } 1.1467 + } 1.1468 + if (found != -1) { 1.1469 + cacheEntry = currCache[found]; 1.1470 + currencyNames = cacheEntry->currencyNames; 1.1471 + total_currency_name_count = cacheEntry->totalCurrencyNameCount; 1.1472 + currencySymbols = cacheEntry->currencySymbols; 1.1473 + total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount; 1.1474 + ++(cacheEntry->refCount); 1.1475 + } 1.1476 + umtx_unlock(&gCurrencyCacheMutex); 1.1477 + if (found == -1) { 1.1478 + collectCurrencyNames(locale, ¤cyNames, &total_currency_name_count, ¤cySymbols, &total_currency_symbol_count, ec); 1.1479 + if (U_FAILURE(ec)) { 1.1480 + return; 1.1481 + } 1.1482 + umtx_lock(&gCurrencyCacheMutex); 1.1483 + // check again. 1.1484 + int8_t found = -1; 1.1485 + for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) { 1.1486 + if (currCache[i]!= NULL && 1.1487 + uprv_strcmp(locale, currCache[i]->locale) == 0) { 1.1488 + found = i; 1.1489 + break; 1.1490 + } 1.1491 + } 1.1492 + if (found == -1) { 1.1493 + // insert new entry to 1.1494 + // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM 1.1495 + // and remove the existing entry 1.1496 + // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM 1.1497 + // from cache. 1.1498 + cacheEntry = currCache[currentCacheEntryIndex]; 1.1499 + if (cacheEntry) { 1.1500 + --(cacheEntry->refCount); 1.1501 + // delete if the ref count is zero 1.1502 + if (cacheEntry->refCount == 0) { 1.1503 + deleteCacheEntry(cacheEntry); 1.1504 + } 1.1505 + } 1.1506 + cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry)); 1.1507 + currCache[currentCacheEntryIndex] = cacheEntry; 1.1508 + uprv_strcpy(cacheEntry->locale, locale); 1.1509 + cacheEntry->currencyNames = currencyNames; 1.1510 + cacheEntry->totalCurrencyNameCount = total_currency_name_count; 1.1511 + cacheEntry->currencySymbols = currencySymbols; 1.1512 + cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count; 1.1513 + cacheEntry->refCount = 2; // one for cache, one for reference 1.1514 + currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM; 1.1515 + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup); 1.1516 + 1.1517 + } else { 1.1518 + deleteCurrencyNames(currencyNames, total_currency_name_count); 1.1519 + deleteCurrencyNames(currencySymbols, total_currency_symbol_count); 1.1520 + cacheEntry = currCache[found]; 1.1521 + currencyNames = cacheEntry->currencyNames; 1.1522 + total_currency_name_count = cacheEntry->totalCurrencyNameCount; 1.1523 + currencySymbols = cacheEntry->currencySymbols; 1.1524 + total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount; 1.1525 + ++(cacheEntry->refCount); 1.1526 + } 1.1527 + umtx_unlock(&gCurrencyCacheMutex); 1.1528 + } 1.1529 + 1.1530 + int32_t start = pos.getIndex(); 1.1531 + 1.1532 + UChar inputText[MAX_CURRENCY_NAME_LEN]; 1.1533 + UChar upperText[MAX_CURRENCY_NAME_LEN]; 1.1534 + int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start); 1.1535 + text.extract(start, textLen, inputText); 1.1536 + UErrorCode ec1 = U_ZERO_ERROR; 1.1537 + textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, locale, &ec1); 1.1538 + 1.1539 + int32_t max = 0; 1.1540 + int32_t matchIndex = -1; 1.1541 + // case in-sensitive comparision against currency names 1.1542 + searchCurrencyName(currencyNames, total_currency_name_count, 1.1543 + upperText, textLen, &max, &matchIndex); 1.1544 + 1.1545 +#ifdef UCURR_DEBUG 1.1546 + printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex); 1.1547 +#endif 1.1548 + 1.1549 + int32_t maxInSymbol = 0; 1.1550 + int32_t matchIndexInSymbol = -1; 1.1551 + if (type != UCURR_LONG_NAME) { // not name only 1.1552 + // case sensitive comparison against currency symbols and ISO code. 1.1553 + searchCurrencyName(currencySymbols, total_currency_symbol_count, 1.1554 + inputText, textLen, 1.1555 + &maxInSymbol, &matchIndexInSymbol); 1.1556 + } 1.1557 + 1.1558 +#ifdef UCURR_DEBUG 1.1559 + printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol); 1.1560 + if(matchIndexInSymbol != -1) { 1.1561 + printf("== ISO=%s\n", currencySymbols[matchIndexInSymbol].IsoCode); 1.1562 + } 1.1563 +#endif 1.1564 + 1.1565 + if (max >= maxInSymbol && matchIndex != -1) { 1.1566 + u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4); 1.1567 + pos.setIndex(start + max); 1.1568 + } else if (maxInSymbol >= max && matchIndexInSymbol != -1) { 1.1569 + u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4); 1.1570 + pos.setIndex(start + maxInSymbol); 1.1571 + } 1.1572 + 1.1573 + // decrease reference count 1.1574 + umtx_lock(&gCurrencyCacheMutex); 1.1575 + --(cacheEntry->refCount); 1.1576 + if (cacheEntry->refCount == 0) { // remove 1.1577 + deleteCacheEntry(cacheEntry); 1.1578 + } 1.1579 + umtx_unlock(&gCurrencyCacheMutex); 1.1580 +} 1.1581 + 1.1582 + 1.1583 +/** 1.1584 + * Internal method. Given a currency ISO code and a locale, return 1.1585 + * the "static" currency name. This is usually the same as the 1.1586 + * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the 1.1587 + * format is applied to the number 2.0 (to yield the more common 1.1588 + * plural) to return a static name. 1.1589 + * 1.1590 + * This is used for backward compatibility with old currency logic in 1.1591 + * DecimalFormat and DecimalFormatSymbols. 1.1592 + */ 1.1593 +U_CFUNC void 1.1594 +uprv_getStaticCurrencyName(const UChar* iso, const char* loc, 1.1595 + icu::UnicodeString& result, UErrorCode& ec) 1.1596 +{ 1.1597 + U_NAMESPACE_USE 1.1598 + 1.1599 + UBool isChoiceFormat; 1.1600 + int32_t len; 1.1601 + const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME, 1.1602 + &isChoiceFormat, &len, &ec); 1.1603 + if (U_SUCCESS(ec)) { 1.1604 + // If this is a ChoiceFormat currency, then format an 1.1605 + // arbitrary value; pick something != 1; more common. 1.1606 + result.truncate(0); 1.1607 + if (isChoiceFormat) { 1.1608 + ChoiceFormat f(UnicodeString(TRUE, currname, len), ec); 1.1609 + if (U_SUCCESS(ec)) { 1.1610 + f.format(2.0, result); 1.1611 + } else { 1.1612 + result.setTo(iso, -1); 1.1613 + } 1.1614 + } else { 1.1615 + result.setTo(currname, -1); 1.1616 + } 1.1617 + } 1.1618 +} 1.1619 + 1.1620 +U_CAPI int32_t U_EXPORT2 1.1621 +ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) { 1.1622 + return (_findMetaData(currency, *ec))[0]; 1.1623 +} 1.1624 + 1.1625 +U_CAPI double U_EXPORT2 1.1626 +ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) { 1.1627 + const int32_t *data = _findMetaData(currency, *ec); 1.1628 + 1.1629 + // If the meta data is invalid, return 0.0. 1.1630 + if (data[0] < 0 || data[0] > MAX_POW10) { 1.1631 + if (U_SUCCESS(*ec)) { 1.1632 + *ec = U_INVALID_FORMAT_ERROR; 1.1633 + } 1.1634 + return 0.0; 1.1635 + } 1.1636 + 1.1637 + // If there is no rounding, return 0.0 to indicate no rounding. A 1.1638 + // rounding value (data[1]) of 0 or 1 indicates no rounding. 1.1639 + if (data[1] < 2) { 1.1640 + return 0.0; 1.1641 + } 1.1642 + 1.1643 + // Return data[1] / 10^(data[0]). The only actual rounding data, 1.1644 + // as of this writing, is CHF { 2, 5 }. 1.1645 + return double(data[1]) / POW10[data[0]]; 1.1646 +} 1.1647 + 1.1648 +U_CDECL_BEGIN 1.1649 + 1.1650 +typedef struct UCurrencyContext { 1.1651 + uint32_t currType; /* UCurrCurrencyType */ 1.1652 + uint32_t listIdx; 1.1653 +} UCurrencyContext; 1.1654 + 1.1655 +/* 1.1656 +Please keep this list in alphabetical order. 1.1657 +You can look at the CLDR supplemental data or ISO-4217 for the meaning of some 1.1658 +of these items. 1.1659 +ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html 1.1660 +*/ 1.1661 +static const struct CurrencyList { 1.1662 + const char *currency; 1.1663 + uint32_t currType; 1.1664 +} gCurrencyList[] = { 1.1665 + {"ADP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1666 + {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1667 + {"AFA", UCURR_COMMON|UCURR_DEPRECATED}, 1.1668 + {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1669 + {"ALK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1670 + {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1671 + {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1672 + {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1673 + {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1674 + {"AOK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1675 + {"AON", UCURR_COMMON|UCURR_DEPRECATED}, 1.1676 + {"AOR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1677 + {"ARA", UCURR_COMMON|UCURR_DEPRECATED}, 1.1678 + {"ARL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1679 + {"ARM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1680 + {"ARP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1681 + {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1682 + {"ATS", UCURR_COMMON|UCURR_DEPRECATED}, 1.1683 + {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1684 + {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1685 + {"AZM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1686 + {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1687 + {"BAD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1688 + {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1689 + {"BAN", UCURR_COMMON|UCURR_DEPRECATED}, 1.1690 + {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1691 + {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1692 + {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1693 + {"BEF", UCURR_COMMON|UCURR_DEPRECATED}, 1.1694 + {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1695 + {"BGL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1696 + {"BGM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1697 + {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1698 + {"BGO", UCURR_COMMON|UCURR_DEPRECATED}, 1.1699 + {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1700 + {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1701 + {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1702 + {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1703 + {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1704 + {"BOL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1705 + {"BOP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1706 + {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1707 + {"BRB", UCURR_COMMON|UCURR_DEPRECATED}, 1.1708 + {"BRC", UCURR_COMMON|UCURR_DEPRECATED}, 1.1709 + {"BRE", UCURR_COMMON|UCURR_DEPRECATED}, 1.1710 + {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1711 + {"BRN", UCURR_COMMON|UCURR_DEPRECATED}, 1.1712 + {"BRR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1713 + {"BRZ", UCURR_COMMON|UCURR_DEPRECATED}, 1.1714 + {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1715 + {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1716 + {"BUK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1717 + {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1718 + {"BYB", UCURR_COMMON|UCURR_DEPRECATED}, 1.1719 + {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1720 + {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1721 + {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1722 + {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1723 + {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1724 + {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1725 + {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1726 + {"CLE", UCURR_COMMON|UCURR_DEPRECATED}, 1.1727 + {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1728 + {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1729 + {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1730 + {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1731 + {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1732 + {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1733 + {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1734 + {"CSD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1735 + {"CSK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1736 + {"CUC", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1737 + {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1738 + {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1739 + {"CYP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1740 + {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1741 + {"DDM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1742 + {"DEM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1743 + {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1744 + {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1745 + {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1746 + {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1747 + {"ECS", UCURR_COMMON|UCURR_DEPRECATED}, 1.1748 + {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1749 + {"EEK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1750 + {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1751 + {"EQE", UCURR_COMMON|UCURR_DEPRECATED}, 1.1752 + {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1753 + {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1754 + {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1755 + {"ESP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1756 + {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1757 + {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1758 + {"FIM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1759 + {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1760 + {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1761 + {"FRF", UCURR_COMMON|UCURR_DEPRECATED}, 1.1762 + {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1763 + {"GEK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1764 + {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1765 + {"GHC", UCURR_COMMON|UCURR_DEPRECATED}, 1.1766 + {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1767 + {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1768 + {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1769 + {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1770 + {"GNS", UCURR_COMMON|UCURR_DEPRECATED}, 1.1771 + {"GQE", UCURR_COMMON|UCURR_DEPRECATED}, 1.1772 + {"GRD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1773 + {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1774 + {"GWE", UCURR_COMMON|UCURR_DEPRECATED}, 1.1775 + {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1776 + {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1777 + {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1778 + {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1779 + {"HRD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1780 + {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1781 + {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1782 + {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1783 + {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1784 + {"IEP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1785 + {"ILP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1786 + {"ILR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1787 + {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1788 + {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1789 + {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1790 + {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1791 + {"ISJ", UCURR_COMMON|UCURR_DEPRECATED}, 1.1792 + {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1793 + {"ITL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1794 + {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1795 + {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1796 + {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1797 + {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1798 + {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1799 + {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1800 + {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1801 + {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1802 + {"KRH", UCURR_COMMON|UCURR_DEPRECATED}, 1.1803 + {"KRO", UCURR_COMMON|UCURR_DEPRECATED}, 1.1804 + {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1805 + {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1806 + {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1807 + {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1808 + {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1809 + {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1810 + {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1811 + {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1812 + {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1813 + {"LSM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1814 + {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1815 + {"LTT", UCURR_COMMON|UCURR_DEPRECATED}, 1.1816 + {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1817 + {"LUF", UCURR_COMMON|UCURR_DEPRECATED}, 1.1818 + {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1819 + {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1820 + {"LVR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1821 + {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1822 + {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1823 + {"MAF", UCURR_COMMON|UCURR_DEPRECATED}, 1.1824 + {"MCF", UCURR_COMMON|UCURR_DEPRECATED}, 1.1825 + {"MDC", UCURR_COMMON|UCURR_DEPRECATED}, 1.1826 + {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1827 + {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1828 + {"MGF", UCURR_COMMON|UCURR_DEPRECATED}, 1.1829 + {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1830 + {"MKN", UCURR_COMMON|UCURR_DEPRECATED}, 1.1831 + {"MLF", UCURR_COMMON|UCURR_DEPRECATED}, 1.1832 + {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1833 + {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1834 + {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1835 + {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1836 + {"MTL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1837 + {"MTP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1838 + {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1839 + {"MVP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1840 + {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1841 + {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1842 + {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1843 + {"MXP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1844 + {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1845 + {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1846 + {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1847 + {"MZM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1848 + {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1849 + {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1850 + {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1851 + {"NIC", UCURR_COMMON|UCURR_DEPRECATED}, 1.1852 + {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1853 + {"NLG", UCURR_COMMON|UCURR_DEPRECATED}, 1.1854 + {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1855 + {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1856 + {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1857 + {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1858 + {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1859 + {"PEI", UCURR_COMMON|UCURR_DEPRECATED}, 1.1860 + {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1861 + {"PES", UCURR_COMMON|UCURR_DEPRECATED}, 1.1862 + {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1863 + {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1864 + {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1865 + {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1866 + {"PLZ", UCURR_COMMON|UCURR_DEPRECATED}, 1.1867 + {"PTE", UCURR_COMMON|UCURR_DEPRECATED}, 1.1868 + {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1869 + {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1870 + {"RHD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1871 + {"ROL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1872 + {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1873 + {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1874 + {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1875 + {"RUR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1876 + {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1877 + {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1878 + {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1879 + {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1880 + {"SDD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1881 + {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1882 + {"SDP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1883 + {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1884 + {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1885 + {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1886 + {"SIT", UCURR_COMMON|UCURR_DEPRECATED}, 1.1887 + {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1888 + {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1889 + {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1890 + {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1891 + {"SRG", UCURR_COMMON|UCURR_DEPRECATED}, 1.1892 + {"SSP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1893 + {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1894 + {"SUR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1895 + {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1896 + {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1897 + {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1898 + {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1899 + {"TJR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1900 + {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1901 + {"TMM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1902 + {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1903 + {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1904 + {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1905 + {"TPE", UCURR_COMMON|UCURR_DEPRECATED}, 1.1906 + {"TRL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1907 + {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1908 + {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1909 + {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1910 + {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1911 + {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1912 + {"UAK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1913 + {"UGS", UCURR_COMMON|UCURR_DEPRECATED}, 1.1914 + {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1915 + {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1916 + {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1917 + {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1918 + {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1919 + {"UYP", UCURR_COMMON|UCURR_DEPRECATED}, 1.1920 + {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1921 + {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1922 + {"VEB", UCURR_COMMON|UCURR_DEPRECATED}, 1.1923 + {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1924 + {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1925 + {"VNN", UCURR_COMMON|UCURR_DEPRECATED}, 1.1926 + {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1927 + {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1928 + {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1929 + {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1930 + {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1931 + {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1932 + {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1933 + {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1934 + {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1935 + {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1936 + {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1937 + {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED}, 1.1938 + {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1939 + {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1940 + {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1941 + {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1942 + {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1943 + {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1944 + {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1945 + {"XSU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1946 + {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1947 + {"XUA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1948 + {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1949 + {"YDD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1950 + {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1951 + {"YUD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1952 + {"YUM", UCURR_COMMON|UCURR_DEPRECATED}, 1.1953 + {"YUN", UCURR_COMMON|UCURR_DEPRECATED}, 1.1954 + {"YUR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1955 + {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, 1.1956 + {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1957 + {"ZMK", UCURR_COMMON|UCURR_DEPRECATED}, 1.1958 + {"ZMW", UCURR_COMMON|UCURR_NON_DEPRECATED}, 1.1959 + {"ZRN", UCURR_COMMON|UCURR_DEPRECATED}, 1.1960 + {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED}, 1.1961 + {"ZWL", UCURR_COMMON|UCURR_DEPRECATED}, 1.1962 + {"ZWR", UCURR_COMMON|UCURR_DEPRECATED}, 1.1963 + {"ZWD", UCURR_COMMON|UCURR_DEPRECATED}, 1.1964 + { NULL, 0 } // Leave here to denote the end of the list. 1.1965 +}; 1.1966 + 1.1967 +#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \ 1.1968 + ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch)) 1.1969 + 1.1970 +static int32_t U_CALLCONV 1.1971 +ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) { 1.1972 + UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context); 1.1973 + uint32_t currType = myContext->currType; 1.1974 + int32_t count = 0; 1.1975 + 1.1976 + /* Count the number of items matching the type we are looking for. */ 1.1977 + for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) { 1.1978 + if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) { 1.1979 + count++; 1.1980 + } 1.1981 + } 1.1982 + return count; 1.1983 +} 1.1984 + 1.1985 +static const char* U_CALLCONV 1.1986 +ucurr_nextCurrencyList(UEnumeration *enumerator, 1.1987 + int32_t* resultLength, 1.1988 + UErrorCode * /*pErrorCode*/) 1.1989 +{ 1.1990 + UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context); 1.1991 + 1.1992 + /* Find the next in the list that matches the type we are looking for. */ 1.1993 + while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) { 1.1994 + const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++]; 1.1995 + if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType)) 1.1996 + { 1.1997 + if (resultLength) { 1.1998 + *resultLength = 3; /* Currency codes are only 3 chars long */ 1.1999 + } 1.2000 + return currItem->currency; 1.2001 + } 1.2002 + } 1.2003 + /* We enumerated too far. */ 1.2004 + if (resultLength) { 1.2005 + *resultLength = 0; 1.2006 + } 1.2007 + return NULL; 1.2008 +} 1.2009 + 1.2010 +static void U_CALLCONV 1.2011 +ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) { 1.2012 + ((UCurrencyContext *)(enumerator->context))->listIdx = 0; 1.2013 +} 1.2014 + 1.2015 +static void U_CALLCONV 1.2016 +ucurr_closeCurrencyList(UEnumeration *enumerator) { 1.2017 + uprv_free(enumerator->context); 1.2018 + uprv_free(enumerator); 1.2019 +} 1.2020 + 1.2021 +static void U_CALLCONV 1.2022 +ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){ 1.2023 + UErrorCode localStatus = U_ZERO_ERROR; 1.2024 + 1.2025 + // Look up the CurrencyMap element in the root bundle. 1.2026 + UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus); 1.2027 + UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); 1.2028 + 1.2029 + if (U_SUCCESS(localStatus)) { 1.2030 + // process each entry in currency map 1.2031 + for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) { 1.2032 + // get the currency resource 1.2033 + UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus); 1.2034 + // process each currency 1.2035 + if (U_SUCCESS(localStatus)) { 1.2036 + for (int32_t j=0; j<ures_getSize(currencyArray); j++) { 1.2037 + // get the currency resource 1.2038 + UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus); 1.2039 + IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry)); 1.2040 + if (entry == NULL) { 1.2041 + *status = U_MEMORY_ALLOCATION_ERROR; 1.2042 + return; 1.2043 + } 1.2044 + 1.2045 + // get the ISO code 1.2046 + int32_t isoLength = 0; 1.2047 + UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus); 1.2048 + if (idRes == NULL) { 1.2049 + continue; 1.2050 + } 1.2051 + const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus); 1.2052 + 1.2053 + // get from date 1.2054 + UDate fromDate = U_DATE_MIN; 1.2055 + UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus); 1.2056 + 1.2057 + if (U_SUCCESS(localStatus)) { 1.2058 + int32_t fromLength = 0; 1.2059 + const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus); 1.2060 + int64_t currDate64 = (int64_t)fromArray[0] << 32; 1.2061 + currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); 1.2062 + fromDate = (UDate)currDate64; 1.2063 + } 1.2064 + ures_close(fromRes); 1.2065 + 1.2066 + // get to date 1.2067 + UDate toDate = U_DATE_MAX; 1.2068 + localStatus = U_ZERO_ERROR; 1.2069 + UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus); 1.2070 + 1.2071 + if (U_SUCCESS(localStatus)) { 1.2072 + int32_t toLength = 0; 1.2073 + const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus); 1.2074 + int64_t currDate64 = (int64_t)toArray[0] << 32; 1.2075 + currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); 1.2076 + toDate = (UDate)currDate64; 1.2077 + } 1.2078 + ures_close(toRes); 1.2079 + 1.2080 + ures_close(idRes); 1.2081 + ures_close(currencyRes); 1.2082 + 1.2083 + entry->isoCode = isoCode; 1.2084 + entry->from = fromDate; 1.2085 + entry->to = toDate; 1.2086 + 1.2087 + localStatus = U_ZERO_ERROR; 1.2088 + uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus); 1.2089 + } 1.2090 + } else { 1.2091 + *status = localStatus; 1.2092 + } 1.2093 + ures_close(currencyArray); 1.2094 + } 1.2095 + } else { 1.2096 + *status = localStatus; 1.2097 + } 1.2098 + 1.2099 + ures_close(currencyMapArray); 1.2100 +} 1.2101 + 1.2102 +static const UEnumeration gEnumCurrencyList = { 1.2103 + NULL, 1.2104 + NULL, 1.2105 + ucurr_closeCurrencyList, 1.2106 + ucurr_countCurrencyList, 1.2107 + uenum_unextDefault, 1.2108 + ucurr_nextCurrencyList, 1.2109 + ucurr_resetCurrencyList 1.2110 +}; 1.2111 +U_CDECL_END 1.2112 + 1.2113 + 1.2114 +static void U_CALLCONV initIsoCodes(UErrorCode &status) { 1.2115 + U_ASSERT(gIsoCodes == NULL); 1.2116 + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); 1.2117 + 1.2118 + UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); 1.2119 + if (U_FAILURE(status)) { 1.2120 + return; 1.2121 + } 1.2122 + uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry); 1.2123 + 1.2124 + ucurr_createCurrencyList(isoCodes, &status); 1.2125 + if (U_FAILURE(status)) { 1.2126 + uhash_close(isoCodes); 1.2127 + return; 1.2128 + } 1.2129 + gIsoCodes = isoCodes; // Note: gIsoCodes is const. Once set up here it is never altered, 1.2130 + // and read only access is safe without synchronization. 1.2131 +} 1.2132 + 1.2133 +static void populateCurrSymbolsEquiv(icu::Hashtable *hash, UErrorCode &status) { 1.2134 + if (U_FAILURE(status)) { 1.2135 + return; 1.2136 + } 1.2137 + int32_t length = sizeof(EQUIV_CURRENCY_SYMBOLS) / sizeof(EQUIV_CURRENCY_SYMBOLS[0]); 1.2138 + for (int32_t i = 0; i < length; ++i) { 1.2139 + icu::UnicodeString lhs(EQUIV_CURRENCY_SYMBOLS[i][0], -1, US_INV); 1.2140 + icu::UnicodeString rhs(EQUIV_CURRENCY_SYMBOLS[i][1], -1, US_INV); 1.2141 + makeEquivalent(lhs.unescape(), rhs.unescape(), hash, status); 1.2142 + if (U_FAILURE(status)) { 1.2143 + return; 1.2144 + } 1.2145 + } 1.2146 +} 1.2147 + 1.2148 +static void U_CALLCONV initCurrSymbolsEquiv() { 1.2149 + U_ASSERT(gCurrSymbolsEquiv == NULL); 1.2150 + UErrorCode status = U_ZERO_ERROR; 1.2151 + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); 1.2152 + icu::Hashtable *temp = new icu::Hashtable(status); 1.2153 + if (temp == NULL) { 1.2154 + return; 1.2155 + } 1.2156 + if (U_FAILURE(status)) { 1.2157 + delete temp; 1.2158 + return; 1.2159 + } 1.2160 + temp->setValueDeleter(deleteUnicode); 1.2161 + populateCurrSymbolsEquiv(temp, status); 1.2162 + if (U_FAILURE(status)) { 1.2163 + delete temp; 1.2164 + return; 1.2165 + } 1.2166 + gCurrSymbolsEquiv = temp; 1.2167 +} 1.2168 + 1.2169 +U_CAPI UBool U_EXPORT2 1.2170 +ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) { 1.2171 + umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode); 1.2172 + if (U_FAILURE(*eErrorCode)) { 1.2173 + return FALSE; 1.2174 + } 1.2175 + 1.2176 + IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode); 1.2177 + if (result == NULL) { 1.2178 + return FALSE; 1.2179 + } else if (from > to) { 1.2180 + *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 1.2181 + return FALSE; 1.2182 + } else if ((from > result->to) || (to < result->from)) { 1.2183 + return FALSE; 1.2184 + } 1.2185 + return TRUE; 1.2186 +} 1.2187 + 1.2188 +static const icu::Hashtable* getCurrSymbolsEquiv() { 1.2189 + umtx_initOnce(gCurrSymbolsEquivInitOnce, &initCurrSymbolsEquiv); 1.2190 + return gCurrSymbolsEquiv; 1.2191 +} 1.2192 + 1.2193 +U_CAPI UEnumeration * U_EXPORT2 1.2194 +ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) { 1.2195 + UEnumeration *myEnum = NULL; 1.2196 + UCurrencyContext *myContext; 1.2197 + 1.2198 + myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration)); 1.2199 + if (myEnum == NULL) { 1.2200 + *pErrorCode = U_MEMORY_ALLOCATION_ERROR; 1.2201 + return NULL; 1.2202 + } 1.2203 + uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration)); 1.2204 + myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext)); 1.2205 + if (myContext == NULL) { 1.2206 + *pErrorCode = U_MEMORY_ALLOCATION_ERROR; 1.2207 + uprv_free(myEnum); 1.2208 + return NULL; 1.2209 + } 1.2210 + myContext->currType = currType; 1.2211 + myContext->listIdx = 0; 1.2212 + myEnum->context = myContext; 1.2213 + return myEnum; 1.2214 +} 1.2215 + 1.2216 +U_CAPI int32_t U_EXPORT2 1.2217 +ucurr_countCurrencies(const char* locale, 1.2218 + UDate date, 1.2219 + UErrorCode* ec) 1.2220 +{ 1.2221 + int32_t currCount = 0; 1.2222 + 1.2223 + if (ec != NULL && U_SUCCESS(*ec)) 1.2224 + { 1.2225 + // local variables 1.2226 + UErrorCode localStatus = U_ZERO_ERROR; 1.2227 + char id[ULOC_FULLNAME_CAPACITY]; 1.2228 + uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus); 1.2229 + // get country or country_variant in `id' 1.2230 + /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec); 1.2231 + 1.2232 + if (U_FAILURE(*ec)) 1.2233 + { 1.2234 + return 0; 1.2235 + } 1.2236 + 1.2237 + // Remove variants, which is only needed for registration. 1.2238 + char *idDelim = strchr(id, VAR_DELIM); 1.2239 + if (idDelim) 1.2240 + { 1.2241 + idDelim[0] = 0; 1.2242 + } 1.2243 + 1.2244 + // Look up the CurrencyMap element in the root bundle. 1.2245 + UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus); 1.2246 + UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); 1.2247 + 1.2248 + // Using the id derived from the local, get the currency data 1.2249 + UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus); 1.2250 + 1.2251 + // process each currency to see which one is valid for the given date 1.2252 + if (U_SUCCESS(localStatus)) 1.2253 + { 1.2254 + for (int32_t i=0; i<ures_getSize(countryArray); i++) 1.2255 + { 1.2256 + // get the currency resource 1.2257 + UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus); 1.2258 + 1.2259 + // get the from date 1.2260 + int32_t fromLength = 0; 1.2261 + UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus); 1.2262 + const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus); 1.2263 + 1.2264 + int64_t currDate64 = (int64_t)fromArray[0] << 32; 1.2265 + currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); 1.2266 + UDate fromDate = (UDate)currDate64; 1.2267 + 1.2268 + if (ures_getSize(currencyRes)> 2) 1.2269 + { 1.2270 + int32_t toLength = 0; 1.2271 + UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus); 1.2272 + const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus); 1.2273 + 1.2274 + currDate64 = (int64_t)toArray[0] << 32; 1.2275 + currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); 1.2276 + UDate toDate = (UDate)currDate64; 1.2277 + 1.2278 + if ((fromDate <= date) && (date < toDate)) 1.2279 + { 1.2280 + currCount++; 1.2281 + } 1.2282 + 1.2283 + ures_close(toRes); 1.2284 + } 1.2285 + else 1.2286 + { 1.2287 + if (fromDate <= date) 1.2288 + { 1.2289 + currCount++; 1.2290 + } 1.2291 + } 1.2292 + 1.2293 + // close open resources 1.2294 + ures_close(currencyRes); 1.2295 + ures_close(fromRes); 1.2296 + 1.2297 + } // end For loop 1.2298 + } // end if (U_SUCCESS(localStatus)) 1.2299 + 1.2300 + ures_close(countryArray); 1.2301 + 1.2302 + // Check for errors 1.2303 + if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) 1.2304 + { 1.2305 + // There is nothing to fallback to. 1.2306 + // Report the failure/warning if possible. 1.2307 + *ec = localStatus; 1.2308 + } 1.2309 + 1.2310 + if (U_SUCCESS(*ec)) 1.2311 + { 1.2312 + // no errors 1.2313 + return currCount; 1.2314 + } 1.2315 + 1.2316 + } 1.2317 + 1.2318 + // If we got here, either error code is invalid or 1.2319 + // some argument passed is no good. 1.2320 + return 0; 1.2321 +} 1.2322 + 1.2323 +U_CAPI int32_t U_EXPORT2 1.2324 +ucurr_forLocaleAndDate(const char* locale, 1.2325 + UDate date, 1.2326 + int32_t index, 1.2327 + UChar* buff, 1.2328 + int32_t buffCapacity, 1.2329 + UErrorCode* ec) 1.2330 +{ 1.2331 + int32_t resLen = 0; 1.2332 + int32_t currIndex = 0; 1.2333 + const UChar* s = NULL; 1.2334 + 1.2335 + if (ec != NULL && U_SUCCESS(*ec)) 1.2336 + { 1.2337 + // check the arguments passed 1.2338 + if ((buff && buffCapacity) || !buffCapacity ) 1.2339 + { 1.2340 + // local variables 1.2341 + UErrorCode localStatus = U_ZERO_ERROR; 1.2342 + char id[ULOC_FULLNAME_CAPACITY]; 1.2343 + resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus); 1.2344 + 1.2345 + // get country or country_variant in `id' 1.2346 + /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec); 1.2347 + if (U_FAILURE(*ec)) 1.2348 + { 1.2349 + return 0; 1.2350 + } 1.2351 + 1.2352 + // Remove variants, which is only needed for registration. 1.2353 + char *idDelim = strchr(id, VAR_DELIM); 1.2354 + if (idDelim) 1.2355 + { 1.2356 + idDelim[0] = 0; 1.2357 + } 1.2358 + 1.2359 + // Look up the CurrencyMap element in the root bundle. 1.2360 + UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus); 1.2361 + UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus); 1.2362 + 1.2363 + // Using the id derived from the local, get the currency data 1.2364 + UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus); 1.2365 + 1.2366 + // process each currency to see which one is valid for the given date 1.2367 + bool matchFound = false; 1.2368 + if (U_SUCCESS(localStatus)) 1.2369 + { 1.2370 + if ((index <= 0) || (index> ures_getSize(countryArray))) 1.2371 + { 1.2372 + // requested index is out of bounds 1.2373 + ures_close(countryArray); 1.2374 + return 0; 1.2375 + } 1.2376 + 1.2377 + for (int32_t i=0; i<ures_getSize(countryArray); i++) 1.2378 + { 1.2379 + // get the currency resource 1.2380 + UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus); 1.2381 + s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus); 1.2382 + 1.2383 + // get the from date 1.2384 + int32_t fromLength = 0; 1.2385 + UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus); 1.2386 + const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus); 1.2387 + 1.2388 + int64_t currDate64 = (int64_t)fromArray[0] << 32; 1.2389 + currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); 1.2390 + UDate fromDate = (UDate)currDate64; 1.2391 + 1.2392 + if (ures_getSize(currencyRes)> 2) 1.2393 + { 1.2394 + int32_t toLength = 0; 1.2395 + UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus); 1.2396 + const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus); 1.2397 + 1.2398 + currDate64 = (int64_t)toArray[0] << 32; 1.2399 + currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF)); 1.2400 + UDate toDate = (UDate)currDate64; 1.2401 + 1.2402 + if ((fromDate <= date) && (date < toDate)) 1.2403 + { 1.2404 + currIndex++; 1.2405 + if (currIndex == index) 1.2406 + { 1.2407 + matchFound = true; 1.2408 + } 1.2409 + } 1.2410 + 1.2411 + ures_close(toRes); 1.2412 + } 1.2413 + else 1.2414 + { 1.2415 + if (fromDate <= date) 1.2416 + { 1.2417 + currIndex++; 1.2418 + if (currIndex == index) 1.2419 + { 1.2420 + matchFound = true; 1.2421 + } 1.2422 + } 1.2423 + } 1.2424 + 1.2425 + // close open resources 1.2426 + ures_close(currencyRes); 1.2427 + ures_close(fromRes); 1.2428 + 1.2429 + // check for loop exit 1.2430 + if (matchFound) 1.2431 + { 1.2432 + break; 1.2433 + } 1.2434 + 1.2435 + } // end For loop 1.2436 + } 1.2437 + 1.2438 + ures_close(countryArray); 1.2439 + 1.2440 + // Check for errors 1.2441 + if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) 1.2442 + { 1.2443 + // There is nothing to fallback to. 1.2444 + // Report the failure/warning if possible. 1.2445 + *ec = localStatus; 1.2446 + } 1.2447 + 1.2448 + if (U_SUCCESS(*ec)) 1.2449 + { 1.2450 + // no errors 1.2451 + if((buffCapacity> resLen) && matchFound) 1.2452 + { 1.2453 + // write out the currency value 1.2454 + u_strcpy(buff, s); 1.2455 + } 1.2456 + else 1.2457 + { 1.2458 + return 0; 1.2459 + } 1.2460 + } 1.2461 + 1.2462 + // return null terminated currency string 1.2463 + return u_terminateUChars(buff, buffCapacity, resLen, ec); 1.2464 + } 1.2465 + else 1.2466 + { 1.2467 + // illegal argument encountered 1.2468 + *ec = U_ILLEGAL_ARGUMENT_ERROR; 1.2469 + } 1.2470 + 1.2471 + } 1.2472 + 1.2473 + // If we got here, either error code is invalid or 1.2474 + // some argument passed is no good. 1.2475 + return resLen; 1.2476 +} 1.2477 + 1.2478 +static const UEnumeration defaultKeywordValues = { 1.2479 + NULL, 1.2480 + NULL, 1.2481 + ulist_close_keyword_values_iterator, 1.2482 + ulist_count_keyword_values, 1.2483 + uenum_unextDefault, 1.2484 + ulist_next_keyword_value, 1.2485 + ulist_reset_keyword_values_iterator 1.2486 +}; 1.2487 + 1.2488 +U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) { 1.2489 + // Resolve region 1.2490 + char prefRegion[ULOC_FULLNAME_CAPACITY] = ""; 1.2491 + int32_t prefRegionLength = 0; 1.2492 + prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status); 1.2493 + if (prefRegionLength == 0) { 1.2494 + char loc[ULOC_FULLNAME_CAPACITY] = ""; 1.2495 + uloc_addLikelySubtags(locale, loc, sizeof(loc), status); 1.2496 + 1.2497 + prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status); 1.2498 + } 1.2499 + 1.2500 + // Read value from supplementalData 1.2501 + UList *values = ulist_createEmptyList(status); 1.2502 + UList *otherValues = ulist_createEmptyList(status); 1.2503 + UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration)); 1.2504 + if (U_FAILURE(*status) || en == NULL) { 1.2505 + if (en == NULL) { 1.2506 + *status = U_MEMORY_ALLOCATION_ERROR; 1.2507 + } else { 1.2508 + uprv_free(en); 1.2509 + } 1.2510 + ulist_deleteList(values); 1.2511 + ulist_deleteList(otherValues); 1.2512 + return NULL; 1.2513 + } 1.2514 + memcpy(en, &defaultKeywordValues, sizeof(UEnumeration)); 1.2515 + en->context = values; 1.2516 + 1.2517 + UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status); 1.2518 + ures_getByKey(bundle, "CurrencyMap", bundle, status); 1.2519 + UResourceBundle bundlekey, regbndl, curbndl, to; 1.2520 + ures_initStackObject(&bundlekey); 1.2521 + ures_initStackObject(®bndl); 1.2522 + ures_initStackObject(&curbndl); 1.2523 + ures_initStackObject(&to); 1.2524 + 1.2525 + while (U_SUCCESS(*status) && ures_hasNext(bundle)) { 1.2526 + ures_getNextResource(bundle, &bundlekey, status); 1.2527 + if (U_FAILURE(*status)) { 1.2528 + break; 1.2529 + } 1.2530 + const char *region = ures_getKey(&bundlekey); 1.2531 + UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE; 1.2532 + if (!isPrefRegion && commonlyUsed) { 1.2533 + // With commonlyUsed=true, we do not put 1.2534 + // currencies for other regions in the 1.2535 + // result list. 1.2536 + continue; 1.2537 + } 1.2538 + ures_getByKey(bundle, region, ®bndl, status); 1.2539 + if (U_FAILURE(*status)) { 1.2540 + break; 1.2541 + } 1.2542 + while (U_SUCCESS(*status) && ures_hasNext(®bndl)) { 1.2543 + ures_getNextResource(®bndl, &curbndl, status); 1.2544 + if (ures_getType(&curbndl) != URES_TABLE) { 1.2545 + // Currently, an empty ARRAY is mixed in. 1.2546 + continue; 1.2547 + } 1.2548 + char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY); 1.2549 + int32_t curIDLength = ULOC_KEYWORDS_CAPACITY; 1.2550 + if (curID == NULL) { 1.2551 + *status = U_MEMORY_ALLOCATION_ERROR; 1.2552 + break; 1.2553 + } 1.2554 + 1.2555 +#if U_CHARSET_FAMILY==U_ASCII_FAMILY 1.2556 + ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status); 1.2557 + /* optimize - use the utf-8 string */ 1.2558 +#else 1.2559 + { 1.2560 + const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status); 1.2561 + if(U_SUCCESS(*status)) { 1.2562 + if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) { 1.2563 + *status = U_BUFFER_OVERFLOW_ERROR; 1.2564 + } else { 1.2565 + u_UCharsToChars(defString, curID, curIDLength+1); 1.2566 + } 1.2567 + } 1.2568 + } 1.2569 +#endif 1.2570 + 1.2571 + if (U_FAILURE(*status)) { 1.2572 + break; 1.2573 + } 1.2574 + UBool hasTo = FALSE; 1.2575 + ures_getByKey(&curbndl, "to", &to, status); 1.2576 + if (U_FAILURE(*status)) { 1.2577 + // Do nothing here... 1.2578 + *status = U_ZERO_ERROR; 1.2579 + } else { 1.2580 + hasTo = TRUE; 1.2581 + } 1.2582 + if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) { 1.2583 + // Currently active currency for the target country 1.2584 + ulist_addItemEndList(values, curID, TRUE, status); 1.2585 + } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) { 1.2586 + ulist_addItemEndList(otherValues, curID, TRUE, status); 1.2587 + } else { 1.2588 + uprv_free(curID); 1.2589 + } 1.2590 + } 1.2591 + 1.2592 + } 1.2593 + if (U_SUCCESS(*status)) { 1.2594 + if (commonlyUsed) { 1.2595 + if (ulist_getListSize(values) == 0) { 1.2596 + // This could happen if no valid region is supplied in the input 1.2597 + // locale. In this case, we use the CLDR's default. 1.2598 + uenum_close(en); 1.2599 + en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status); 1.2600 + } 1.2601 + } else { 1.2602 + // Consolidate the list 1.2603 + char *value = NULL; 1.2604 + ulist_resetList(otherValues); 1.2605 + while ((value = (char *)ulist_getNext(otherValues)) != NULL) { 1.2606 + if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) { 1.2607 + char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY); 1.2608 + uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1); 1.2609 + ulist_addItemEndList(values, tmpValue, TRUE, status); 1.2610 + if (U_FAILURE(*status)) { 1.2611 + break; 1.2612 + } 1.2613 + } 1.2614 + } 1.2615 + } 1.2616 + 1.2617 + ulist_resetList((UList *)(en->context)); 1.2618 + } else { 1.2619 + ulist_deleteList(values); 1.2620 + uprv_free(en); 1.2621 + values = NULL; 1.2622 + en = NULL; 1.2623 + } 1.2624 + ures_close(&to); 1.2625 + ures_close(&curbndl); 1.2626 + ures_close(®bndl); 1.2627 + ures_close(&bundlekey); 1.2628 + ures_close(bundle); 1.2629 + 1.2630 + ulist_deleteList(otherValues); 1.2631 + 1.2632 + return en; 1.2633 +} 1.2634 + 1.2635 + 1.2636 +U_CAPI int32_t U_EXPORT2 1.2637 +ucurr_getNumericCode(const UChar* currency) { 1.2638 + int32_t code = 0; 1.2639 + if (currency && u_strlen(currency) == ISO_CURRENCY_CODE_LENGTH) { 1.2640 + UErrorCode status = U_ZERO_ERROR; 1.2641 + 1.2642 + UResourceBundle *bundle = ures_openDirect(0, "currencyNumericCodes", &status); 1.2643 + ures_getByKey(bundle, "codeMap", bundle, &status); 1.2644 + if (U_SUCCESS(status)) { 1.2645 + char alphaCode[ISO_CURRENCY_CODE_LENGTH+1]; 1.2646 + myUCharsToChars(alphaCode, currency); 1.2647 + T_CString_toUpperCase(alphaCode); 1.2648 + ures_getByKey(bundle, alphaCode, bundle, &status); 1.2649 + int tmpCode = ures_getInt(bundle, &status); 1.2650 + if (U_SUCCESS(status)) { 1.2651 + code = tmpCode; 1.2652 + } 1.2653 + } 1.2654 + ures_close(bundle); 1.2655 + } 1.2656 + return code; 1.2657 +} 1.2658 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.2659 + 1.2660 +//eof