locdispnames.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. // © 2016 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. /*
  4. *******************************************************************************
  5. *
  6. * Copyright (C) 1997-2016, International Business Machines
  7. * Corporation and others. All Rights Reserved.
  8. *
  9. *******************************************************************************
  10. * file name: locdispnames.cpp
  11. * encoding: UTF-8
  12. * tab size: 8 (not used)
  13. * indentation:4
  14. *
  15. * created on: 2010feb25
  16. * created by: Markus W. Scherer
  17. *
  18. * Code for locale display names, separated out from other .cpp files
  19. * that then do not depend on resource bundle code and display name data.
  20. */
  21. #include "unicode/utypes.h"
  22. #include "unicode/brkiter.h"
  23. #include "unicode/locid.h"
  24. #include "unicode/uenum.h"
  25. #include "unicode/uloc.h"
  26. #include "unicode/ures.h"
  27. #include "unicode/ustring.h"
  28. #include "charstr.h"
  29. #include "cmemory.h"
  30. #include "cstring.h"
  31. #include "putilimp.h"
  32. #include "ulocimp.h"
  33. #include "uresimp.h"
  34. #include "ureslocs.h"
  35. #include "ustr_imp.h"
  36. // C++ API ----------------------------------------------------------------- ***
  37. U_NAMESPACE_BEGIN
  38. UnicodeString&
  39. Locale::getDisplayLanguage(UnicodeString& dispLang) const
  40. {
  41. return this->getDisplayLanguage(getDefault(), dispLang);
  42. }
  43. /*We cannot make any assumptions on the size of the output display strings
  44. * Yet, since we are calling through to a C API, we need to set limits on
  45. * buffer size. For all the following getDisplay functions we first attempt
  46. * to fill up a stack allocated buffer. If it is to small we heap allocated
  47. * the exact buffer we need copy it to the UnicodeString and delete it*/
  48. UnicodeString&
  49. Locale::getDisplayLanguage(const Locale &displayLocale,
  50. UnicodeString &result) const {
  51. char16_t *buffer;
  52. UErrorCode errorCode=U_ZERO_ERROR;
  53. int32_t length;
  54. buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
  55. if (buffer == nullptr) {
  56. result.truncate(0);
  57. return result;
  58. }
  59. length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
  60. buffer, result.getCapacity(),
  61. &errorCode);
  62. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  63. if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
  64. buffer=result.getBuffer(length);
  65. if (buffer == nullptr) {
  66. result.truncate(0);
  67. return result;
  68. }
  69. errorCode=U_ZERO_ERROR;
  70. length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
  71. buffer, result.getCapacity(),
  72. &errorCode);
  73. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  74. }
  75. return result;
  76. }
  77. UnicodeString&
  78. Locale::getDisplayScript(UnicodeString& dispScript) const
  79. {
  80. return this->getDisplayScript(getDefault(), dispScript);
  81. }
  82. UnicodeString&
  83. Locale::getDisplayScript(const Locale &displayLocale,
  84. UnicodeString &result) const {
  85. char16_t *buffer;
  86. UErrorCode errorCode=U_ZERO_ERROR;
  87. int32_t length;
  88. buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
  89. if (buffer == nullptr) {
  90. result.truncate(0);
  91. return result;
  92. }
  93. length=uloc_getDisplayScript(fullName, displayLocale.fullName,
  94. buffer, result.getCapacity(),
  95. &errorCode);
  96. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  97. if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
  98. buffer=result.getBuffer(length);
  99. if (buffer == nullptr) {
  100. result.truncate(0);
  101. return result;
  102. }
  103. errorCode=U_ZERO_ERROR;
  104. length=uloc_getDisplayScript(fullName, displayLocale.fullName,
  105. buffer, result.getCapacity(),
  106. &errorCode);
  107. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  108. }
  109. return result;
  110. }
  111. UnicodeString&
  112. Locale::getDisplayCountry(UnicodeString& dispCntry) const
  113. {
  114. return this->getDisplayCountry(getDefault(), dispCntry);
  115. }
  116. UnicodeString&
  117. Locale::getDisplayCountry(const Locale &displayLocale,
  118. UnicodeString &result) const {
  119. char16_t *buffer;
  120. UErrorCode errorCode=U_ZERO_ERROR;
  121. int32_t length;
  122. buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
  123. if (buffer == nullptr) {
  124. result.truncate(0);
  125. return result;
  126. }
  127. length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
  128. buffer, result.getCapacity(),
  129. &errorCode);
  130. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  131. if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
  132. buffer=result.getBuffer(length);
  133. if (buffer == nullptr) {
  134. result.truncate(0);
  135. return result;
  136. }
  137. errorCode=U_ZERO_ERROR;
  138. length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
  139. buffer, result.getCapacity(),
  140. &errorCode);
  141. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  142. }
  143. return result;
  144. }
  145. UnicodeString&
  146. Locale::getDisplayVariant(UnicodeString& dispVar) const
  147. {
  148. return this->getDisplayVariant(getDefault(), dispVar);
  149. }
  150. UnicodeString&
  151. Locale::getDisplayVariant(const Locale &displayLocale,
  152. UnicodeString &result) const {
  153. char16_t *buffer;
  154. UErrorCode errorCode=U_ZERO_ERROR;
  155. int32_t length;
  156. buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
  157. if (buffer == nullptr) {
  158. result.truncate(0);
  159. return result;
  160. }
  161. length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
  162. buffer, result.getCapacity(),
  163. &errorCode);
  164. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  165. if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
  166. buffer=result.getBuffer(length);
  167. if (buffer == nullptr) {
  168. result.truncate(0);
  169. return result;
  170. }
  171. errorCode=U_ZERO_ERROR;
  172. length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
  173. buffer, result.getCapacity(),
  174. &errorCode);
  175. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  176. }
  177. return result;
  178. }
  179. UnicodeString&
  180. Locale::getDisplayName( UnicodeString& name ) const
  181. {
  182. return this->getDisplayName(getDefault(), name);
  183. }
  184. UnicodeString&
  185. Locale::getDisplayName(const Locale &displayLocale,
  186. UnicodeString &result) const {
  187. char16_t *buffer;
  188. UErrorCode errorCode=U_ZERO_ERROR;
  189. int32_t length;
  190. buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
  191. if (buffer == nullptr) {
  192. result.truncate(0);
  193. return result;
  194. }
  195. length=uloc_getDisplayName(fullName, displayLocale.fullName,
  196. buffer, result.getCapacity(),
  197. &errorCode);
  198. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  199. if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
  200. buffer=result.getBuffer(length);
  201. if (buffer == nullptr) {
  202. result.truncate(0);
  203. return result;
  204. }
  205. errorCode=U_ZERO_ERROR;
  206. length=uloc_getDisplayName(fullName, displayLocale.fullName,
  207. buffer, result.getCapacity(),
  208. &errorCode);
  209. result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
  210. }
  211. return result;
  212. }
  213. #if !UCONFIG_NO_BREAK_ITERATION
  214. // -------------------------------------
  215. // Gets the objectLocale display name in the default locale language.
  216. UnicodeString& U_EXPORT2
  217. BreakIterator::getDisplayName(const Locale& objectLocale,
  218. UnicodeString& name)
  219. {
  220. return objectLocale.getDisplayName(name);
  221. }
  222. // -------------------------------------
  223. // Gets the objectLocale display name in the displayLocale language.
  224. UnicodeString& U_EXPORT2
  225. BreakIterator::getDisplayName(const Locale& objectLocale,
  226. const Locale& displayLocale,
  227. UnicodeString& name)
  228. {
  229. return objectLocale.getDisplayName(displayLocale, name);
  230. }
  231. #endif
  232. U_NAMESPACE_END
  233. // C API ------------------------------------------------------------------- ***
  234. U_NAMESPACE_USE
  235. namespace {
  236. /* ### Constants **************************************************/
  237. /* These strings describe the resources we attempt to load from
  238. the locale ResourceBundle data file.*/
  239. constexpr char _kLanguages[] = "Languages";
  240. constexpr char _kScripts[] = "Scripts";
  241. constexpr char _kScriptsStandAlone[] = "Scripts%stand-alone";
  242. constexpr char _kCountries[] = "Countries";
  243. constexpr char _kVariants[] = "Variants";
  244. constexpr char _kKeys[] = "Keys";
  245. constexpr char _kTypes[] = "Types";
  246. //constexpr char _kRootName[] = "root";
  247. constexpr char _kCurrency[] = "currency";
  248. constexpr char _kCurrencies[] = "Currencies";
  249. constexpr char _kLocaleDisplayPattern[] = "localeDisplayPattern";
  250. constexpr char _kPattern[] = "pattern";
  251. constexpr char _kSeparator[] = "separator";
  252. /* ### Display name **************************************************/
  253. int32_t
  254. _getStringOrCopyKey(const char *path, const char *locale,
  255. const char *tableKey,
  256. const char* subTableKey,
  257. const char *itemKey,
  258. const char *substitute,
  259. char16_t *dest, int32_t destCapacity,
  260. UErrorCode &errorCode) {
  261. if (U_FAILURE(errorCode)) { return 0; }
  262. const char16_t *s = nullptr;
  263. int32_t length = 0;
  264. if(itemKey==nullptr) {
  265. /* top-level item: normal resource bundle access */
  266. icu::LocalUResourceBundlePointer rb(ures_open(path, locale, &errorCode));
  267. if(U_SUCCESS(errorCode)) {
  268. s=ures_getStringByKey(rb.getAlias(), tableKey, &length, &errorCode);
  269. /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
  270. }
  271. } else {
  272. bool isLanguageCode = (uprv_strncmp(tableKey, _kLanguages, 9) == 0);
  273. /* Language code should not be a number. If it is, set the error code. */
  274. if (isLanguageCode && uprv_strtol(itemKey, nullptr, 10)) {
  275. errorCode = U_MISSING_RESOURCE_ERROR;
  276. } else {
  277. /* second-level item, use special fallback */
  278. s=uloc_getTableStringWithFallback(path, locale,
  279. tableKey,
  280. subTableKey,
  281. itemKey,
  282. &length,
  283. &errorCode);
  284. if (U_FAILURE(errorCode) && isLanguageCode && itemKey != nullptr) {
  285. // convert itemKey locale code to canonical form and try again, ICU-20870
  286. errorCode = U_ZERO_ERROR;
  287. Locale canonKey = Locale::createCanonical(itemKey);
  288. s=uloc_getTableStringWithFallback(path, locale,
  289. tableKey,
  290. subTableKey,
  291. canonKey.getName(),
  292. &length,
  293. &errorCode);
  294. }
  295. }
  296. }
  297. if(U_SUCCESS(errorCode)) {
  298. int32_t copyLength=uprv_min(length, destCapacity);
  299. if(copyLength>0 && s != nullptr) {
  300. u_memcpy(dest, s, copyLength);
  301. }
  302. } else {
  303. /* no string from a resource bundle: convert the substitute */
  304. length = static_cast<int32_t>(uprv_strlen(substitute));
  305. u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
  306. errorCode = U_USING_DEFAULT_WARNING;
  307. }
  308. return u_terminateUChars(dest, destCapacity, length, &errorCode);
  309. }
  310. using UDisplayNameGetter = icu::CharString(const char*, UErrorCode&);
  311. int32_t
  312. _getDisplayNameForComponent(const char *locale,
  313. const char *displayLocale,
  314. char16_t *dest, int32_t destCapacity,
  315. UDisplayNameGetter *getter,
  316. const char *tag,
  317. UErrorCode &errorCode) {
  318. if (U_FAILURE(errorCode)) { return 0; }
  319. UErrorCode localStatus;
  320. const char* root = nullptr;
  321. if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
  322. errorCode = U_ILLEGAL_ARGUMENT_ERROR;
  323. return 0;
  324. }
  325. localStatus = U_ZERO_ERROR;
  326. icu::CharString localeBuffer = (*getter)(locale, localStatus);
  327. if (U_FAILURE(localStatus)) {
  328. errorCode = U_ILLEGAL_ARGUMENT_ERROR;
  329. return 0;
  330. }
  331. if (localeBuffer.isEmpty()) {
  332. // For the display name, we treat this as unknown language (ICU-20273).
  333. if (getter == ulocimp_getLanguage) {
  334. localeBuffer.append("und", errorCode);
  335. } else {
  336. return u_terminateUChars(dest, destCapacity, 0, &errorCode);
  337. }
  338. }
  339. root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
  340. return _getStringOrCopyKey(root, displayLocale,
  341. tag, nullptr, localeBuffer.data(),
  342. localeBuffer.data(),
  343. dest, destCapacity,
  344. errorCode);
  345. }
  346. } // namespace
  347. U_CAPI int32_t U_EXPORT2
  348. uloc_getDisplayLanguage(const char *locale,
  349. const char *displayLocale,
  350. char16_t *dest, int32_t destCapacity,
  351. UErrorCode *pErrorCode) {
  352. return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
  353. ulocimp_getLanguage, _kLanguages, *pErrorCode);
  354. }
  355. U_CAPI int32_t U_EXPORT2
  356. uloc_getDisplayScript(const char* locale,
  357. const char* displayLocale,
  358. char16_t *dest, int32_t destCapacity,
  359. UErrorCode *pErrorCode)
  360. {
  361. if (U_FAILURE(*pErrorCode)) { return 0; }
  362. UErrorCode err = U_ZERO_ERROR;
  363. int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
  364. ulocimp_getScript, _kScriptsStandAlone, err);
  365. if (destCapacity == 0 && err == U_BUFFER_OVERFLOW_ERROR) {
  366. // For preflight, return the max of the value and the fallback.
  367. int32_t fallback_res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
  368. ulocimp_getScript, _kScripts, *pErrorCode);
  369. return (fallback_res > res) ? fallback_res : res;
  370. }
  371. if ( err == U_USING_DEFAULT_WARNING ) {
  372. return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
  373. ulocimp_getScript, _kScripts, *pErrorCode);
  374. } else {
  375. *pErrorCode = err;
  376. return res;
  377. }
  378. }
  379. static int32_t
  380. uloc_getDisplayScriptInContext(const char* locale,
  381. const char* displayLocale,
  382. char16_t *dest, int32_t destCapacity,
  383. UErrorCode *pErrorCode)
  384. {
  385. return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
  386. ulocimp_getScript, _kScripts, *pErrorCode);
  387. }
  388. U_CAPI int32_t U_EXPORT2
  389. uloc_getDisplayCountry(const char *locale,
  390. const char *displayLocale,
  391. char16_t *dest, int32_t destCapacity,
  392. UErrorCode *pErrorCode) {
  393. return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
  394. ulocimp_getRegion, _kCountries, *pErrorCode);
  395. }
  396. /*
  397. * TODO separate variant1_variant2_variant3...
  398. * by getting each tag's display string and concatenating them with ", "
  399. * in between - similar to uloc_getDisplayName()
  400. */
  401. U_CAPI int32_t U_EXPORT2
  402. uloc_getDisplayVariant(const char *locale,
  403. const char *displayLocale,
  404. char16_t *dest, int32_t destCapacity,
  405. UErrorCode *pErrorCode) {
  406. return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
  407. ulocimp_getVariant, _kVariants, *pErrorCode);
  408. }
  409. /* Instead of having a separate pass for 'special' patterns, reintegrate the two
  410. * so we don't get bitten by preflight bugs again. We can be reasonably efficient
  411. * without two separate code paths, this code isn't that performance-critical.
  412. *
  413. * This code is general enough to deal with patterns that have a prefix or swap the
  414. * language and remainder components, since we gave developers enough rope to do such
  415. * things if they futz with the pattern data. But since we don't give them a way to
  416. * specify a pattern for arbitrary combinations of components, there's not much use in
  417. * that. I don't think our data includes such patterns, the only variable I know if is
  418. * whether there is a space before the open paren, or not. Oh, and zh uses different
  419. * chars than the standard open/close paren (which ja and ko use, btw).
  420. */
  421. U_CAPI int32_t U_EXPORT2
  422. uloc_getDisplayName(const char *locale,
  423. const char *displayLocale,
  424. char16_t *dest, int32_t destCapacity,
  425. UErrorCode *pErrorCode)
  426. {
  427. static const char16_t defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
  428. static const char16_t sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
  429. static const char16_t sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
  430. static const int32_t subLen = 3;
  431. static const char16_t defaultPattern[10] = {
  432. 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
  433. }; /* {0} ({1}) */
  434. static const int32_t defaultPatLen = 9;
  435. static const int32_t defaultSub0Pos = 0;
  436. static const int32_t defaultSub1Pos = 5;
  437. int32_t length; /* of formatted result */
  438. const char16_t *separator;
  439. int32_t sepLen = 0;
  440. const char16_t *pattern;
  441. int32_t patLen = 0;
  442. int32_t sub0Pos, sub1Pos;
  443. char16_t formatOpenParen = 0x0028; // (
  444. char16_t formatReplaceOpenParen = 0x005B; // [
  445. char16_t formatCloseParen = 0x0029; // )
  446. char16_t formatReplaceCloseParen = 0x005D; // ]
  447. UBool haveLang = true; /* assume true, set false if we find we don't have
  448. a lang component in the locale */
  449. UBool haveRest = true; /* assume true, set false if we find we don't have
  450. any other component in the locale */
  451. UBool retry = false; /* set true if we need to retry, see below */
  452. int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
  453. if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
  454. return 0;
  455. }
  456. if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
  457. *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
  458. return 0;
  459. }
  460. {
  461. UErrorCode status = U_ZERO_ERROR;
  462. icu::LocalUResourceBundlePointer locbundle(
  463. ures_open(U_ICUDATA_LANG, displayLocale, &status));
  464. icu::LocalUResourceBundlePointer dspbundle(
  465. ures_getByKeyWithFallback(locbundle.getAlias(), _kLocaleDisplayPattern, nullptr, &status));
  466. separator=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kSeparator, &sepLen, &status);
  467. pattern=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kPattern, &patLen, &status);
  468. }
  469. /* If we couldn't find any data, then use the defaults */
  470. if(sepLen == 0) {
  471. separator = defaultSeparator;
  472. }
  473. /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
  474. * here since we are trying to build the display string in place in the dest buffer,
  475. * and to handle it as a pattern would entail having separate storage for the
  476. * substrings that need to be combined (the first of which may be the result of
  477. * previous such combinations). So for now we continue to treat the portion between
  478. * {0} and {1} as a string to be appended when joining substrings, ignoring anything
  479. * that is before {0} or after {1} (no existing separator pattern has any such thing).
  480. * This is similar to how pattern is handled below.
  481. */
  482. {
  483. char16_t *p0=u_strstr(separator, sub0);
  484. char16_t *p1=u_strstr(separator, sub1);
  485. if (p0==nullptr || p1==nullptr || p1<p0) {
  486. *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
  487. return 0;
  488. }
  489. separator = (const char16_t *)p0 + subLen;
  490. sepLen = static_cast<int32_t>(p1 - separator);
  491. }
  492. if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
  493. pattern=defaultPattern;
  494. patLen=defaultPatLen;
  495. sub0Pos=defaultSub0Pos;
  496. sub1Pos=defaultSub1Pos;
  497. // use default formatOpenParen etc. set above
  498. } else { /* non-default pattern */
  499. char16_t *p0=u_strstr(pattern, sub0);
  500. char16_t *p1=u_strstr(pattern, sub1);
  501. if (p0==nullptr || p1==nullptr) {
  502. *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
  503. return 0;
  504. }
  505. sub0Pos = static_cast<int32_t>(p0-pattern);
  506. sub1Pos = static_cast<int32_t>(p1-pattern);
  507. if (sub1Pos < sub0Pos) { /* a very odd pattern */
  508. int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
  509. langi=1;
  510. }
  511. if (u_strchr(pattern, 0xFF08) != nullptr) {
  512. formatOpenParen = 0xFF08; // fullwidth (
  513. formatReplaceOpenParen = 0xFF3B; // fullwidth [
  514. formatCloseParen = 0xFF09; // fullwidth )
  515. formatReplaceCloseParen = 0xFF3D; // fullwidth ]
  516. }
  517. }
  518. /* We loop here because there is one case in which after the first pass we could need to
  519. * reextract the data. If there's initial padding before the first element, we put in
  520. * the padding and then write that element. If it turns out there's no second element,
  521. * we didn't need the padding. If we do need the data (no preflight), and the first element
  522. * would have fit but for the padding, we need to reextract. In this case (only) we
  523. * adjust the parameters so padding is not added, and repeat.
  524. */
  525. do {
  526. char16_t* p=dest;
  527. int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
  528. int32_t langLen=0; /* length of language substitution */
  529. int32_t langPos=0; /* position in output of language substitution */
  530. int32_t restLen=0; /* length of 'everything else' substitution */
  531. int32_t restPos=0; /* position in output of 'everything else' substitution */
  532. icu::LocalUEnumerationPointer kenum; /* keyword enumeration */
  533. /* prefix of pattern, extremely likely to be empty */
  534. if(sub0Pos) {
  535. if(destCapacity >= sub0Pos) {
  536. while (patPos < sub0Pos) {
  537. *p++ = pattern[patPos++];
  538. }
  539. } else {
  540. patPos=sub0Pos;
  541. }
  542. length=sub0Pos;
  543. } else {
  544. length=0;
  545. }
  546. for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
  547. UBool subdone = false; /* set true when ready to move to next substitution */
  548. /* prep p and cap for calls to get display components, pin cap to 0 since
  549. they complain if cap is negative */
  550. int32_t cap=destCapacity-length;
  551. if (cap <= 0) {
  552. cap=0;
  553. } else {
  554. p=dest+length;
  555. }
  556. if (subi == langi) { /* {0}*/
  557. if(haveLang) {
  558. langPos=length;
  559. langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
  560. length+=langLen;
  561. haveLang=langLen>0;
  562. }
  563. subdone=true;
  564. } else { /* {1} */
  565. if(!haveRest) {
  566. subdone=true;
  567. } else {
  568. int32_t len; /* length of component (plus other stuff) we just fetched */
  569. switch(resti++) {
  570. case 0:
  571. restPos=length;
  572. len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
  573. break;
  574. case 1:
  575. len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
  576. break;
  577. case 2:
  578. len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
  579. break;
  580. case 3:
  581. kenum.adoptInstead(uloc_openKeywords(locale, pErrorCode));
  582. U_FALLTHROUGH;
  583. default: {
  584. const char* kw=uenum_next(kenum.getAlias(), &len, pErrorCode);
  585. if (kw == nullptr) {
  586. len=0; /* mark that we didn't add a component */
  587. subdone=true;
  588. } else {
  589. /* incorporating this behavior into the loop made it even more complex,
  590. so just special case it here */
  591. len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
  592. if(len) {
  593. if(len < cap) {
  594. p[len]=0x3d; /* '=', assume we'll need it */
  595. }
  596. len+=1;
  597. /* adjust for call to get keyword */
  598. cap-=len;
  599. if(cap <= 0) {
  600. cap=0;
  601. } else {
  602. p+=len;
  603. }
  604. }
  605. /* reset for call below */
  606. if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
  607. *pErrorCode=U_ZERO_ERROR;
  608. }
  609. int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
  610. p, cap, pErrorCode);
  611. if(len) {
  612. if(vlen==0) {
  613. --len; /* remove unneeded '=' */
  614. }
  615. /* restore cap and p to what they were at start */
  616. cap=destCapacity-length;
  617. if(cap <= 0) {
  618. cap=0;
  619. } else {
  620. p=dest+length;
  621. }
  622. }
  623. len+=vlen; /* total we added for key + '=' + value */
  624. }
  625. } break;
  626. } /* end switch */
  627. if (len>0) {
  628. /* we added a component, so add separator and write it if there's room. */
  629. if(len+sepLen<=cap) {
  630. const char16_t * plimit = p + len;
  631. for (; p < plimit; p++) {
  632. if (*p == formatOpenParen) {
  633. *p = formatReplaceOpenParen;
  634. } else if (*p == formatCloseParen) {
  635. *p = formatReplaceCloseParen;
  636. }
  637. }
  638. for(int32_t i=0;i<sepLen;++i) {
  639. *p++=separator[i];
  640. }
  641. }
  642. length+=len+sepLen;
  643. } else if(subdone) {
  644. /* remove separator if we added it */
  645. if (length!=restPos) {
  646. length-=sepLen;
  647. }
  648. restLen=length-restPos;
  649. haveRest=restLen>0;
  650. }
  651. }
  652. }
  653. if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
  654. *pErrorCode=U_ZERO_ERROR;
  655. }
  656. if(subdone) {
  657. if(haveLang && haveRest) {
  658. /* append internal portion of pattern, the first time,
  659. or last portion of pattern the second time */
  660. int32_t padLen;
  661. patPos+=subLen;
  662. padLen=(subi==0 ? sub1Pos : patLen)-patPos;
  663. if(length+padLen <= destCapacity) {
  664. p=dest+length;
  665. for(int32_t i=0;i<padLen;++i) {
  666. *p++=pattern[patPos++];
  667. }
  668. } else {
  669. patPos+=padLen;
  670. }
  671. length+=padLen;
  672. } else if(subi==0) {
  673. /* don't have first component, reset for second component */
  674. sub0Pos=0;
  675. length=0;
  676. } else if(length>0) {
  677. /* true length is the length of just the component we got. */
  678. length=haveLang?langLen:restLen;
  679. if(dest && sub0Pos!=0) {
  680. if (sub0Pos+length<=destCapacity) {
  681. /* first component not at start of result,
  682. but we have full component in buffer. */
  683. u_memmove(dest, dest+(haveLang?langPos:restPos), length);
  684. } else {
  685. /* would have fit, but didn't because of pattern prefix. */
  686. sub0Pos=0; /* stops initial padding (and a second retry,
  687. so we won't end up here again) */
  688. retry=true;
  689. }
  690. }
  691. }
  692. ++subi; /* move on to next substitution */
  693. }
  694. }
  695. } while(retry);
  696. return u_terminateUChars(dest, destCapacity, length, pErrorCode);
  697. }
  698. U_CAPI int32_t U_EXPORT2
  699. uloc_getDisplayKeyword(const char* keyword,
  700. const char* displayLocale,
  701. char16_t* dest,
  702. int32_t destCapacity,
  703. UErrorCode* status){
  704. /* argument checking */
  705. if(status==nullptr || U_FAILURE(*status)) {
  706. return 0;
  707. }
  708. if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
  709. *status=U_ILLEGAL_ARGUMENT_ERROR;
  710. return 0;
  711. }
  712. /* pass itemKey=nullptr to look for a top-level item */
  713. return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
  714. _kKeys, nullptr,
  715. keyword,
  716. keyword,
  717. dest, destCapacity,
  718. *status);
  719. }
  720. #define UCURRENCY_DISPLAY_NAME_INDEX 1
  721. U_CAPI int32_t U_EXPORT2
  722. uloc_getDisplayKeywordValue( const char* locale,
  723. const char* keyword,
  724. const char* displayLocale,
  725. char16_t* dest,
  726. int32_t destCapacity,
  727. UErrorCode* status){
  728. /* argument checking */
  729. if(status==nullptr || U_FAILURE(*status)) {
  730. return 0;
  731. }
  732. if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
  733. *status=U_ILLEGAL_ARGUMENT_ERROR;
  734. return 0;
  735. }
  736. /* get the keyword value */
  737. CharString keywordValue;
  738. if (keyword != nullptr && *keyword != '\0') {
  739. keywordValue = ulocimp_getKeywordValue(locale, keyword, *status);
  740. }
  741. /*
  742. * if the keyword is equal to currency .. then to get the display name
  743. * we need to do the fallback ourselves
  744. */
  745. if(uprv_stricmp(keyword, _kCurrency)==0){
  746. int32_t dispNameLen = 0;
  747. const char16_t *dispName = nullptr;
  748. icu::LocalUResourceBundlePointer bundle(
  749. ures_open(U_ICUDATA_CURR, displayLocale, status));
  750. icu::LocalUResourceBundlePointer currencies(
  751. ures_getByKey(bundle.getAlias(), _kCurrencies, nullptr, status));
  752. icu::LocalUResourceBundlePointer currency(
  753. ures_getByKeyWithFallback(currencies.getAlias(), keywordValue.data(), nullptr, status));
  754. dispName = ures_getStringByIndex(currency.getAlias(), UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
  755. if(U_FAILURE(*status)){
  756. if(*status == U_MISSING_RESOURCE_ERROR){
  757. /* we just want to write the value over if nothing is available */
  758. *status = U_USING_DEFAULT_WARNING;
  759. }else{
  760. return 0;
  761. }
  762. }
  763. /* now copy the dispName over if not nullptr */
  764. if(dispName != nullptr){
  765. if(dispNameLen <= destCapacity){
  766. u_memcpy(dest, dispName, dispNameLen);
  767. return u_terminateUChars(dest, destCapacity, dispNameLen, status);
  768. }else{
  769. *status = U_BUFFER_OVERFLOW_ERROR;
  770. return dispNameLen;
  771. }
  772. }else{
  773. /* we have not found the display name for the value .. just copy over */
  774. if(keywordValue.length() <= destCapacity){
  775. u_charsToUChars(keywordValue.data(), dest, keywordValue.length());
  776. return u_terminateUChars(dest, destCapacity, keywordValue.length(), status);
  777. }else{
  778. *status = U_BUFFER_OVERFLOW_ERROR;
  779. return keywordValue.length();
  780. }
  781. }
  782. }else{
  783. return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
  784. _kTypes, keyword,
  785. keywordValue.data(),
  786. keywordValue.data(),
  787. dest, destCapacity,
  788. *status);
  789. }
  790. }