ucurr.cpp 97 KB

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