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