+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
-* Copyright (C) 1996-2014, International Business Machines
+* Copyright (C) 1996-2016, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: ucol_res.cpp
-* encoding: US-ASCII
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
#include "unicode/uloc.h"
#include "unicode/unistr.h"
#include "unicode/ures.h"
+#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "collationdatareader.h"
#include "collationroot.h"
#include "collationtailoring.h"
+#include "resource.h"
#include "putilimp.h"
#include "uassert.h"
#include "ucln_in.h"
static const UChar *rootRules = NULL;
static int32_t rootRulesLength = 0;
static UResourceBundle *rootBundle = NULL;
-static UInitOnce gInitOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gInitOnceUcolRes = U_INITONCE_INITIALIZER;
} // namespace
rootRulesLength = 0;
ures_close(rootBundle);
rootBundle = NULL;
- gInitOnce.reset();
+ gInitOnceUcolRes.reset();
return TRUE;
}
-U_CDECL_END
-
-void
+void U_CALLCONV
CollationLoader::loadRootRules(UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) { return; }
rootBundle = ures_open(U_ICUDATA_COLL, kRootLocaleName, &errorCode);
ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
}
+U_CDECL_END
+
void
CollationLoader::appendRootRules(UnicodeString &s) {
UErrorCode errorCode = U_ZERO_ERROR;
- umtx_initOnce(gInitOnce, CollationLoader::loadRootRules, errorCode);
+ umtx_initOnce(gInitOnceUcolRes, CollationLoader::loadRootRules, errorCode);
if(U_SUCCESS(errorCode)) {
s.append(rootRules, rootRulesLength);
}
U_ASSERT(collationType != NULL && *collationType != 0);
// Copy the type for lowercasing.
char type[16];
- int32_t typeLength = uprv_strlen(collationType);
+ int32_t typeLength = static_cast<int32_t>(uprv_strlen(collationType));
if(typeLength >= UPRV_LENGTHOF(type)) {
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
return;
// Load the collations/type tailoring, with type fallback.
LocalUResourceBundlePointer localData(
ures_getByKeyWithFallback(collations, type, NULL, &errorCode));
- int32_t typeLength = uprv_strlen(type);
+ int32_t typeLength = static_cast<int32_t>(uprv_strlen(type));
if(errorCode == U_MISSING_RESOURCE_ERROR) {
errorCode = U_USING_DEFAULT_WARNING;
typeFallback = TRUE;
const char *actualLocale = ures_getLocaleByType(data, ULOC_ACTUAL_LOCALE, &errorCode);
if(U_FAILURE(errorCode)) { return NULL; }
const char *vLocale = validLocale.getBaseName();
- UBool actualAndValidLocalesAreDifferent = uprv_strcmp(actualLocale, vLocale) != 0;
+ UBool actualAndValidLocalesAreDifferent = Locale(actualLocale) != Locale(vLocale);
// Set the collation types on the informational locales,
// except when they match the default types (for brevity and backwards compatibility).
// Try to fetch the optional rules string.
{
UErrorCode internalErrorCode = U_ZERO_ERROR;
- int32_t length;
- const UChar *s = ures_getStringByKey(data, "Sequence", &length,
+ int32_t len;
+ const UChar *s = ures_getStringByKey(data, "Sequence", &len,
&internalErrorCode);
if(U_SUCCESS(internalErrorCode)) {
- t->rules.setTo(TRUE, s, length);
+ t->rules.setTo(TRUE, s, len);
}
}
const char *actualLocale = locale.getBaseName(); // without type
const char *vLocale = validLocale.getBaseName();
- UBool actualAndValidLocalesAreDifferent = uprv_strcmp(actualLocale, vLocale) != 0;
+ UBool actualAndValidLocalesAreDifferent = Locale(actualLocale) != Locale(vLocale);
// For the actual locale, suppress the default type *according to the actual locale*.
// For example, zh has default=pinyin and contains all of the Chinese tailorings.
LocalUResourceBundlePointer def(
ures_getByKeyWithFallback(actualBundle.getAlias(), "collations/default", NULL,
&internalErrorCode));
- int32_t length;
- const UChar *s = ures_getString(def.getAlias(), &length, &internalErrorCode);
- if(U_SUCCESS(internalErrorCode) && length < UPRV_LENGTHOF(defaultType)) {
- u_UCharsToChars(s, defaultType, length + 1);
+ int32_t len;
+ const UChar *s = ures_getString(def.getAlias(), &len, &internalErrorCode);
+ if(U_SUCCESS(internalErrorCode) && len < UPRV_LENGTHOF(defaultType)) {
+ u_UCharsToChars(s, defaultType, len + 1);
} else {
uprv_strcpy(defaultType, "standard");
}
const CollationCacheEntry *entry = new CollationCacheEntry(validLocale, t.getAlias());
if(entry == NULL) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
} else {
t.orphan();
}
ucol_open(const char *loc,
UErrorCode *status)
{
- U_NAMESPACE_USE
-
UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN);
UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc);
UCollator *result = NULL;
int32_t resultLength,
UErrorCode *status)
{
- U_NAMESPACE_USE
-
if(U_FAILURE(*status)) return -1;
UnicodeString dst;
if(!(result==NULL && resultLength==0)) {
#if !UCONFIG_NO_SERVICE
U_CAPI UEnumeration* U_EXPORT2
ucol_openAvailableLocales(UErrorCode *status) {
- U_NAMESPACE_USE
-
// This is a wrapper over Collator::getAvailableLocales()
if (U_FAILURE(*status)) {
return NULL;
ulist_reset_keyword_values_iterator
};
-#include <stdio.h>
-
-U_CAPI UEnumeration* U_EXPORT2
-ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
- UBool /*commonlyUsed*/, UErrorCode* status) {
- /* Get the locale base name. */
- char localeBuffer[ULOC_FULLNAME_CAPACITY] = "";
- uloc_getBaseName(locale, localeBuffer, sizeof(localeBuffer), status);
-
- /* Create the 2 lists
- * -values is the temp location for the keyword values
- * -results hold the actual list used by the UEnumeration object
- */
- UList *values = ulist_createEmptyList(status);
- UList *results = ulist_createEmptyList(status);
- UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
- if (U_FAILURE(*status) || en == NULL) {
- if (en == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- uprv_free(en);
- }
- ulist_deleteList(values);
- ulist_deleteList(results);
- return NULL;
- }
+namespace {
- memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
- en->context = results;
-
- /* Open the resource bundle for collation with the given locale. */
- UResourceBundle bundle, collations, collres, defres;
- ures_initStackObject(&bundle);
- ures_initStackObject(&collations);
- ures_initStackObject(&collres);
- ures_initStackObject(&defres);
-
- ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
-
- while (U_SUCCESS(*status)) {
- ures_getByKey(&bundle, RESOURCE_NAME, &collations, status);
- ures_resetIterator(&collations);
- while (U_SUCCESS(*status) && ures_hasNext(&collations)) {
- ures_getNextResource(&collations, &collres, status);
- const char *key = ures_getKey(&collres);
- /* If the key is default, get the string and store it in results list only
- * if results list is empty.
- */
- if (uprv_strcmp(key, "default") == 0) {
- if (ulist_getListSize(results) == 0) {
- char *defcoll = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
- int32_t defcollLength = ULOC_KEYWORDS_CAPACITY;
-
- ures_getNextResource(&collres, &defres, status);
-#if U_CHARSET_FAMILY==U_ASCII_FAMILY
- /* optimize - use the utf-8 string */
- ures_getUTF8String(&defres, defcoll, &defcollLength, TRUE, status);
-#else
- {
- const UChar* defString = ures_getString(&defres, &defcollLength, status);
- if(U_SUCCESS(*status)) {
- if(defcollLength+1 > ULOC_KEYWORDS_CAPACITY) {
- *status = U_BUFFER_OVERFLOW_ERROR;
- } else {
- u_UCharsToChars(defString, defcoll, defcollLength+1);
- }
- }
+struct KeywordsSink : public ResourceSink {
+public:
+ KeywordsSink(UErrorCode &errorCode) :
+ values(ulist_createEmptyList(&errorCode)), hasDefault(FALSE) {}
+ virtual ~KeywordsSink();
+
+ virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
+ UErrorCode &errorCode) {
+ if (U_FAILURE(errorCode)) { return; }
+ ResourceTable collations = value.getTable(errorCode);
+ for (int32_t i = 0; collations.getKeyAndValue(i, key, value); ++i) {
+ UResType type = value.getType();
+ if (type == URES_STRING) {
+ if (!hasDefault && uprv_strcmp(key, "default") == 0) {
+ CharString defcoll;
+ defcoll.appendInvariantChars(value.getUnicodeString(errorCode), errorCode);
+ if (U_SUCCESS(errorCode) && !defcoll.isEmpty()) {
+ char *ownedDefault = uprv_strdup(defcoll.data());
+ if (ownedDefault == NULL) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ ulist_removeString(values, defcoll.data());
+ ulist_addItemBeginList(values, ownedDefault, TRUE, &errorCode);
+ hasDefault = TRUE;
}
-#endif
-
- ulist_addItemBeginList(results, defcoll, TRUE, status);
}
- } else if (uprv_strncmp(key, "private-", 8) != 0) {
- ulist_addItemEndList(values, key, FALSE, status);
- }
- }
-
- /* If the locale is "" this is root so exit. */
- if (uprv_strlen(localeBuffer) == 0) {
- break;
- }
- /* Get the parent locale and open a new resource bundle. */
- uloc_getParent(localeBuffer, localeBuffer, sizeof(localeBuffer), status);
- ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
- }
-
- ures_close(&defres);
- ures_close(&collres);
- ures_close(&collations);
- ures_close(&bundle);
-
- if (U_SUCCESS(*status)) {
- char *value = NULL;
- ulist_resetList(values);
- while ((value = (char *)ulist_getNext(values)) != NULL) {
- if (!ulist_containsString(results, value, (int32_t)uprv_strlen(value))) {
- ulist_addItemEndList(results, value, FALSE, status);
- if (U_FAILURE(*status)) {
- break;
+ } else if (type == URES_TABLE && uprv_strncmp(key, "private-", 8) != 0) {
+ if (!ulist_containsString(values, key, (int32_t)uprv_strlen(key))) {
+ ulist_addItemEndList(values, key, FALSE, &errorCode);
}
}
+ if (U_FAILURE(errorCode)) { return; }
}
}
+ UList *values;
+ UBool hasDefault;
+};
+
+KeywordsSink::~KeywordsSink() {
ulist_deleteList(values);
+}
- if (U_FAILURE(*status)){
- uenum_close(en);
- en = NULL;
- } else {
- ulist_resetList(results);
- }
+} // namespace
+
+U_CAPI UEnumeration* U_EXPORT2
+ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
+ UBool /*commonlyUsed*/, UErrorCode* status) {
+ // Note: The parameter commonlyUsed is not used.
+ // The switch is in the method signature for consistency
+ // with other locale services.
+ // Read available collation values from collation bundles.
+ LocalUResourceBundlePointer bundle(ures_open(U_ICUDATA_COLL, locale, status));
+ KeywordsSink sink(*status);
+ ures_getAllItemsWithFallback(bundle.getAlias(), RESOURCE_NAME, sink, *status);
+ if (U_FAILURE(*status)) { return NULL; }
+
+ UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
+ if (en == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
+ ulist_resetList(sink.values); // Initialize the iterator.
+ en->context = sink.values;
+ sink.values = NULL; // Avoid deletion in the sink destructor.
return en;
}