summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/common/locavailable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/icu-small/source/common/locavailable.cpp')
-rw-r--r--deps/icu-small/source/common/locavailable.cpp206
1 files changed, 149 insertions, 57 deletions
diff --git a/deps/icu-small/source/common/locavailable.cpp b/deps/icu-small/source/common/locavailable.cpp
index 1e608ffb9e..ad9d2ca8c7 100644
--- a/deps/icu-small/source/common/locavailable.cpp
+++ b/deps/icu-small/source/common/locavailable.cpp
@@ -19,11 +19,13 @@
* that then do not depend on resource bundle code and res_index bundles.
*/
+#include "unicode/errorcode.h"
#include "unicode/utypes.h"
#include "unicode/locid.h"
#include "unicode/uloc.h"
#include "unicode/ures.h"
#include "cmemory.h"
+#include "cstring.h"
#include "ucln_cmn.h"
#include "uassert.h"
#include "umutex.h"
@@ -95,84 +97,174 @@ U_NAMESPACE_USE
/* ### Constants **************************************************/
-/* These strings describe the resources we attempt to load from
- the locale ResourceBundle data file.*/
-static const char _kIndexLocaleName[] = "res_index";
-static const char _kIndexTag[] = "InstalledLocales";
+namespace {
-static char** _installedLocales = NULL;
-static int32_t _installedLocalesCount = 0;
-static icu::UInitOnce _installedLocalesInitOnce;
+// Enough capacity for the two lists in the res_index.res file
+const char** gAvailableLocaleNames[2] = {};
+int32_t gAvailableLocaleCounts[2] = {};
+icu::UInitOnce ginstalledLocalesInitOnce = U_INITONCE_INITIALIZER;
-/* ### Get available **************************************************/
+class AvailableLocalesSink : public ResourceSink {
+ public:
+ void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) U_OVERRIDE {
+ ResourceTable resIndexTable = value.getTable(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ for (int32_t i = 0; resIndexTable.getKeyAndValue(i, key, value); ++i) {
+ ULocAvailableType type;
+ if (uprv_strcmp(key, "InstalledLocales") == 0) {
+ type = ULOC_AVAILABLE_DEFAULT;
+ } else if (uprv_strcmp(key, "AliasLocales") == 0) {
+ type = ULOC_AVAILABLE_ONLY_LEGACY_ALIASES;
+ } else {
+ // CLDRVersion, etc.
+ continue;
+ }
+ ResourceTable availableLocalesTable = value.getTable(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ gAvailableLocaleCounts[type] = availableLocalesTable.getSize();
+ gAvailableLocaleNames[type] = static_cast<const char**>(
+ uprv_malloc(gAvailableLocaleCounts[type] * sizeof(const char*)));
+ if (gAvailableLocaleNames[type] == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (int32_t j = 0; availableLocalesTable.getKeyAndValue(j, key, value); ++j) {
+ gAvailableLocaleNames[type][j] = key;
+ }
+ }
+ }
+};
-static UBool U_CALLCONV uloc_cleanup(void) {
- char ** temp;
+class AvailableLocalesStringEnumeration : public StringEnumeration {
+ public:
+ AvailableLocalesStringEnumeration(ULocAvailableType type) : fType(type) {
+ }
+
+ const char* next(int32_t *resultLength, UErrorCode&) override {
+ ULocAvailableType actualType = fType;
+ int32_t actualIndex = fIndex++;
+
+ // If the "combined" list was requested, resolve that now
+ if (fType == ULOC_AVAILABLE_WITH_LEGACY_ALIASES) {
+ int32_t defaultLocalesCount = gAvailableLocaleCounts[ULOC_AVAILABLE_DEFAULT];
+ if (actualIndex < defaultLocalesCount) {
+ actualType = ULOC_AVAILABLE_DEFAULT;
+ } else {
+ actualIndex -= defaultLocalesCount;
+ actualType = ULOC_AVAILABLE_ONLY_LEGACY_ALIASES;
+ }
+ }
+
+ // Return the requested string
+ int32_t count = gAvailableLocaleCounts[actualType];
+ const char* result;
+ if (actualIndex < count) {
+ result = gAvailableLocaleNames[actualType][actualIndex];
+ if (resultLength != nullptr) {
+ *resultLength = static_cast<int32_t>(uprv_strlen(result));
+ }
+ } else {
+ result = nullptr;
+ if (resultLength != nullptr) {
+ *resultLength = 0;
+ }
+ }
+ return result;
+ }
+
+ void reset(UErrorCode&) override {
+ fIndex = 0;
+ }
+
+ int32_t count(UErrorCode&) const override {
+ if (fType == ULOC_AVAILABLE_WITH_LEGACY_ALIASES) {
+ return gAvailableLocaleCounts[ULOC_AVAILABLE_DEFAULT]
+ + gAvailableLocaleCounts[ULOC_AVAILABLE_ONLY_LEGACY_ALIASES];
+ } else {
+ return gAvailableLocaleCounts[fType];
+ }
+ }
- if (_installedLocales) {
- temp = _installedLocales;
- _installedLocales = NULL;
+ private:
+ ULocAvailableType fType;
+ int32_t fIndex = 0;
+};
- _installedLocalesCount = 0;
- _installedLocalesInitOnce.reset();
+/* ### Get available **************************************************/
- uprv_free(temp);
+static UBool U_CALLCONV uloc_cleanup(void) {
+ for (int32_t i = 0; i < UPRV_LENGTHOF(gAvailableLocaleNames); i++) {
+ uprv_free(gAvailableLocaleNames[i]);
+ gAvailableLocaleNames[i] = nullptr;
+ gAvailableLocaleCounts[i] = 0;
}
+ ginstalledLocalesInitOnce.reset();
return TRUE;
}
// Load Installed Locales. This function will be called exactly once
// via the initOnce mechanism.
-static void U_CALLCONV loadInstalledLocales() {
- UErrorCode status = U_ZERO_ERROR;
- int32_t i = 0;
- int32_t localeCount;
-
- U_ASSERT(_installedLocales == NULL);
- U_ASSERT(_installedLocalesCount == 0);
+static void U_CALLCONV loadInstalledLocales(UErrorCode& status) {
+ ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
- _installedLocalesCount = 0;
+ icu::LocalUResourceBundlePointer rb(ures_openDirect(NULL, "res_index", &status));
+ AvailableLocalesSink sink;
+ ures_getAllItemsWithFallback(rb.getAlias(), "", sink, status);
+}
- icu::LocalUResourceBundlePointer indexLocale(ures_openDirect(NULL, _kIndexLocaleName, &status));
- icu::StackUResourceBundle installed;
+void _load_installedLocales(UErrorCode& status) {
+ umtx_initOnce(ginstalledLocalesInitOnce, &loadInstalledLocales, status);
+}
- ures_getByKey(indexLocale.getAlias(), _kIndexTag, installed.getAlias(), &status);
+} // namespace
- if(U_SUCCESS(status)) {
- localeCount = ures_getSize(installed.getAlias());
- _installedLocales = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
- if (_installedLocales != NULL) {
- ures_resetIterator(installed.getAlias());
- while(ures_hasNext(installed.getAlias())) {
- ures_getNextString(installed.getAlias(), NULL, (const char **)&_installedLocales[i++], &status);
- }
- _installedLocales[i] = NULL;
- _installedLocalesCount = localeCount;
- ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
- }
+U_CAPI const char* U_EXPORT2
+uloc_getAvailable(int32_t offset) {
+ icu::ErrorCode status;
+ _load_installedLocales(status);
+ if (status.isFailure()) {
+ return nullptr;
+ }
+ if (offset > gAvailableLocaleCounts[0]) {
+ // *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
}
+ return gAvailableLocaleNames[0][offset];
}
-static void _load_installedLocales()
-{
- umtx_initOnce(_installedLocalesInitOnce, &loadInstalledLocales);
+U_CAPI int32_t U_EXPORT2
+uloc_countAvailable() {
+ icu::ErrorCode status;
+ _load_installedLocales(status);
+ if (status.isFailure()) {
+ return 0;
+ }
+ return gAvailableLocaleCounts[0];
}
-U_CAPI const char* U_EXPORT2
-uloc_getAvailable(int32_t offset)
-{
-
- _load_installedLocales();
-
- if (offset > _installedLocalesCount)
- return NULL;
- return _installedLocales[offset];
+U_CAPI UEnumeration* U_EXPORT2
+uloc_openAvailableByType(ULocAvailableType type, UErrorCode* status) {
+ if (U_FAILURE(*status)) {
+ return nullptr;
+ }
+ if (type < 0 || type >= ULOC_AVAILABLE_COUNT) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
+ }
+ _load_installedLocales(*status);
+ if (U_FAILURE(*status)) {
+ return nullptr;
+ }
+ LocalPointer<AvailableLocalesStringEnumeration> result(
+ new AvailableLocalesStringEnumeration(type), *status);
+ if (U_FAILURE(*status)) {
+ return nullptr;
+ }
+ return uenum_openFromStringEnumeration(result.orphan(), status);
}
-U_CAPI int32_t U_EXPORT2
-uloc_countAvailable()
-{
- _load_installedLocales();
- return _installedLocalesCount;
-}