LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - ucol_res.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 325 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : *   Copyright (C) 1996-2016, International Business Machines
       6             : *   Corporation and others.  All Rights Reserved.
       7             : *******************************************************************************
       8             : *   file name:  ucol_res.cpp
       9             : *   encoding:   UTF-8
      10             : *   tab size:   8 (not used)
      11             : *   indentation:4
      12             : *
      13             : * Description:
      14             : * This file contains dependencies that the collation run-time doesn't normally
      15             : * need. This mainly contains resource bundle usage and collation meta information
      16             : *
      17             : * Modification history
      18             : * Date        Name      Comments
      19             : * 1996-1999   various members of ICU team maintained C API for collation framework
      20             : * 02/16/2001  synwee    Added internal method getPrevSpecialCE
      21             : * 03/01/2001  synwee    Added maxexpansion functionality.
      22             : * 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
      23             : * 12/08/2004  grhoten   Split part of ucol.cpp into ucol_res.cpp
      24             : * 2012-2014   markus    Rewritten in C++ again.
      25             : */
      26             : 
      27             : #include "unicode/utypes.h"
      28             : 
      29             : #if !UCONFIG_NO_COLLATION
      30             : 
      31             : #include "unicode/coll.h"
      32             : #include "unicode/localpointer.h"
      33             : #include "unicode/locid.h"
      34             : #include "unicode/tblcoll.h"
      35             : #include "unicode/ucol.h"
      36             : #include "unicode/uloc.h"
      37             : #include "unicode/unistr.h"
      38             : #include "unicode/ures.h"
      39             : #include "charstr.h"
      40             : #include "cmemory.h"
      41             : #include "cstring.h"
      42             : #include "collationdatareader.h"
      43             : #include "collationroot.h"
      44             : #include "collationtailoring.h"
      45             : #include "resource.h"
      46             : #include "putilimp.h"
      47             : #include "uassert.h"
      48             : #include "ucln_in.h"
      49             : #include "ucol_imp.h"
      50             : #include "uenumimp.h"
      51             : #include "ulist.h"
      52             : #include "umutex.h"
      53             : #include "unifiedcache.h"
      54             : #include "uresimp.h"
      55             : #include "ustrenum.h"
      56             : #include "utracimp.h"
      57             : 
      58             : U_NAMESPACE_BEGIN
      59             : 
      60             : namespace {
      61             : 
      62             : static const UChar *rootRules = NULL;
      63             : static int32_t rootRulesLength = 0;
      64             : static UResourceBundle *rootBundle = NULL;
      65             : static UInitOnce gInitOnce = U_INITONCE_INITIALIZER;
      66             : 
      67             : }  // namespace
      68             : 
      69             : U_CDECL_BEGIN
      70             : 
      71             : static UBool U_CALLCONV
      72           0 : ucol_res_cleanup() {
      73           0 :     rootRules = NULL;
      74           0 :     rootRulesLength = 0;
      75           0 :     ures_close(rootBundle);
      76           0 :     rootBundle = NULL;
      77           0 :     gInitOnce.reset();
      78           0 :     return TRUE;
      79             : }
      80             : 
      81             : void U_CALLCONV
      82           0 : CollationLoader::loadRootRules(UErrorCode &errorCode) {
      83           0 :     if(U_FAILURE(errorCode)) { return; }
      84           0 :     rootBundle = ures_open(U_ICUDATA_COLL, kRootLocaleName, &errorCode);
      85           0 :     if(U_FAILURE(errorCode)) { return; }
      86           0 :     rootRules = ures_getStringByKey(rootBundle, "UCARules", &rootRulesLength, &errorCode);
      87           0 :     if(U_FAILURE(errorCode)) {
      88           0 :         ures_close(rootBundle);
      89           0 :         rootBundle = NULL;
      90           0 :         return;
      91             :     }
      92           0 :     ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
      93             : }
      94             : 
      95             : U_CDECL_END
      96             : 
      97             : void
      98           0 : CollationLoader::appendRootRules(UnicodeString &s) {
      99           0 :     UErrorCode errorCode = U_ZERO_ERROR;
     100           0 :     umtx_initOnce(gInitOnce, CollationLoader::loadRootRules, errorCode);
     101           0 :     if(U_SUCCESS(errorCode)) {
     102           0 :         s.append(rootRules, rootRulesLength);
     103             :     }
     104           0 : }
     105             : 
     106             : void
     107           0 : CollationLoader::loadRules(const char *localeID, const char *collationType,
     108             :                            UnicodeString &rules, UErrorCode &errorCode) {
     109           0 :     if(U_FAILURE(errorCode)) { return; }
     110           0 :     U_ASSERT(collationType != NULL && *collationType != 0);
     111             :     // Copy the type for lowercasing.
     112             :     char type[16];
     113           0 :     int32_t typeLength = uprv_strlen(collationType);
     114           0 :     if(typeLength >= UPRV_LENGTHOF(type)) {
     115           0 :         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
     116           0 :         return;
     117             :     }
     118           0 :     uprv_memcpy(type, collationType, typeLength + 1);
     119           0 :     T_CString_toLowerCase(type);
     120             : 
     121           0 :     LocalUResourceBundlePointer bundle(ures_open(U_ICUDATA_COLL, localeID, &errorCode));
     122             :     LocalUResourceBundlePointer collations(
     123           0 :             ures_getByKey(bundle.getAlias(), "collations", NULL, &errorCode));
     124             :     LocalUResourceBundlePointer data(
     125           0 :             ures_getByKeyWithFallback(collations.getAlias(), type, NULL, &errorCode));
     126             :     int32_t length;
     127           0 :     const UChar *s =  ures_getStringByKey(data.getAlias(), "Sequence", &length, &errorCode);
     128           0 :     if(U_FAILURE(errorCode)) { return; }
     129             : 
     130             :     // No string pointer aliasing so that we need not hold onto the resource bundle.
     131           0 :     rules.setTo(s, length);
     132           0 :     if(rules.isBogus()) {
     133           0 :         errorCode = U_MEMORY_ALLOCATION_ERROR;
     134             :     }
     135             : }
     136             : 
     137             : template<> U_I18N_API
     138             : const CollationCacheEntry *
     139           0 : LocaleCacheKey<CollationCacheEntry>::createObject(const void *creationContext,
     140             :                                                   UErrorCode &errorCode) const {
     141             :     CollationLoader *loader =
     142             :             reinterpret_cast<CollationLoader *>(
     143           0 :                     const_cast<void *>(creationContext));
     144           0 :     return loader->createCacheEntry(errorCode);
     145             : }
     146             : 
     147             : const CollationCacheEntry *
     148           0 : CollationLoader::loadTailoring(const Locale &locale, UErrorCode &errorCode) {
     149           0 :     const CollationCacheEntry *rootEntry = CollationRoot::getRootCacheEntry(errorCode);
     150           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     151           0 :     const char *name = locale.getName();
     152           0 :     if(*name == 0 || uprv_strcmp(name, "root") == 0) {
     153             : 
     154             :         // Have to add a ref.
     155           0 :         rootEntry->addRef();
     156           0 :         return rootEntry;
     157             :     }
     158             : 
     159             :     // Clear warning codes before loading where they get cached.
     160           0 :     errorCode = U_ZERO_ERROR;
     161           0 :     CollationLoader loader(rootEntry, locale, errorCode);
     162             : 
     163             :     // getCacheEntry adds a ref for us.
     164           0 :     return loader.getCacheEntry(errorCode);
     165             : }
     166             : 
     167           0 : CollationLoader::CollationLoader(const CollationCacheEntry *re, const Locale &requested,
     168           0 :                                  UErrorCode &errorCode)
     169           0 :         : cache(UnifiedCache::getInstance(errorCode)), rootEntry(re),
     170             :           validLocale(re->validLocale), locale(requested),
     171             :           typesTried(0), typeFallback(FALSE),
     172           0 :           bundle(NULL), collations(NULL), data(NULL) {
     173           0 :     type[0] = 0;
     174           0 :     defaultType[0] = 0;
     175           0 :     if(U_FAILURE(errorCode)) { return; }
     176             : 
     177             :     // Canonicalize the locale ID: Ignore all irrelevant keywords.
     178           0 :     const char *baseName = locale.getBaseName();
     179           0 :     if(uprv_strcmp(locale.getName(), baseName) != 0) {
     180           0 :         locale = Locale(baseName);
     181             : 
     182             :         // Fetch the collation type from the locale ID.
     183           0 :         int32_t typeLength = requested.getKeywordValue("collation",
     184           0 :                 type, UPRV_LENGTHOF(type) - 1, errorCode);
     185           0 :         if(U_FAILURE(errorCode)) {
     186           0 :             errorCode = U_ILLEGAL_ARGUMENT_ERROR;
     187           0 :             return;
     188             :         }
     189           0 :         type[typeLength] = 0;  // in case of U_NOT_TERMINATED_WARNING
     190           0 :         if(typeLength == 0) {
     191             :             // No collation type.
     192           0 :         } else if(uprv_stricmp(type, "default") == 0) {
     193             :             // Ignore "default" (case-insensitive).
     194           0 :             type[0] = 0;
     195             :         } else {
     196             :             // Copy the collation type.
     197           0 :             T_CString_toLowerCase(type);
     198           0 :             locale.setKeywordValue("collation", type, errorCode);
     199             :         }
     200             :     }
     201             : }
     202             : 
     203           0 : CollationLoader::~CollationLoader() {
     204           0 :     ures_close(data);
     205           0 :     ures_close(collations);
     206           0 :     ures_close(bundle);
     207           0 : }
     208             : 
     209             : const CollationCacheEntry *
     210           0 : CollationLoader::createCacheEntry(UErrorCode &errorCode) {
     211             :     // This is a linear lookup and fallback flow turned into a state machine.
     212             :     // Most local variables have been turned into instance fields.
     213             :     // In a cache miss, cache.get() calls CacheKey::createObject(),
     214             :     // which means that we progress via recursion.
     215             :     // loadFromCollations() will recurse to itself as well for collation type fallback.
     216           0 :     if(bundle == NULL) {
     217           0 :         return loadFromLocale(errorCode);
     218           0 :     } else if(collations == NULL) {
     219           0 :         return loadFromBundle(errorCode);
     220           0 :     } else if(data == NULL) {
     221           0 :         return loadFromCollations(errorCode);
     222             :     } else {
     223           0 :         return loadFromData(errorCode);
     224             :     }
     225             : }
     226             : 
     227             : const CollationCacheEntry *
     228           0 : CollationLoader::loadFromLocale(UErrorCode &errorCode) {
     229           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     230           0 :     U_ASSERT(bundle == NULL);
     231           0 :     bundle = ures_openNoDefault(U_ICUDATA_COLL, locale.getBaseName(), &errorCode);
     232           0 :     if(errorCode == U_MISSING_RESOURCE_ERROR) {
     233           0 :         errorCode = U_USING_DEFAULT_WARNING;
     234             : 
     235             :         // Have to add that ref that we promise.
     236           0 :         rootEntry->addRef();
     237           0 :         return rootEntry;
     238             :     }
     239           0 :     Locale requestedLocale(locale);
     240           0 :     const char *vLocale = ures_getLocaleByType(bundle, ULOC_ACTUAL_LOCALE, &errorCode);
     241           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     242           0 :     locale = validLocale = Locale(vLocale);  // no type until loadFromCollations()
     243           0 :     if(type[0] != 0) {
     244           0 :         locale.setKeywordValue("collation", type, errorCode);
     245             :     }
     246           0 :     if(locale != requestedLocale) {
     247           0 :         return getCacheEntry(errorCode);
     248             :     } else {
     249           0 :         return loadFromBundle(errorCode);
     250             :     }
     251             : }
     252             : 
     253             : const CollationCacheEntry *
     254           0 : CollationLoader::loadFromBundle(UErrorCode &errorCode) {
     255           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     256           0 :     U_ASSERT(collations == NULL);
     257             :     // There are zero or more tailorings in the collations table.
     258           0 :     collations = ures_getByKey(bundle, "collations", NULL, &errorCode);
     259           0 :     if(errorCode == U_MISSING_RESOURCE_ERROR) {
     260           0 :         errorCode = U_USING_DEFAULT_WARNING;
     261             :         // Return the root tailoring with the validLocale, without collation type.
     262           0 :         return makeCacheEntryFromRoot(validLocale, errorCode);
     263             :     }
     264           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     265             : 
     266             :     // Fetch the default type from the data.
     267             :     {
     268           0 :         UErrorCode internalErrorCode = U_ZERO_ERROR;
     269             :         LocalUResourceBundlePointer def(
     270           0 :                 ures_getByKeyWithFallback(collations, "default", NULL, &internalErrorCode));
     271             :         int32_t length;
     272           0 :         const UChar *s = ures_getString(def.getAlias(), &length, &internalErrorCode);
     273           0 :         if(U_SUCCESS(internalErrorCode) && 0 < length && length < UPRV_LENGTHOF(defaultType)) {
     274           0 :             u_UCharsToChars(s, defaultType, length + 1);
     275             :         } else {
     276           0 :             uprv_strcpy(defaultType, "standard");
     277             :         }
     278             :     }
     279             : 
     280             :     // Record which collation types we have looked for already,
     281             :     // so that we do not deadlock in the cache.
     282             :     //
     283             :     // If there is no explicit type, then we look in the cache
     284             :     // for the entry with the default type.
     285             :     // If the explicit type is the default type, then we do not look in the cache
     286             :     // for the entry with an empty type.
     287             :     // Otherwise, two concurrent requests with opposite fallbacks would deadlock each other.
     288             :     // Also, it is easier to always enter the next method with a non-empty type.
     289           0 :     if(type[0] == 0) {
     290           0 :         uprv_strcpy(type, defaultType);
     291           0 :         typesTried |= TRIED_DEFAULT;
     292           0 :         if(uprv_strcmp(type, "search") == 0) {
     293           0 :             typesTried |= TRIED_SEARCH;
     294             :         }
     295           0 :         if(uprv_strcmp(type, "standard") == 0) {
     296           0 :             typesTried |= TRIED_STANDARD;
     297             :         }
     298           0 :         locale.setKeywordValue("collation", type, errorCode);
     299           0 :         return getCacheEntry(errorCode);
     300             :     } else {
     301           0 :         if(uprv_strcmp(type, defaultType) == 0) {
     302           0 :             typesTried |= TRIED_DEFAULT;
     303             :         }
     304           0 :         if(uprv_strcmp(type, "search") == 0) {
     305           0 :             typesTried |= TRIED_SEARCH;
     306             :         }
     307           0 :         if(uprv_strcmp(type, "standard") == 0) {
     308           0 :             typesTried |= TRIED_STANDARD;
     309             :         }
     310           0 :         return loadFromCollations(errorCode);
     311             :     }
     312             : }
     313             : 
     314             : const CollationCacheEntry *
     315           0 : CollationLoader::loadFromCollations(UErrorCode &errorCode) {
     316           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     317           0 :     U_ASSERT(data == NULL);
     318             :     // Load the collations/type tailoring, with type fallback.
     319             :     LocalUResourceBundlePointer localData(
     320           0 :             ures_getByKeyWithFallback(collations, type, NULL, &errorCode));
     321           0 :     int32_t typeLength = uprv_strlen(type);
     322           0 :     if(errorCode == U_MISSING_RESOURCE_ERROR) {
     323           0 :         errorCode = U_USING_DEFAULT_WARNING;
     324           0 :         typeFallback = TRUE;
     325           0 :         if((typesTried & TRIED_SEARCH) == 0 &&
     326           0 :                 typeLength > 6 && uprv_strncmp(type, "search", 6) == 0) {
     327             :             // fall back from something like "searchjl" to "search"
     328           0 :             typesTried |= TRIED_SEARCH;
     329           0 :             type[6] = 0;
     330           0 :         } else if((typesTried & TRIED_DEFAULT) == 0) {
     331             :             // fall back to the default type
     332           0 :             typesTried |= TRIED_DEFAULT;
     333           0 :             uprv_strcpy(type, defaultType);
     334           0 :         } else if((typesTried & TRIED_STANDARD) == 0) {
     335             :             // fall back to the "standard" type
     336           0 :             typesTried |= TRIED_STANDARD;
     337           0 :             uprv_strcpy(type, "standard");
     338             :         } else {
     339             :             // Return the root tailoring with the validLocale, without collation type.
     340           0 :             return makeCacheEntryFromRoot(validLocale, errorCode);
     341             :         }
     342           0 :         locale.setKeywordValue("collation", type, errorCode);
     343           0 :         return getCacheEntry(errorCode);
     344             :     }
     345           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     346             : 
     347           0 :     data = localData.orphan();
     348           0 :     const char *actualLocale = ures_getLocaleByType(data, ULOC_ACTUAL_LOCALE, &errorCode);
     349           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     350           0 :     const char *vLocale = validLocale.getBaseName();
     351           0 :     UBool actualAndValidLocalesAreDifferent = uprv_strcmp(actualLocale, vLocale) != 0;
     352             : 
     353             :     // Set the collation types on the informational locales,
     354             :     // except when they match the default types (for brevity and backwards compatibility).
     355             :     // For the valid locale, suppress the default type.
     356           0 :     if(uprv_strcmp(type, defaultType) != 0) {
     357           0 :         validLocale.setKeywordValue("collation", type, errorCode);
     358           0 :         if(U_FAILURE(errorCode)) { return NULL; }
     359             :     }
     360             : 
     361             :     // Is this the same as the root collator? If so, then use that instead.
     362           0 :     if((*actualLocale == 0 || uprv_strcmp(actualLocale, "root") == 0) &&
     363           0 :             uprv_strcmp(type, "standard") == 0) {
     364           0 :         if(typeFallback) {
     365           0 :             errorCode = U_USING_DEFAULT_WARNING;
     366             :         }
     367           0 :         return makeCacheEntryFromRoot(validLocale, errorCode);
     368             :     }
     369             : 
     370           0 :     locale = Locale(actualLocale);
     371           0 :     if(actualAndValidLocalesAreDifferent) {
     372           0 :         locale.setKeywordValue("collation", type, errorCode);
     373           0 :         const CollationCacheEntry *entry = getCacheEntry(errorCode);
     374           0 :         return makeCacheEntry(validLocale, entry, errorCode);
     375             :     } else {
     376           0 :         return loadFromData(errorCode);
     377             :     }
     378             : }
     379             : 
     380             : const CollationCacheEntry *
     381           0 : CollationLoader::loadFromData(UErrorCode &errorCode) {
     382           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     383           0 :     LocalPointer<CollationTailoring> t(new CollationTailoring(rootEntry->tailoring->settings));
     384           0 :     if(t.isNull() || t->isBogus()) {
     385           0 :         errorCode = U_MEMORY_ALLOCATION_ERROR;
     386           0 :         return NULL;
     387             :     }
     388             : 
     389             :     // deserialize
     390           0 :     LocalUResourceBundlePointer binary(ures_getByKey(data, "%%CollationBin", NULL, &errorCode));
     391             :     // Note: U_MISSING_RESOURCE_ERROR --> The old code built from rules if available
     392             :     // but that created undesirable dependencies.
     393             :     int32_t length;
     394           0 :     const uint8_t *inBytes = ures_getBinary(binary.getAlias(), &length, &errorCode);
     395           0 :     CollationDataReader::read(rootEntry->tailoring, inBytes, length, *t, errorCode);
     396             :     // Note: U_COLLATOR_VERSION_MISMATCH --> The old code built from rules if available
     397             :     // but that created undesirable dependencies.
     398           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     399             : 
     400             :     // Try to fetch the optional rules string.
     401             :     {
     402           0 :         UErrorCode internalErrorCode = U_ZERO_ERROR;
     403             :         int32_t length;
     404           0 :         const UChar *s = ures_getStringByKey(data, "Sequence", &length,
     405           0 :                                              &internalErrorCode);
     406           0 :         if(U_SUCCESS(internalErrorCode)) {
     407           0 :             t->rules.setTo(TRUE, s, length);
     408             :         }
     409             :     }
     410             : 
     411           0 :     const char *actualLocale = locale.getBaseName();  // without type
     412           0 :     const char *vLocale = validLocale.getBaseName();
     413           0 :     UBool actualAndValidLocalesAreDifferent = uprv_strcmp(actualLocale, vLocale) != 0;
     414             : 
     415             :     // For the actual locale, suppress the default type *according to the actual locale*.
     416             :     // For example, zh has default=pinyin and contains all of the Chinese tailorings.
     417             :     // zh_Hant has default=stroke but has no other data.
     418             :     // For the valid locale "zh_Hant" we need to suppress stroke.
     419             :     // For the actual locale "zh" we need to suppress pinyin instead.
     420           0 :     if(actualAndValidLocalesAreDifferent) {
     421             :         // Opening a bundle for the actual locale should always succeed.
     422             :         LocalUResourceBundlePointer actualBundle(
     423           0 :                 ures_open(U_ICUDATA_COLL, actualLocale, &errorCode));
     424           0 :         if(U_FAILURE(errorCode)) { return NULL; }
     425           0 :         UErrorCode internalErrorCode = U_ZERO_ERROR;
     426             :         LocalUResourceBundlePointer def(
     427           0 :                 ures_getByKeyWithFallback(actualBundle.getAlias(), "collations/default", NULL,
     428           0 :                                           &internalErrorCode));
     429             :         int32_t length;
     430           0 :         const UChar *s = ures_getString(def.getAlias(), &length, &internalErrorCode);
     431           0 :         if(U_SUCCESS(internalErrorCode) && length < UPRV_LENGTHOF(defaultType)) {
     432           0 :             u_UCharsToChars(s, defaultType, length + 1);
     433             :         } else {
     434           0 :             uprv_strcpy(defaultType, "standard");
     435             :         }
     436             :     }
     437           0 :     t->actualLocale = locale;
     438           0 :     if(uprv_strcmp(type, defaultType) != 0) {
     439           0 :         t->actualLocale.setKeywordValue("collation", type, errorCode);
     440           0 :     } else if(uprv_strcmp(locale.getName(), locale.getBaseName()) != 0) {
     441             :         // Remove the collation keyword if it was set.
     442           0 :         t->actualLocale.setKeywordValue("collation", NULL, errorCode);
     443             :     }
     444           0 :     if(U_FAILURE(errorCode)) { return NULL; }
     445             : 
     446           0 :     if(typeFallback) {
     447           0 :         errorCode = U_USING_DEFAULT_WARNING;
     448             :     }
     449           0 :     t->bundle = bundle;
     450           0 :     bundle = NULL;
     451           0 :     const CollationCacheEntry *entry = new CollationCacheEntry(validLocale, t.getAlias());
     452           0 :     if(entry == NULL) {
     453           0 :         errorCode = U_MEMORY_ALLOCATION_ERROR;
     454             :     } else {
     455           0 :         t.orphan();
     456             :     }
     457             :     // Have to add that reference that we promise.
     458           0 :     entry->addRef();
     459           0 :     return entry;
     460             : }
     461             : 
     462             : const CollationCacheEntry *
     463           0 : CollationLoader::getCacheEntry(UErrorCode &errorCode) {
     464           0 :     LocaleCacheKey<CollationCacheEntry> key(locale);
     465           0 :     const CollationCacheEntry *entry = NULL;
     466           0 :     cache->get(key, this, entry, errorCode);
     467           0 :     return entry;
     468             : }
     469             : 
     470             : const CollationCacheEntry *
     471           0 : CollationLoader::makeCacheEntryFromRoot(
     472             :         const Locale &/*loc*/,
     473             :         UErrorCode &errorCode) const {
     474           0 :     if (U_FAILURE(errorCode)) {
     475           0 :         return NULL;
     476             :     }
     477           0 :     rootEntry->addRef();
     478           0 :     return makeCacheEntry(validLocale, rootEntry, errorCode);
     479             : }
     480             : 
     481             : const CollationCacheEntry *
     482           0 : CollationLoader::makeCacheEntry(
     483             :         const Locale &loc,
     484             :         const CollationCacheEntry *entryFromCache,
     485             :         UErrorCode &errorCode) {
     486           0 :     if(U_FAILURE(errorCode) || loc == entryFromCache->validLocale) {
     487           0 :         return entryFromCache;
     488             :     }
     489           0 :     CollationCacheEntry *entry = new CollationCacheEntry(loc, entryFromCache->tailoring);
     490           0 :     if(entry == NULL) {
     491           0 :         errorCode = U_MEMORY_ALLOCATION_ERROR;
     492           0 :         entryFromCache->removeRef();
     493           0 :         return NULL;
     494             :     }
     495           0 :     entry->addRef();
     496           0 :     entryFromCache->removeRef();
     497           0 :     return entry;
     498             : }
     499             : 
     500             : U_NAMESPACE_END
     501             : 
     502             : U_NAMESPACE_USE
     503             : 
     504             : U_CAPI UCollator*
     505           0 : ucol_open(const char *loc,
     506             :           UErrorCode *status)
     507             : {
     508             :     UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN);
     509             :     UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc);
     510           0 :     UCollator *result = NULL;
     511             : 
     512           0 :     Collator *coll = Collator::createInstance(loc, *status);
     513           0 :     if(U_SUCCESS(*status)) {
     514           0 :         result = coll->toUCollator();
     515             :     }
     516             :     UTRACE_EXIT_PTR_STATUS(result, *status);
     517           0 :     return result;
     518             : }
     519             : 
     520             : 
     521             : U_CAPI int32_t U_EXPORT2
     522           0 : ucol_getDisplayName(    const    char        *objLoc,
     523             :                     const    char        *dispLoc,
     524             :                     UChar             *result,
     525             :                     int32_t         resultLength,
     526             :                     UErrorCode        *status)
     527             : {
     528           0 :     if(U_FAILURE(*status)) return -1;
     529           0 :     UnicodeString dst;
     530           0 :     if(!(result==NULL && resultLength==0)) {
     531             :         // NULL destination for pure preflighting: empty dummy string
     532             :         // otherwise, alias the destination buffer
     533           0 :         dst.setTo(result, 0, resultLength);
     534             :     }
     535           0 :     Collator::getDisplayName(Locale(objLoc), Locale(dispLoc), dst);
     536           0 :     return dst.extract(result, resultLength, *status);
     537             : }
     538             : 
     539             : U_CAPI const char* U_EXPORT2
     540           0 : ucol_getAvailable(int32_t index)
     541             : {
     542           0 :     int32_t count = 0;
     543           0 :     const Locale *loc = Collator::getAvailableLocales(count);
     544           0 :     if (loc != NULL && index < count) {
     545           0 :         return loc[index].getName();
     546             :     }
     547           0 :     return NULL;
     548             : }
     549             : 
     550             : U_CAPI int32_t U_EXPORT2
     551           0 : ucol_countAvailable()
     552             : {
     553           0 :     int32_t count = 0;
     554           0 :     Collator::getAvailableLocales(count);
     555           0 :     return count;
     556             : }
     557             : 
     558             : #if !UCONFIG_NO_SERVICE
     559             : U_CAPI UEnumeration* U_EXPORT2
     560           0 : ucol_openAvailableLocales(UErrorCode *status) {
     561             :     // This is a wrapper over Collator::getAvailableLocales()
     562           0 :     if (U_FAILURE(*status)) {
     563           0 :         return NULL;
     564             :     }
     565           0 :     StringEnumeration *s = icu::Collator::getAvailableLocales();
     566           0 :     if (s == NULL) {
     567           0 :         *status = U_MEMORY_ALLOCATION_ERROR;
     568           0 :         return NULL;
     569             :     }
     570           0 :     return uenum_openFromStringEnumeration(s, status);
     571             : }
     572             : #endif
     573             : 
     574             : // Note: KEYWORDS[0] != RESOURCE_NAME - alan
     575             : 
     576             : static const char RESOURCE_NAME[] = "collations";
     577             : 
     578             : static const char* const KEYWORDS[] = { "collation" };
     579             : 
     580             : #define KEYWORD_COUNT UPRV_LENGTHOF(KEYWORDS)
     581             : 
     582             : U_CAPI UEnumeration* U_EXPORT2
     583           0 : ucol_getKeywords(UErrorCode *status) {
     584           0 :     UEnumeration *result = NULL;
     585           0 :     if (U_SUCCESS(*status)) {
     586           0 :         return uenum_openCharStringsEnumeration(KEYWORDS, KEYWORD_COUNT, status);
     587             :     }
     588           0 :     return result;
     589             : }
     590             : 
     591             : U_CAPI UEnumeration* U_EXPORT2
     592           0 : ucol_getKeywordValues(const char *keyword, UErrorCode *status) {
     593           0 :     if (U_FAILURE(*status)) {
     594           0 :         return NULL;
     595             :     }
     596             :     // hard-coded to accept exactly one collation keyword
     597             :     // modify if additional collation keyword is added later
     598           0 :     if (keyword==NULL || uprv_strcmp(keyword, KEYWORDS[0])!=0)
     599             :     {
     600           0 :         *status = U_ILLEGAL_ARGUMENT_ERROR;
     601           0 :         return NULL;
     602             :     }
     603           0 :     return ures_getKeywordValues(U_ICUDATA_COLL, RESOURCE_NAME, status);
     604             : }
     605             : 
     606             : static const UEnumeration defaultKeywordValues = {
     607             :     NULL,
     608             :     NULL,
     609             :     ulist_close_keyword_values_iterator,
     610             :     ulist_count_keyword_values,
     611             :     uenum_unextDefault,
     612             :     ulist_next_keyword_value,
     613             :     ulist_reset_keyword_values_iterator
     614             : };
     615             : 
     616             : namespace {
     617             : 
     618             : struct KeywordsSink : public ResourceSink {
     619             : public:
     620           0 :     KeywordsSink(UErrorCode &errorCode) :
     621           0 :             values(ulist_createEmptyList(&errorCode)), hasDefault(FALSE) {}
     622             :     virtual ~KeywordsSink();
     623             : 
     624           0 :     virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
     625             :                      UErrorCode &errorCode) {
     626           0 :         if (U_FAILURE(errorCode)) { return; }
     627           0 :         ResourceTable collations = value.getTable(errorCode);
     628           0 :         for (int32_t i = 0; collations.getKeyAndValue(i, key, value); ++i) {
     629           0 :             UResType type = value.getType();
     630           0 :             if (type == URES_STRING) {
     631           0 :                 if (!hasDefault && uprv_strcmp(key, "default") == 0) {
     632           0 :                     CharString defcoll;
     633           0 :                     defcoll.appendInvariantChars(value.getUnicodeString(errorCode), errorCode);
     634           0 :                     if (U_SUCCESS(errorCode) && !defcoll.isEmpty()) {
     635           0 :                         char *ownedDefault = uprv_strdup(defcoll.data());
     636           0 :                         if (ownedDefault == NULL) {
     637           0 :                             errorCode = U_MEMORY_ALLOCATION_ERROR;
     638           0 :                             return;
     639             :                         }
     640           0 :                         ulist_removeString(values, defcoll.data());
     641           0 :                         ulist_addItemBeginList(values, ownedDefault, TRUE, &errorCode);
     642           0 :                         hasDefault = TRUE;
     643             :                     }
     644             :                 }
     645           0 :             } else if (type == URES_TABLE && uprv_strncmp(key, "private-", 8) != 0) {
     646           0 :                 if (!ulist_containsString(values, key, (int32_t)uprv_strlen(key))) {
     647           0 :                     ulist_addItemEndList(values, key, FALSE, &errorCode);
     648             :                 }
     649             :             }
     650           0 :             if (U_FAILURE(errorCode)) { return; }
     651             :         }
     652             :     }
     653             : 
     654             :     UList *values;
     655             :     UBool hasDefault;
     656             : };
     657             : 
     658           0 : KeywordsSink::~KeywordsSink() {
     659           0 :     ulist_deleteList(values);
     660           0 : }
     661             : 
     662             : }  // namespace
     663             : 
     664             : U_CAPI UEnumeration* U_EXPORT2
     665           0 : ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
     666             :                                UBool /*commonlyUsed*/, UErrorCode* status) {
     667             :     // Note: The parameter commonlyUsed is not used.
     668             :     // The switch is in the method signature for consistency
     669             :     // with other locale services.
     670             : 
     671             :     // Read available collation values from collation bundles.
     672           0 :     LocalUResourceBundlePointer bundle(ures_open(U_ICUDATA_COLL, locale, status));
     673           0 :     KeywordsSink sink(*status);
     674           0 :     ures_getAllItemsWithFallback(bundle.getAlias(), RESOURCE_NAME, sink, *status);
     675           0 :     if (U_FAILURE(*status)) { return NULL; }
     676             : 
     677           0 :     UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
     678           0 :     if (en == NULL) {
     679           0 :         *status = U_MEMORY_ALLOCATION_ERROR;
     680           0 :         return NULL;
     681             :     }
     682           0 :     memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
     683           0 :     ulist_resetList(sink.values);  // Initialize the iterator.
     684           0 :     en->context = sink.values;
     685           0 :     sink.values = NULL;  // Avoid deletion in the sink destructor.
     686           0 :     return en;
     687             : }
     688             : 
     689             : U_CAPI int32_t U_EXPORT2
     690           0 : ucol_getFunctionalEquivalent(char* result, int32_t resultCapacity,
     691             :                              const char* keyword, const char* locale,
     692             :                              UBool* isAvailable, UErrorCode* status)
     693             : {
     694             :     // N.B.: Resource name is "collations" but keyword is "collation"
     695             :     return ures_getFunctionalEquivalent(result, resultCapacity, U_ICUDATA_COLL,
     696             :         "collations", keyword, locale,
     697           0 :         isAvailable, TRUE, status);
     698             : }
     699             : 
     700             : #endif /* #if !UCONFIG_NO_COLLATION */

Generated by: LCOV version 1.13