Home | History | Annotate | Download | only in i18n
      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-2014, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  ******************************************************************************
      8  */
      9 
     10 /**
     11  * File coll.cpp
     12  *
     13  * Created by: Helena Shih
     14  *
     15  * Modification History:
     16  *
     17  *  Date        Name        Description
     18  *  2/5/97      aliu        Modified createDefault to load collation data from
     19  *                          binary files when possible.  Added related methods
     20  *                          createCollationFromFile, chopLocale, createPathName.
     21  *  2/11/97     aliu        Added methods addToCache, findInCache, which implement
     22  *                          a Collation cache.  Modified createDefault to look in
     23  *                          cache first, and also to store newly created Collation
     24  *                          objects in the cache.  Modified to not use gLocPath.
     25  *  2/12/97     aliu        Modified to create objects from RuleBasedCollator cache.
     26  *                          Moved cache out of Collation class.
     27  *  2/13/97     aliu        Moved several methods out of this class and into
     28  *                          RuleBasedCollator, with modifications.  Modified
     29  *                          createDefault() to call new RuleBasedCollator(Locale&)
     30  *                          constructor.  General clean up and documentation.
     31  *  2/20/97     helena      Added clone, operator==, operator!=, operator=, and copy
     32  *                          constructor.
     33  * 05/06/97     helena      Added memory allocation error detection.
     34  * 05/08/97     helena      Added createInstance().
     35  *  6/20/97     helena      Java class name change.
     36  * 04/23/99     stephen     Removed EDecompositionMode, merged with
     37  *                          Normalizer::EMode
     38  * 11/23/9      srl         Inlining of some critical functions
     39  * 01/29/01     synwee      Modified into a C++ wrapper calling C APIs (ucol.h)
     40  * 2012-2014    markus      Rewritten in C++ again.
     41  */
     42 
     43 #include "utypeinfo.h"  // for 'typeid' to work
     44 
     45 #include "unicode/utypes.h"
     46 
     47 #if !UCONFIG_NO_COLLATION
     48 
     49 #include "unicode/coll.h"
     50 #include "unicode/tblcoll.h"
     51 #include "collationdata.h"
     52 #include "collationroot.h"
     53 #include "collationtailoring.h"
     54 #include "ucol_imp.h"
     55 #include "cstring.h"
     56 #include "cmemory.h"
     57 #include "umutex.h"
     58 #include "servloc.h"
     59 #include "uassert.h"
     60 #include "ustrenum.h"
     61 #include "uresimp.h"
     62 #include "ucln_in.h"
     63 
     64 static icu::Locale* availableLocaleList = NULL;
     65 static int32_t  availableLocaleListCount;
     66 #if !UCONFIG_NO_SERVICE
     67 static icu::ICULocaleService* gService = NULL;
     68 static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
     69 #endif
     70 static icu::UInitOnce gAvailableLocaleListInitOnce;
     71 
     72 /**
     73  * Release all static memory held by collator.
     74  */
     75 U_CDECL_BEGIN
     76 static UBool U_CALLCONV collator_cleanup(void) {
     77 #if !UCONFIG_NO_SERVICE
     78     if (gService) {
     79         delete gService;
     80         gService = NULL;
     81     }
     82     gServiceInitOnce.reset();
     83 #endif
     84     if (availableLocaleList) {
     85         delete []availableLocaleList;
     86         availableLocaleList = NULL;
     87     }
     88     availableLocaleListCount = 0;
     89     gAvailableLocaleListInitOnce.reset();
     90     return TRUE;
     91 }
     92 
     93 U_CDECL_END
     94 
     95 U_NAMESPACE_BEGIN
     96 
     97 #if !UCONFIG_NO_SERVICE
     98 
     99 // ------------------------------------------
    100 //
    101 // Registration
    102 //
    103 
    104 //-------------------------------------------
    105 
    106 CollatorFactory::~CollatorFactory() {}
    107 
    108 //-------------------------------------------
    109 
    110 UBool
    111 CollatorFactory::visible(void) const {
    112     return TRUE;
    113 }
    114 
    115 //-------------------------------------------
    116 
    117 UnicodeString&
    118 CollatorFactory::getDisplayName(const Locale& objectLocale,
    119                                 const Locale& displayLocale,
    120                                 UnicodeString& result)
    121 {
    122   return objectLocale.getDisplayName(displayLocale, result);
    123 }
    124 
    125 // -------------------------------------
    126 
    127 class ICUCollatorFactory : public ICUResourceBundleFactory {
    128  public:
    129     ICUCollatorFactory() : ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
    130     virtual ~ICUCollatorFactory();
    131  protected:
    132     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
    133 };
    134 
    135 ICUCollatorFactory::~ICUCollatorFactory() {}
    136 
    137 UObject*
    138 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
    139     if (handlesKey(key, status)) {
    140         const LocaleKey& lkey = (const LocaleKey&)key;
    141         Locale loc;
    142         // make sure the requested locale is correct
    143         // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
    144         // but for ICU rb resources we use the actual one since it will fallback again
    145         lkey.canonicalLocale(loc);
    146 
    147         return Collator::makeInstance(loc, status);
    148     }
    149     return NULL;
    150 }
    151 
    152 // -------------------------------------
    153 
    154 class ICUCollatorService : public ICULocaleService {
    155 public:
    156     ICUCollatorService()
    157         : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
    158     {
    159         UErrorCode status = U_ZERO_ERROR;
    160         registerFactory(new ICUCollatorFactory(), status);
    161     }
    162 
    163     virtual ~ICUCollatorService();
    164 
    165     virtual UObject* cloneInstance(UObject* instance) const {
    166         return ((Collator*)instance)->clone();
    167     }
    168 
    169     virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
    170         LocaleKey& lkey = (LocaleKey&)key;
    171         if (actualID) {
    172             // Ugly Hack Alert! We return an empty actualID to signal
    173             // to callers that this is a default object, not a "real"
    174             // service-created object. (TODO remove in 3.0) [aliu]
    175             actualID->truncate(0);
    176         }
    177         Locale loc("");
    178         lkey.canonicalLocale(loc);
    179         return Collator::makeInstance(loc, status);
    180     }
    181 
    182     virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
    183         UnicodeString ar;
    184         if (actualReturn == NULL) {
    185             actualReturn = &ar;
    186         }
    187         return (Collator*)ICULocaleService::getKey(key, actualReturn, status);
    188     }
    189 
    190     virtual UBool isDefault() const {
    191         return countFactories() == 1;
    192     }
    193 };
    194 
    195 ICUCollatorService::~ICUCollatorService() {}
    196 
    197 // -------------------------------------
    198 
    199 static void U_CALLCONV initService() {
    200     gService = new ICUCollatorService();
    201     ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
    202 }
    203 
    204 
    205 static ICULocaleService*
    206 getService(void)
    207 {
    208     umtx_initOnce(gServiceInitOnce, &initService);
    209     return gService;
    210 }
    211 
    212 // -------------------------------------
    213 
    214 static inline UBool
    215 hasService(void)
    216 {
    217     UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL);
    218     return retVal;
    219 }
    220 
    221 #endif /* UCONFIG_NO_SERVICE */
    222 
    223 static void U_CALLCONV
    224 initAvailableLocaleList(UErrorCode &status) {
    225     U_ASSERT(availableLocaleListCount == 0);
    226     U_ASSERT(availableLocaleList == NULL);
    227     // for now, there is a hardcoded list, so just walk through that list and set it up.
    228     UResourceBundle *index = NULL;
    229     UResourceBundle installed;
    230     int32_t i = 0;
    231 
    232     ures_initStackObject(&installed);
    233     index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
    234     ures_getByKey(index, "InstalledLocales", &installed, &status);
    235 
    236     if(U_SUCCESS(status)) {
    237         availableLocaleListCount = ures_getSize(&installed);
    238         availableLocaleList = new Locale[availableLocaleListCount];
    239 
    240         if (availableLocaleList != NULL) {
    241             ures_resetIterator(&installed);
    242             while(ures_hasNext(&installed)) {
    243                 const char *tempKey = NULL;
    244                 ures_getNextString(&installed, NULL, &tempKey, &status);
    245                 availableLocaleList[i++] = Locale(tempKey);
    246             }
    247         }
    248         U_ASSERT(availableLocaleListCount == i);
    249         ures_close(&installed);
    250     }
    251     ures_close(index);
    252     ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
    253 }
    254 
    255 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
    256     umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status);
    257     return U_SUCCESS(status);
    258 }
    259 
    260 
    261 // Collator public methods -----------------------------------------------
    262 
    263 namespace {
    264 
    265 static const struct {
    266     const char *name;
    267     UColAttribute attr;
    268 } collAttributes[] = {
    269     { "colStrength", UCOL_STRENGTH },
    270     { "colBackwards", UCOL_FRENCH_COLLATION },
    271     { "colCaseLevel", UCOL_CASE_LEVEL },
    272     { "colCaseFirst", UCOL_CASE_FIRST },
    273     { "colAlternate", UCOL_ALTERNATE_HANDLING },
    274     { "colNormalization", UCOL_NORMALIZATION_MODE },
    275     { "colNumeric", UCOL_NUMERIC_COLLATION }
    276 };
    277 
    278 static const struct {
    279     const char *name;
    280     UColAttributeValue value;
    281 } collAttributeValues[] = {
    282     { "primary", UCOL_PRIMARY },
    283     { "secondary", UCOL_SECONDARY },
    284     { "tertiary", UCOL_TERTIARY },
    285     { "quaternary", UCOL_QUATERNARY },
    286     // Note: Not supporting typo "quarternary" because it was never supported in locale IDs.
    287     { "identical", UCOL_IDENTICAL },
    288     { "no", UCOL_OFF },
    289     { "yes", UCOL_ON },
    290     { "shifted", UCOL_SHIFTED },
    291     { "non-ignorable", UCOL_NON_IGNORABLE },
    292     { "lower", UCOL_LOWER_FIRST },
    293     { "upper", UCOL_UPPER_FIRST }
    294 };
    295 
    296 static const char *collReorderCodes[UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST] = {
    297     "space", "punct", "symbol", "currency", "digit"
    298 };
    299 
    300 int32_t getReorderCode(const char *s) {
    301     for (int32_t i = 0; i < UPRV_LENGTHOF(collReorderCodes); ++i) {
    302         if (uprv_stricmp(s, collReorderCodes[i]) == 0) {
    303             return UCOL_REORDER_CODE_FIRST + i;
    304         }
    305     }
    306     // Not supporting "others" = UCOL_REORDER_CODE_OTHERS
    307     // as a synonym for Zzzz = USCRIPT_UNKNOWN for now:
    308     // Avoid introducing synonyms/aliases.
    309     return -1;
    310 }
    311 
    312 /**
    313  * Sets collation attributes according to locale keywords. See
    314  * http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings
    315  *
    316  * Using "alias" keywords and values where defined:
    317  * http://www.unicode.org/reports/tr35/tr35.html#Old_Locale_Extension_Syntax
    318  * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
    319  */
    320 void setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) {
    321     if (U_FAILURE(errorCode)) {
    322         return;
    323     }
    324     if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) {
    325         // No keywords.
    326         return;
    327     }
    328     char value[1024];  // The reordering value could be long.
    329     // Check for collation keywords that were already deprecated
    330     // before any were supported in createInstance() (except for "collation").
    331     int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, UPRV_LENGTHOF(value), errorCode);
    332     if (U_FAILURE(errorCode)) {
    333         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    334         return;
    335     }
    336     if (length != 0) {
    337         errorCode = U_UNSUPPORTED_ERROR;
    338         return;
    339     }
    340     length = loc.getKeywordValue("variableTop", value, UPRV_LENGTHOF(value), errorCode);
    341     if (U_FAILURE(errorCode)) {
    342         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    343         return;
    344     }
    345     if (length != 0) {
    346         errorCode = U_UNSUPPORTED_ERROR;
    347         return;
    348     }
    349     // Parse known collation keywords, ignore others.
    350     if (errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    351         errorCode = U_ZERO_ERROR;
    352     }
    353     for (int32_t i = 0; i < UPRV_LENGTHOF(collAttributes); ++i) {
    354         length = loc.getKeywordValue(collAttributes[i].name, value, UPRV_LENGTHOF(value), errorCode);
    355         if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    356             errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    357             return;
    358         }
    359         if (length == 0) { continue; }
    360         for (int32_t j = 0;; ++j) {
    361             if (j == UPRV_LENGTHOF(collAttributeValues)) {
    362                 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    363                 return;
    364             }
    365             if (uprv_stricmp(value, collAttributeValues[j].name) == 0) {
    366                 coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode);
    367                 break;
    368             }
    369         }
    370     }
    371     length = loc.getKeywordValue("colReorder", value, UPRV_LENGTHOF(value), errorCode);
    372     if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    373         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    374         return;
    375     }
    376     if (length != 0) {
    377         int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST];
    378         int32_t codesLength = 0;
    379         char *scriptName = value;
    380         for (;;) {
    381             if (codesLength == UPRV_LENGTHOF(codes)) {
    382                 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    383                 return;
    384             }
    385             char *limit = scriptName;
    386             char c;
    387             while ((c = *limit) != 0 && c != '-') { ++limit; }
    388             *limit = 0;
    389             int32_t code;
    390             if ((limit - scriptName) == 4) {
    391                 // Strict parsing, accept only 4-letter script codes, not long names.
    392                 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName);
    393             } else {
    394                 code = getReorderCode(scriptName);
    395             }
    396             if (code < 0) {
    397                 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    398                 return;
    399             }
    400             codes[codesLength++] = code;
    401             if (c == 0) { break; }
    402             scriptName = limit + 1;
    403         }
    404         coll.setReorderCodes(codes, codesLength, errorCode);
    405     }
    406     length = loc.getKeywordValue("kv", value, UPRV_LENGTHOF(value), errorCode);
    407     if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    408         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    409         return;
    410     }
    411     if (length != 0) {
    412         int32_t code = getReorderCode(value);
    413         if (code < 0) {
    414             errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    415             return;
    416         }
    417         coll.setMaxVariable((UColReorderCode)code, errorCode);
    418     }
    419     if (U_FAILURE(errorCode)) {
    420         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    421     }
    422 }
    423 
    424 }  // namespace
    425 
    426 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
    427 {
    428     return createInstance(Locale::getDefault(), success);
    429 }
    430 
    431 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
    432                                    UErrorCode& status)
    433 {
    434     if (U_FAILURE(status))
    435         return 0;
    436     if (desiredLocale.isBogus()) {
    437         // Locale constructed from malformed locale ID or language tag.
    438         status = U_ILLEGAL_ARGUMENT_ERROR;
    439         return NULL;
    440     }
    441 
    442     Collator* coll;
    443 #if !UCONFIG_NO_SERVICE
    444     if (hasService()) {
    445         Locale actualLoc;
    446         coll = (Collator*)gService->get(desiredLocale, &actualLoc, status);
    447     } else
    448 #endif
    449     {
    450         coll = makeInstance(desiredLocale, status);
    451     }
    452     setAttributesFromKeywords(desiredLocale, *coll, status);
    453     if (U_FAILURE(status)) {
    454         delete coll;
    455         return NULL;
    456     }
    457     return coll;
    458 }
    459 
    460 
    461 Collator* Collator::makeInstance(const Locale&  desiredLocale, UErrorCode& status) {
    462     const CollationCacheEntry *entry = CollationLoader::loadTailoring(desiredLocale, status);
    463     if (U_SUCCESS(status)) {
    464         Collator *result = new RuleBasedCollator(entry);
    465         if (result != NULL) {
    466             // Both the unified cache's get() and the RBC constructor
    467             // did addRef(). Undo one of them.
    468             entry->removeRef();
    469             return result;
    470         }
    471         status = U_MEMORY_ALLOCATION_ERROR;
    472     }
    473     if (entry != NULL) {
    474         // Undo the addRef() from the cache.get().
    475         entry->removeRef();
    476     }
    477     return NULL;
    478 }
    479 
    480 Collator *
    481 Collator::safeClone() const {
    482     return clone();
    483 }
    484 
    485 // implement deprecated, previously abstract method
    486 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
    487                                     const UnicodeString& target) const
    488 {
    489     UErrorCode ec = U_ZERO_ERROR;
    490     return (EComparisonResult)compare(source, target, ec);
    491 }
    492 
    493 // implement deprecated, previously abstract method
    494 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
    495                                     const UnicodeString& target,
    496                                     int32_t length) const
    497 {
    498     UErrorCode ec = U_ZERO_ERROR;
    499     return (EComparisonResult)compare(source, target, length, ec);
    500 }
    501 
    502 // implement deprecated, previously abstract method
    503 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
    504                                     const UChar* target, int32_t targetLength)
    505                                     const
    506 {
    507     UErrorCode ec = U_ZERO_ERROR;
    508     return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
    509 }
    510 
    511 UCollationResult Collator::compare(UCharIterator &/*sIter*/,
    512                                    UCharIterator &/*tIter*/,
    513                                    UErrorCode &status) const {
    514     if(U_SUCCESS(status)) {
    515         // Not implemented in the base class.
    516         status = U_UNSUPPORTED_ERROR;
    517     }
    518     return UCOL_EQUAL;
    519 }
    520 
    521 UCollationResult Collator::compareUTF8(const StringPiece &source,
    522                                        const StringPiece &target,
    523                                        UErrorCode &status) const {
    524     if(U_FAILURE(status)) {
    525         return UCOL_EQUAL;
    526     }
    527     UCharIterator sIter, tIter;
    528     uiter_setUTF8(&sIter, source.data(), source.length());
    529     uiter_setUTF8(&tIter, target.data(), target.length());
    530     return compare(sIter, tIter, status);
    531 }
    532 
    533 UBool Collator::equals(const UnicodeString& source,
    534                        const UnicodeString& target) const
    535 {
    536     UErrorCode ec = U_ZERO_ERROR;
    537     return (compare(source, target, ec) == UCOL_EQUAL);
    538 }
    539 
    540 UBool Collator::greaterOrEqual(const UnicodeString& source,
    541                                const UnicodeString& target) const
    542 {
    543     UErrorCode ec = U_ZERO_ERROR;
    544     return (compare(source, target, ec) != UCOL_LESS);
    545 }
    546 
    547 UBool Collator::greater(const UnicodeString& source,
    548                         const UnicodeString& target) const
    549 {
    550     UErrorCode ec = U_ZERO_ERROR;
    551     return (compare(source, target, ec) == UCOL_GREATER);
    552 }
    553 
    554 // this API  ignores registered collators, since it returns an
    555 // array of indefinite lifetime
    556 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
    557 {
    558     UErrorCode status = U_ZERO_ERROR;
    559     Locale *result = NULL;
    560     count = 0;
    561     if (isAvailableLocaleListInitialized(status))
    562     {
    563         result = availableLocaleList;
    564         count = availableLocaleListCount;
    565     }
    566     return result;
    567 }
    568 
    569 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
    570                                         const Locale& displayLocale,
    571                                         UnicodeString& name)
    572 {
    573 #if !UCONFIG_NO_SERVICE
    574     if (hasService()) {
    575         UnicodeString locNameStr;
    576         LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
    577         return gService->getDisplayName(locNameStr, name, displayLocale);
    578     }
    579 #endif
    580     return objectLocale.getDisplayName(displayLocale, name);
    581 }
    582 
    583 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
    584                                         UnicodeString& name)
    585 {
    586     return getDisplayName(objectLocale, Locale::getDefault(), name);
    587 }
    588 
    589 /* This is useless information */
    590 /*void Collator::getVersion(UVersionInfo versionInfo) const
    591 {
    592   if (versionInfo!=NULL)
    593     uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
    594 }
    595 */
    596 
    597 // UCollator protected constructor destructor ----------------------------
    598 
    599 /**
    600 * Default constructor.
    601 * Constructor is different from the old default Collator constructor.
    602 * The task for determing the default collation strength and normalization mode
    603 * is left to the child class.
    604 */
    605 Collator::Collator()
    606 : UObject()
    607 {
    608 }
    609 
    610 /**
    611 * Constructor.
    612 * Empty constructor, does not handle the arguments.
    613 * This constructor is done for backward compatibility with 1.7 and 1.8.
    614 * The task for handling the argument collation strength and normalization
    615 * mode is left to the child class.
    616 * @param collationStrength collation strength
    617 * @param decompositionMode
    618 * @deprecated 2.4 use the default constructor instead
    619 */
    620 Collator::Collator(UCollationStrength, UNormalizationMode )
    621 : UObject()
    622 {
    623 }
    624 
    625 Collator::~Collator()
    626 {
    627 }
    628 
    629 Collator::Collator(const Collator &other)
    630     : UObject(other)
    631 {
    632 }
    633 
    634 UBool Collator::operator==(const Collator& other) const
    635 {
    636     // Subclasses: Call this method and then add more specific checks.
    637     return typeid(*this) == typeid(other);
    638 }
    639 
    640 UBool Collator::operator!=(const Collator& other) const
    641 {
    642     return (UBool)!(*this == other);
    643 }
    644 
    645 int32_t U_EXPORT2 Collator::getBound(const uint8_t       *source,
    646                            int32_t             sourceLength,
    647                            UColBoundMode       boundType,
    648                            uint32_t            noOfLevels,
    649                            uint8_t             *result,
    650                            int32_t             resultLength,
    651                            UErrorCode          &status)
    652 {
    653     return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
    654 }
    655 
    656 void
    657 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
    658 }
    659 
    660 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
    661 {
    662     if(U_FAILURE(status)) {
    663         return NULL;
    664     }
    665     // everything can be changed
    666     return new UnicodeSet(0, 0x10FFFF);
    667 }
    668 
    669 // -------------------------------------
    670 
    671 #if !UCONFIG_NO_SERVICE
    672 URegistryKey U_EXPORT2
    673 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
    674 {
    675     if (U_SUCCESS(status)) {
    676         // Set the collator locales while registering so that createInstance()
    677         // need not guess whether the collator's locales are already set properly
    678         // (as they are by the data loader).
    679         toAdopt->setLocales(locale, locale, locale);
    680         return getService()->registerInstance(toAdopt, locale, status);
    681     }
    682     return NULL;
    683 }
    684 
    685 // -------------------------------------
    686 
    687 class CFactory : public LocaleKeyFactory {
    688 private:
    689     CollatorFactory* _delegate;
    690     Hashtable* _ids;
    691 
    692 public:
    693     CFactory(CollatorFactory* delegate, UErrorCode& status)
    694         : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
    695         , _delegate(delegate)
    696         , _ids(NULL)
    697     {
    698         if (U_SUCCESS(status)) {
    699             int32_t count = 0;
    700             _ids = new Hashtable(status);
    701             if (_ids) {
    702                 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
    703                 for (int i = 0; i < count; ++i) {
    704                     _ids->put(idlist[i], (void*)this, status);
    705                     if (U_FAILURE(status)) {
    706                         delete _ids;
    707                         _ids = NULL;
    708                         return;
    709                     }
    710                 }
    711             } else {
    712                 status = U_MEMORY_ALLOCATION_ERROR;
    713             }
    714         }
    715     }
    716 
    717     virtual ~CFactory();
    718 
    719     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
    720 
    721 protected:
    722     virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
    723     {
    724         if (U_SUCCESS(status)) {
    725             return _ids;
    726         }
    727         return NULL;
    728     }
    729 
    730     virtual UnicodeString&
    731         getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
    732 };
    733 
    734 CFactory::~CFactory()
    735 {
    736     delete _delegate;
    737     delete _ids;
    738 }
    739 
    740 UObject*
    741 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
    742 {
    743     if (handlesKey(key, status)) {
    744         const LocaleKey& lkey = (const LocaleKey&)key;
    745         Locale validLoc;
    746         lkey.currentLocale(validLoc);
    747         return _delegate->createCollator(validLoc);
    748     }
    749     return NULL;
    750 }
    751 
    752 UnicodeString&
    753 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
    754 {
    755     if ((_coverage & 0x1) == 0) {
    756         UErrorCode status = U_ZERO_ERROR;
    757         const Hashtable* ids = getSupportedIDs(status);
    758         if (ids && (ids->get(id) != NULL)) {
    759             Locale loc;
    760             LocaleUtility::initLocaleFromName(id, loc);
    761             return _delegate->getDisplayName(loc, locale, result);
    762         }
    763     }
    764     result.setToBogus();
    765     return result;
    766 }
    767 
    768 URegistryKey U_EXPORT2
    769 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
    770 {
    771     if (U_SUCCESS(status)) {
    772         CFactory* f = new CFactory(toAdopt, status);
    773         if (f) {
    774             return getService()->registerFactory(f, status);
    775         }
    776         status = U_MEMORY_ALLOCATION_ERROR;
    777     }
    778     return NULL;
    779 }
    780 
    781 // -------------------------------------
    782 
    783 UBool U_EXPORT2
    784 Collator::unregister(URegistryKey key, UErrorCode& status)
    785 {
    786     if (U_SUCCESS(status)) {
    787         if (hasService()) {
    788             return gService->unregister(key, status);
    789         }
    790         status = U_ILLEGAL_ARGUMENT_ERROR;
    791     }
    792     return FALSE;
    793 }
    794 #endif /* UCONFIG_NO_SERVICE */
    795 
    796 class CollationLocaleListEnumeration : public StringEnumeration {
    797 private:
    798     int32_t index;
    799 public:
    800     static UClassID U_EXPORT2 getStaticClassID(void);
    801     virtual UClassID getDynamicClassID(void) const;
    802 public:
    803     CollationLocaleListEnumeration()
    804         : index(0)
    805     {
    806         // The global variables should already be initialized.
    807         //isAvailableLocaleListInitialized(status);
    808     }
    809 
    810     virtual ~CollationLocaleListEnumeration();
    811 
    812     virtual StringEnumeration * clone() const
    813     {
    814         CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
    815         if (result) {
    816             result->index = index;
    817         }
    818         return result;
    819     }
    820 
    821     virtual int32_t count(UErrorCode &/*status*/) const {
    822         return availableLocaleListCount;
    823     }
    824 
    825     virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
    826         const char* result;
    827         if(index < availableLocaleListCount) {
    828             result = availableLocaleList[index++].getName();
    829             if(resultLength != NULL) {
    830                 *resultLength = (int32_t)uprv_strlen(result);
    831             }
    832         } else {
    833             if(resultLength != NULL) {
    834                 *resultLength = 0;
    835             }
    836             result = NULL;
    837         }
    838         return result;
    839     }
    840 
    841     virtual const UnicodeString* snext(UErrorCode& status) {
    842         int32_t resultLength = 0;
    843         const char *s = next(&resultLength, status);
    844         return setChars(s, resultLength, status);
    845     }
    846 
    847     virtual void reset(UErrorCode& /*status*/) {
    848         index = 0;
    849     }
    850 };
    851 
    852 CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {}
    853 
    854 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
    855 
    856 
    857 // -------------------------------------
    858 
    859 StringEnumeration* U_EXPORT2
    860 Collator::getAvailableLocales(void)
    861 {
    862 #if !UCONFIG_NO_SERVICE
    863     if (hasService()) {
    864         return getService()->getAvailableLocales();
    865     }
    866 #endif /* UCONFIG_NO_SERVICE */
    867     UErrorCode status = U_ZERO_ERROR;
    868     if (isAvailableLocaleListInitialized(status)) {
    869         return new CollationLocaleListEnumeration();
    870     }
    871     return NULL;
    872 }
    873 
    874 StringEnumeration* U_EXPORT2
    875 Collator::getKeywords(UErrorCode& status) {
    876     return UStringEnumeration::fromUEnumeration(
    877             ucol_getKeywords(&status), status);
    878 }
    879 
    880 StringEnumeration* U_EXPORT2
    881 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
    882     return UStringEnumeration::fromUEnumeration(
    883             ucol_getKeywordValues(keyword, &status), status);
    884 }
    885 
    886 StringEnumeration* U_EXPORT2
    887 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
    888                                     UBool commonlyUsed, UErrorCode& status) {
    889     return UStringEnumeration::fromUEnumeration(
    890             ucol_getKeywordValuesForLocale(
    891                     key, locale.getName(), commonlyUsed, &status),
    892             status);
    893 }
    894 
    895 Locale U_EXPORT2
    896 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
    897                                   UBool& isAvailable, UErrorCode& status) {
    898     // This is a wrapper over ucol_getFunctionalEquivalent
    899     char loc[ULOC_FULLNAME_CAPACITY];
    900     /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
    901                     keyword, locale.getName(), &isAvailable, &status);
    902     if (U_FAILURE(status)) {
    903         *loc = 0; // root
    904     }
    905     return Locale::createFromName(loc);
    906 }
    907 
    908 Collator::ECollationStrength
    909 Collator::getStrength(void) const {
    910     UErrorCode intStatus = U_ZERO_ERROR;
    911     return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus);
    912 }
    913 
    914 void
    915 Collator::setStrength(ECollationStrength newStrength) {
    916     UErrorCode intStatus = U_ZERO_ERROR;
    917     setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus);
    918 }
    919 
    920 Collator &
    921 Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) {
    922     if (U_SUCCESS(errorCode)) {
    923         errorCode = U_UNSUPPORTED_ERROR;
    924     }
    925     return *this;
    926 }
    927 
    928 UColReorderCode
    929 Collator::getMaxVariable() const {
    930     return UCOL_REORDER_CODE_PUNCTUATION;
    931 }
    932 
    933 int32_t
    934 Collator::getReorderCodes(int32_t* /* dest*/,
    935                           int32_t /* destCapacity*/,
    936                           UErrorCode& status) const
    937 {
    938     if (U_SUCCESS(status)) {
    939         status = U_UNSUPPORTED_ERROR;
    940     }
    941     return 0;
    942 }
    943 
    944 void
    945 Collator::setReorderCodes(const int32_t* /* reorderCodes */,
    946                           int32_t /* reorderCodesLength */,
    947                           UErrorCode& status)
    948 {
    949     if (U_SUCCESS(status)) {
    950         status = U_UNSUPPORTED_ERROR;
    951     }
    952 }
    953 
    954 int32_t
    955 Collator::getEquivalentReorderCodes(int32_t reorderCode,
    956                                     int32_t *dest, int32_t capacity,
    957                                     UErrorCode &errorCode) {
    958     if(U_FAILURE(errorCode)) { return 0; }
    959     if(capacity < 0 || (dest == NULL && capacity > 0)) {
    960         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    961         return 0;
    962     }
    963     const CollationData *baseData = CollationRoot::getData(errorCode);
    964     if(U_FAILURE(errorCode)) { return 0; }
    965     return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode);
    966 }
    967 
    968 int32_t
    969 Collator::internalGetShortDefinitionString(const char * /*locale*/,
    970                                                              char * /*buffer*/,
    971                                                              int32_t /*capacity*/,
    972                                                              UErrorCode &status) const {
    973   if(U_SUCCESS(status)) {
    974     status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */
    975   }
    976   return 0;
    977 }
    978 
    979 UCollationResult
    980 Collator::internalCompareUTF8(const char *left, int32_t leftLength,
    981                               const char *right, int32_t rightLength,
    982                               UErrorCode &errorCode) const {
    983     if(U_FAILURE(errorCode)) { return UCOL_EQUAL; }
    984     if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) {
    985         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    986         return UCOL_EQUAL;
    987     }
    988     return compareUTF8(
    989             StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength),
    990             StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength),
    991             errorCode);
    992 }
    993 
    994 int32_t
    995 Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2],
    996                                   uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const {
    997     if (U_SUCCESS(errorCode)) {
    998         errorCode = U_UNSUPPORTED_ERROR;
    999     }
   1000     return 0;
   1001 }
   1002 
   1003 // UCollator private data members ----------------------------------------
   1004 
   1005 /* This is useless information */
   1006 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
   1007 
   1008 // -------------------------------------
   1009 
   1010 U_NAMESPACE_END
   1011 
   1012 #endif /* #if !UCONFIG_NO_COLLATION */
   1013 
   1014 /* eof */
   1015