locavailable.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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-2013, International Business Machines
  7. * Corporation and others. All Rights Reserved.
  8. *
  9. *******************************************************************************
  10. * file name: locavailable.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 available locales, separated out from other .cpp files
  19. * that then do not depend on resource bundle code and res_index bundles.
  20. */
  21. #include "unicode/errorcode.h"
  22. #include "unicode/utypes.h"
  23. #include "unicode/locid.h"
  24. #include "unicode/uloc.h"
  25. #include "unicode/ures.h"
  26. #include "cmemory.h"
  27. #include "cstring.h"
  28. #include "ucln_cmn.h"
  29. #include "uassert.h"
  30. #include "umutex.h"
  31. #include "uresimp.h"
  32. // C++ API ----------------------------------------------------------------- ***
  33. U_NAMESPACE_BEGIN
  34. static icu::Locale* availableLocaleList = nullptr;
  35. static int32_t availableLocaleListCount;
  36. static icu::UInitOnce gInitOnceLocale {};
  37. U_NAMESPACE_END
  38. U_CDECL_BEGIN
  39. static UBool U_CALLCONV locale_available_cleanup()
  40. {
  41. U_NAMESPACE_USE
  42. if (availableLocaleList) {
  43. delete []availableLocaleList;
  44. availableLocaleList = nullptr;
  45. }
  46. availableLocaleListCount = 0;
  47. gInitOnceLocale.reset();
  48. return true;
  49. }
  50. U_CDECL_END
  51. U_NAMESPACE_BEGIN
  52. void U_CALLCONV locale_available_init() {
  53. // This function is a friend of class Locale.
  54. // This function is only invoked via umtx_initOnce().
  55. // for now, there is a hardcoded list, so just walk through that list and set it up.
  56. // Note: this function is a friend of class Locale.
  57. availableLocaleListCount = uloc_countAvailable();
  58. if(availableLocaleListCount) {
  59. availableLocaleList = new Locale[availableLocaleListCount];
  60. }
  61. if (availableLocaleList == nullptr) {
  62. availableLocaleListCount= 0;
  63. }
  64. for (int32_t locCount=availableLocaleListCount-1; locCount>=0; --locCount) {
  65. availableLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
  66. }
  67. ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup);
  68. }
  69. const Locale* U_EXPORT2
  70. Locale::getAvailableLocales(int32_t& count)
  71. {
  72. umtx_initOnce(gInitOnceLocale, &locale_available_init);
  73. count = availableLocaleListCount;
  74. return availableLocaleList;
  75. }
  76. U_NAMESPACE_END
  77. // C API ------------------------------------------------------------------- ***
  78. U_NAMESPACE_USE
  79. /* ### Constants **************************************************/
  80. namespace {
  81. // Enough capacity for the two lists in the res_index.res file
  82. const char** gAvailableLocaleNames[2] = {};
  83. int32_t gAvailableLocaleCounts[2] = {};
  84. icu::UInitOnce ginstalledLocalesInitOnce {};
  85. class AvailableLocalesSink : public ResourceSink {
  86. public:
  87. void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) override {
  88. ResourceTable resIndexTable = value.getTable(status);
  89. if (U_FAILURE(status)) {
  90. return;
  91. }
  92. for (int32_t i = 0; resIndexTable.getKeyAndValue(i, key, value); ++i) {
  93. ULocAvailableType type;
  94. if (uprv_strcmp(key, "InstalledLocales") == 0) {
  95. type = ULOC_AVAILABLE_DEFAULT;
  96. } else if (uprv_strcmp(key, "AliasLocales") == 0) {
  97. type = ULOC_AVAILABLE_ONLY_LEGACY_ALIASES;
  98. } else {
  99. // CLDRVersion, etc.
  100. continue;
  101. }
  102. ResourceTable availableLocalesTable = value.getTable(status);
  103. if (U_FAILURE(status)) {
  104. return;
  105. }
  106. gAvailableLocaleCounts[type] = availableLocalesTable.getSize();
  107. gAvailableLocaleNames[type] = static_cast<const char**>(
  108. uprv_malloc(gAvailableLocaleCounts[type] * sizeof(const char*)));
  109. if (gAvailableLocaleNames[type] == nullptr) {
  110. status = U_MEMORY_ALLOCATION_ERROR;
  111. return;
  112. }
  113. for (int32_t j = 0; availableLocalesTable.getKeyAndValue(j, key, value); ++j) {
  114. gAvailableLocaleNames[type][j] = key;
  115. }
  116. }
  117. }
  118. };
  119. class AvailableLocalesStringEnumeration : public StringEnumeration {
  120. public:
  121. AvailableLocalesStringEnumeration(ULocAvailableType type) : fType(type) {
  122. }
  123. const char* next(int32_t *resultLength, UErrorCode&) override {
  124. ULocAvailableType actualType = fType;
  125. int32_t actualIndex = fIndex++;
  126. // If the "combined" list was requested, resolve that now
  127. if (fType == ULOC_AVAILABLE_WITH_LEGACY_ALIASES) {
  128. int32_t defaultLocalesCount = gAvailableLocaleCounts[ULOC_AVAILABLE_DEFAULT];
  129. if (actualIndex < defaultLocalesCount) {
  130. actualType = ULOC_AVAILABLE_DEFAULT;
  131. } else {
  132. actualIndex -= defaultLocalesCount;
  133. actualType = ULOC_AVAILABLE_ONLY_LEGACY_ALIASES;
  134. }
  135. }
  136. // Return the requested string
  137. int32_t count = gAvailableLocaleCounts[actualType];
  138. const char* result;
  139. if (actualIndex < count) {
  140. result = gAvailableLocaleNames[actualType][actualIndex];
  141. if (resultLength != nullptr) {
  142. *resultLength = static_cast<int32_t>(uprv_strlen(result));
  143. }
  144. } else {
  145. result = nullptr;
  146. if (resultLength != nullptr) {
  147. *resultLength = 0;
  148. }
  149. }
  150. return result;
  151. }
  152. void reset(UErrorCode&) override {
  153. fIndex = 0;
  154. }
  155. int32_t count(UErrorCode&) const override {
  156. if (fType == ULOC_AVAILABLE_WITH_LEGACY_ALIASES) {
  157. return gAvailableLocaleCounts[ULOC_AVAILABLE_DEFAULT]
  158. + gAvailableLocaleCounts[ULOC_AVAILABLE_ONLY_LEGACY_ALIASES];
  159. } else {
  160. return gAvailableLocaleCounts[fType];
  161. }
  162. }
  163. private:
  164. ULocAvailableType fType;
  165. int32_t fIndex = 0;
  166. };
  167. /* ### Get available **************************************************/
  168. static UBool U_CALLCONV uloc_cleanup() {
  169. for (int32_t i = 0; i < UPRV_LENGTHOF(gAvailableLocaleNames); i++) {
  170. uprv_free(gAvailableLocaleNames[i]);
  171. gAvailableLocaleNames[i] = nullptr;
  172. gAvailableLocaleCounts[i] = 0;
  173. }
  174. ginstalledLocalesInitOnce.reset();
  175. return true;
  176. }
  177. // Load Installed Locales. This function will be called exactly once
  178. // via the initOnce mechanism.
  179. static void U_CALLCONV loadInstalledLocales(UErrorCode& status) {
  180. ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
  181. icu::LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "res_index", &status));
  182. AvailableLocalesSink sink;
  183. ures_getAllItemsWithFallback(rb.getAlias(), "", sink, status);
  184. }
  185. void _load_installedLocales(UErrorCode& status) {
  186. umtx_initOnce(ginstalledLocalesInitOnce, &loadInstalledLocales, status);
  187. }
  188. } // namespace
  189. U_CAPI const char* U_EXPORT2
  190. uloc_getAvailable(int32_t offset) {
  191. icu::ErrorCode status;
  192. _load_installedLocales(status);
  193. if (status.isFailure()) {
  194. return nullptr;
  195. }
  196. if (offset > gAvailableLocaleCounts[0]) {
  197. // *status = U_ILLEGAL_ARGUMENT_ERROR;
  198. return nullptr;
  199. }
  200. return gAvailableLocaleNames[0][offset];
  201. }
  202. U_CAPI int32_t U_EXPORT2
  203. uloc_countAvailable() {
  204. icu::ErrorCode status;
  205. _load_installedLocales(status);
  206. if (status.isFailure()) {
  207. return 0;
  208. }
  209. return gAvailableLocaleCounts[0];
  210. }
  211. U_CAPI UEnumeration* U_EXPORT2
  212. uloc_openAvailableByType(ULocAvailableType type, UErrorCode* status) {
  213. if (U_FAILURE(*status)) {
  214. return nullptr;
  215. }
  216. if (type < 0 || type >= ULOC_AVAILABLE_COUNT) {
  217. *status = U_ILLEGAL_ARGUMENT_ERROR;
  218. return nullptr;
  219. }
  220. _load_installedLocales(*status);
  221. if (U_FAILURE(*status)) {
  222. return nullptr;
  223. }
  224. LocalPointer<AvailableLocalesStringEnumeration> result(
  225. new AvailableLocalesStringEnumeration(type), *status);
  226. if (U_FAILURE(*status)) {
  227. return nullptr;
  228. }
  229. return uenum_openFromStringEnumeration(result.orphan(), status);
  230. }