ucurr.cpp 97 KB

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