Home | History | Annotate | Download | only in i18n
      1 /*
      2  ******************************************************************************
      3  * Copyright (C) 1996-2014, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ******************************************************************************
      6  */
      7 
      8 /**
      9  * File coll.cpp
     10  *
     11  * Created by: Helena Shih
     12  *
     13  * Modification History:
     14  *
     15  *  Date        Name        Description
     16  *  2/5/97      aliu        Modified createDefault to load collation data from
     17  *                          binary files when possible.  Added related methods
     18  *                          createCollationFromFile, chopLocale, createPathName.
     19  *  2/11/97     aliu        Added methods addToCache, findInCache, which implement
     20  *                          a Collation cache.  Modified createDefault to look in
     21  *                          cache first, and also to store newly created Collation
     22  *                          objects in the cache.  Modified to not use gLocPath.
     23  *  2/12/97     aliu        Modified to create objects from RuleBasedCollator cache.
     24  *                          Moved cache out of Collation class.
     25  *  2/13/97     aliu        Moved several methods out of this class and into
     26  *                          RuleBasedCollator, with modifications.  Modified
     27  *                          createDefault() to call new RuleBasedCollator(Locale&)
     28  *                          constructor.  General clean up and documentation.
     29  *  2/20/97     helena      Added clone, operator==, operator!=, operator=, and copy
     30  *                          constructor.
     31  * 05/06/97     helena      Added memory allocation error detection.
     32  * 05/08/97     helena      Added createInstance().
     33  *  6/20/97     helena      Java class name change.
     34  * 04/23/99     stephen     Removed EDecompositionMode, merged with
     35  *                          Normalizer::EMode
     36  * 11/23/9      srl         Inlining of some critical functions
     37  * 01/29/01     synwee      Modified into a C++ wrapper calling C APIs (ucol.h)
     38  * 2012-2014    markus      Rewritten in C++ again.
     39  */
     40 
     41 #include "utypeinfo.h"  // for 'typeid' to work
     42 
     43 #include "unicode/utypes.h"
     44 
     45 #if !UCONFIG_NO_COLLATION
     46 
     47 #include "unicode/coll.h"
     48 #include "unicode/tblcoll.h"
     49 #include "collationdata.h"
     50 #include "collationroot.h"
     51 #include "collationtailoring.h"
     52 #include "ucol_imp.h"
     53 #include "cstring.h"
     54 #include "cmemory.h"
     55 #include "umutex.h"
     56 #include "servloc.h"
     57 #include "uassert.h"
     58 #include "ustrenum.h"
     59 #include "uresimp.h"
     60 #include "ucln_in.h"
     61 
     62 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
     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 < LENGTHOF(collReorderCodes); ++i) {
    300         if (uprv_stricmp(s, collReorderCodes[i]) == 0) {
    301             return UCOL_REORDER_CODE_FIRST + i;
    302         }
    303     }
    304     return -1;
    305 }
    306 
    307 /**
    308  * Sets collation attributes according to locale keywords. See
    309  * http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings
    310  *
    311  * Using "alias" keywords and values where defined:
    312  * http://www.unicode.org/reports/tr35/tr35.html#Old_Locale_Extension_Syntax
    313  * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
    314  */
    315 void setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) {
    316     if (U_FAILURE(errorCode)) {
    317         return;
    318     }
    319     if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) {
    320         // No keywords.
    321         return;
    322     }
    323     char value[1024];  // The reordering value could be long.
    324     // Check for collation keywords that were already deprecated
    325     // before any were supported in createInstance() (except for "collation").
    326     int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, LENGTHOF(value), errorCode);
    327     if (U_FAILURE(errorCode)) {
    328         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    329         return;
    330     }
    331     if (length != 0) {
    332         errorCode = U_UNSUPPORTED_ERROR;
    333         return;
    334     }
    335     length = loc.getKeywordValue("variableTop", value, LENGTHOF(value), errorCode);
    336     if (U_FAILURE(errorCode)) {
    337         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    338         return;
    339     }
    340     if (length != 0) {
    341         errorCode = U_UNSUPPORTED_ERROR;
    342         return;
    343     }
    344     // Parse known collation keywords, ignore others.
    345     if (errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    346         errorCode = U_ZERO_ERROR;
    347     }
    348     for (int32_t i = 0; i < LENGTHOF(collAttributes); ++i) {
    349         length = loc.getKeywordValue(collAttributes[i].name, value, LENGTHOF(value), errorCode);
    350         if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    351             errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    352             return;
    353         }
    354         if (length == 0) { continue; }
    355         for (int32_t j = 0;; ++j) {
    356             if (j == LENGTHOF(collAttributeValues)) {
    357                 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    358                 return;
    359             }
    360             if (uprv_stricmp(value, collAttributeValues[j].name) == 0) {
    361                 coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode);
    362                 break;
    363             }
    364         }
    365     }
    366     length = loc.getKeywordValue("colReorder", value, LENGTHOF(value), errorCode);
    367     if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    368         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    369         return;
    370     }
    371     if (length != 0) {
    372         int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST];
    373         int32_t codesLength = 0;
    374         char *scriptName = value;
    375         for (;;) {
    376             if (codesLength == LENGTHOF(codes)) {
    377                 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    378                 return;
    379             }
    380             char *limit = scriptName;
    381             char c;
    382             while ((c = *limit) != 0 && c != '-') { ++limit; }
    383             *limit = 0;
    384             int32_t code;
    385             if ((limit - scriptName) == 4) {
    386                 // Strict parsing, accept only 4-letter script codes, not long names.
    387                 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName);
    388             } else {
    389                 code = getReorderCode(scriptName);
    390             }
    391             if (code < 0) {
    392                 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    393                 return;
    394             }
    395             codes[codesLength++] = code;
    396             if (c == 0) { break; }
    397             scriptName = limit + 1;
    398         }
    399         coll.setReorderCodes(codes, codesLength, errorCode);
    400     }
    401     length = loc.getKeywordValue("kv", value, LENGTHOF(value), errorCode);
    402     if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
    403         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    404         return;
    405     }
    406     if (length != 0) {
    407         int32_t code = getReorderCode(value);
    408         if (code < 0) {
    409             errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    410             return;
    411         }
    412         coll.setMaxVariable((UColReorderCode)code, errorCode);
    413     }
    414     if (U_FAILURE(errorCode)) {
    415         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    416     }
    417 }
    418 
    419 }  // namespace
    420 
    421 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
    422 {
    423     return createInstance(Locale::getDefault(), success);
    424 }
    425 
    426 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
    427                                    UErrorCode& status)
    428 {
    429     if (U_FAILURE(status))
    430         return 0;
    431     if (desiredLocale.isBogus()) {
    432         // Locale constructed from malformed locale ID or language tag.
    433         status = U_ILLEGAL_ARGUMENT_ERROR;
    434         return NULL;
    435     }
    436 
    437     Collator* coll;
    438 #if !UCONFIG_NO_SERVICE
    439     if (hasService()) {
    440         Locale actualLoc;
    441         coll = (Collator*)gService->get(desiredLocale, &actualLoc, status);
    442     } else
    443 #endif
    444     {
    445         coll = makeInstance(desiredLocale, status);
    446     }
    447     setAttributesFromKeywords(desiredLocale, *coll, status);
    448     if (U_FAILURE(status)) {
    449         delete coll;
    450         return NULL;
    451     }
    452     return coll;
    453 }
    454 
    455 
    456 Collator* Collator::makeInstance(const Locale&  desiredLocale,
    457                                          UErrorCode& status)
    458 {
    459     Locale validLocale("");
    460     const CollationTailoring *t =
    461         CollationLoader::loadTailoring(desiredLocale, validLocale, status);
    462     if (U_SUCCESS(status)) {
    463         Collator *result = new RuleBasedCollator(t, validLocale);
    464         if (result != NULL) {
    465             return result;
    466         }
    467         status = U_MEMORY_ALLOCATION_ERROR;
    468     }
    469     if (t != NULL) {
    470         t->deleteIfZeroRefCount();
    471     }
    472     return NULL;
    473 }
    474 
    475 Collator *
    476 Collator::safeClone() const {
    477     return clone();
    478 }
    479 
    480 // implement deprecated, previously abstract method
    481 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
    482                                     const UnicodeString& target) const
    483 {
    484     UErrorCode ec = U_ZERO_ERROR;
    485     return (EComparisonResult)compare(source, target, ec);
    486 }
    487 
    488 // implement deprecated, previously abstract method
    489 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
    490                                     const UnicodeString& target,
    491                                     int32_t length) const
    492 {
    493     UErrorCode ec = U_ZERO_ERROR;
    494     return (EComparisonResult)compare(source, target, length, ec);
    495 }
    496 
    497 // implement deprecated, previously abstract method
    498 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
    499                                     const UChar* target, int32_t targetLength)
    500                                     const
    501 {
    502     UErrorCode ec = U_ZERO_ERROR;
    503     return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
    504 }
    505 
    506 UCollationResult Collator::compare(UCharIterator &/*sIter*/,
    507                                    UCharIterator &/*tIter*/,
    508                                    UErrorCode &status) const {
    509     if(U_SUCCESS(status)) {
    510         // Not implemented in the base class.
    511         status = U_UNSUPPORTED_ERROR;
    512     }
    513     return UCOL_EQUAL;
    514 }
    515 
    516 UCollationResult Collator::compareUTF8(const StringPiece &source,
    517                                        const StringPiece &target,
    518                                        UErrorCode &status) const {
    519     if(U_FAILURE(status)) {
    520         return UCOL_EQUAL;
    521     }
    522     UCharIterator sIter, tIter;
    523     uiter_setUTF8(&sIter, source.data(), source.length());
    524     uiter_setUTF8(&tIter, target.data(), target.length());
    525     return compare(sIter, tIter, status);
    526 }
    527 
    528 UBool Collator::equals(const UnicodeString& source,
    529                        const UnicodeString& target) const
    530 {
    531     UErrorCode ec = U_ZERO_ERROR;
    532     return (compare(source, target, ec) == UCOL_EQUAL);
    533 }
    534 
    535 UBool Collator::greaterOrEqual(const UnicodeString& source,
    536                                const UnicodeString& target) const
    537 {
    538     UErrorCode ec = U_ZERO_ERROR;
    539     return (compare(source, target, ec) != UCOL_LESS);
    540 }
    541 
    542 UBool Collator::greater(const UnicodeString& source,
    543                         const UnicodeString& target) const
    544 {
    545     UErrorCode ec = U_ZERO_ERROR;
    546     return (compare(source, target, ec) == UCOL_GREATER);
    547 }
    548 
    549 // this API  ignores registered collators, since it returns an
    550 // array of indefinite lifetime
    551 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
    552 {
    553     UErrorCode status = U_ZERO_ERROR;
    554     Locale *result = NULL;
    555     count = 0;
    556     if (isAvailableLocaleListInitialized(status))
    557     {
    558         result = availableLocaleList;
    559         count = availableLocaleListCount;
    560     }
    561     return result;
    562 }
    563 
    564 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
    565                                         const Locale& displayLocale,
    566                                         UnicodeString& name)
    567 {
    568 #if !UCONFIG_NO_SERVICE
    569     if (hasService()) {
    570         UnicodeString locNameStr;
    571         LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
    572         return gService->getDisplayName(locNameStr, name, displayLocale);
    573     }
    574 #endif
    575     return objectLocale.getDisplayName(displayLocale, name);
    576 }
    577 
    578 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
    579                                         UnicodeString& name)
    580 {
    581     return getDisplayName(objectLocale, Locale::getDefault(), name);
    582 }
    583 
    584 /* This is useless information */
    585 /*void Collator::getVersion(UVersionInfo versionInfo) const
    586 {
    587   if (versionInfo!=NULL)
    588     uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
    589 }
    590 */
    591 
    592 // UCollator protected constructor destructor ----------------------------
    593 
    594 /**
    595 * Default constructor.
    596 * Constructor is different from the old default Collator constructor.
    597 * The task for determing the default collation strength and normalization mode
    598 * is left to the child class.
    599 */
    600 Collator::Collator()
    601 : UObject()
    602 {
    603 }
    604 
    605 /**
    606 * Constructor.
    607 * Empty constructor, does not handle the arguments.
    608 * This constructor is done for backward compatibility with 1.7 and 1.8.
    609 * The task for handling the argument collation strength and normalization
    610 * mode is left to the child class.
    611 * @param collationStrength collation strength
    612 * @param decompositionMode
    613 * @deprecated 2.4 use the default constructor instead
    614 */
    615 Collator::Collator(UCollationStrength, UNormalizationMode )
    616 : UObject()
    617 {
    618 }
    619 
    620 Collator::~Collator()
    621 {
    622 }
    623 
    624 Collator::Collator(const Collator &other)
    625     : UObject(other)
    626 {
    627 }
    628 
    629 UBool Collator::operator==(const Collator& other) const
    630 {
    631     // Subclasses: Call this method and then add more specific checks.
    632     return typeid(*this) == typeid(other);
    633 }
    634 
    635 UBool Collator::operator!=(const Collator& other) const
    636 {
    637     return (UBool)!(*this == other);
    638 }
    639 
    640 int32_t U_EXPORT2 Collator::getBound(const uint8_t       *source,
    641                            int32_t             sourceLength,
    642                            UColBoundMode       boundType,
    643                            uint32_t            noOfLevels,
    644                            uint8_t             *result,
    645                            int32_t             resultLength,
    646                            UErrorCode          &status)
    647 {
    648     return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
    649 }
    650 
    651 void
    652 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
    653 }
    654 
    655 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
    656 {
    657     if(U_FAILURE(status)) {
    658         return NULL;
    659     }
    660     // everything can be changed
    661     return new UnicodeSet(0, 0x10FFFF);
    662 }
    663 
    664 // -------------------------------------
    665 
    666 #if !UCONFIG_NO_SERVICE
    667 URegistryKey U_EXPORT2
    668 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
    669 {
    670     if (U_SUCCESS(status)) {
    671         // Set the collator locales while registering so that createInstance()
    672         // need not guess whether the collator's locales are already set properly
    673         // (as they are by the data loader).
    674         toAdopt->setLocales(locale, locale, locale);
    675         return getService()->registerInstance(toAdopt, locale, status);
    676     }
    677     return NULL;
    678 }
    679 
    680 // -------------------------------------
    681 
    682 class CFactory : public LocaleKeyFactory {
    683 private:
    684     CollatorFactory* _delegate;
    685     Hashtable* _ids;
    686 
    687 public:
    688     CFactory(CollatorFactory* delegate, UErrorCode& status)
    689         : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
    690         , _delegate(delegate)
    691         , _ids(NULL)
    692     {
    693         if (U_SUCCESS(status)) {
    694             int32_t count = 0;
    695             _ids = new Hashtable(status);
    696             if (_ids) {
    697                 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
    698                 for (int i = 0; i < count; ++i) {
    699                     _ids->put(idlist[i], (void*)this, status);
    700                     if (U_FAILURE(status)) {
    701                         delete _ids;
    702                         _ids = NULL;
    703                         return;
    704                     }
    705                 }
    706             } else {
    707                 status = U_MEMORY_ALLOCATION_ERROR;
    708             }
    709         }
    710     }
    711 
    712     virtual ~CFactory();
    713 
    714     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
    715 
    716 protected:
    717     virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
    718     {
    719         if (U_SUCCESS(status)) {
    720             return _ids;
    721         }
    722         return NULL;
    723     }
    724 
    725     virtual UnicodeString&
    726         getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
    727 };
    728 
    729 CFactory::~CFactory()
    730 {
    731     delete _delegate;
    732     delete _ids;
    733 }
    734 
    735 UObject*
    736 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
    737 {
    738     if (handlesKey(key, status)) {
    739         const LocaleKey& lkey = (const LocaleKey&)key;
    740         Locale validLoc;
    741         lkey.currentLocale(validLoc);
    742         return _delegate->createCollator(validLoc);
    743     }
    744     return NULL;
    745 }
    746 
    747 UnicodeString&
    748 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
    749 {
    750     if ((_coverage & 0x1) == 0) {
    751         UErrorCode status = U_ZERO_ERROR;
    752         const Hashtable* ids = getSupportedIDs(status);
    753         if (ids && (ids->get(id) != NULL)) {
    754             Locale loc;
    755             LocaleUtility::initLocaleFromName(id, loc);
    756             return _delegate->getDisplayName(loc, locale, result);
    757         }
    758     }
    759     result.setToBogus();
    760     return result;
    761 }
    762 
    763 URegistryKey U_EXPORT2
    764 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
    765 {
    766     if (U_SUCCESS(status)) {
    767         CFactory* f = new CFactory(toAdopt, status);
    768         if (f) {
    769             return getService()->registerFactory(f, status);
    770         }
    771         status = U_MEMORY_ALLOCATION_ERROR;
    772     }
    773     return NULL;
    774 }
    775 
    776 // -------------------------------------
    777 
    778 UBool U_EXPORT2
    779 Collator::unregister(URegistryKey key, UErrorCode& status)
    780 {
    781     if (U_SUCCESS(status)) {
    782         if (hasService()) {
    783             return gService->unregister(key, status);
    784         }
    785         status = U_ILLEGAL_ARGUMENT_ERROR;
    786     }
    787     return FALSE;
    788 }
    789 #endif /* UCONFIG_NO_SERVICE */
    790 
    791 class CollationLocaleListEnumeration : public StringEnumeration {
    792 private:
    793     int32_t index;
    794 public:
    795     static UClassID U_EXPORT2 getStaticClassID(void);
    796     virtual UClassID getDynamicClassID(void) const;
    797 public:
    798     CollationLocaleListEnumeration()
    799         : index(0)
    800     {
    801         // The global variables should already be initialized.
    802         //isAvailableLocaleListInitialized(status);
    803     }
    804 
    805     virtual ~CollationLocaleListEnumeration();
    806 
    807     virtual StringEnumeration * clone() const
    808     {
    809         CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
    810         if (result) {
    811             result->index = index;
    812         }
    813         return result;
    814     }
    815 
    816     virtual int32_t count(UErrorCode &/*status*/) const {
    817         return availableLocaleListCount;
    818     }
    819 
    820     virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
    821         const char* result;
    822         if(index < availableLocaleListCount) {
    823             result = availableLocaleList[index++].getName();
    824             if(resultLength != NULL) {
    825                 *resultLength = (int32_t)uprv_strlen(result);
    826             }
    827         } else {
    828             if(resultLength != NULL) {
    829                 *resultLength = 0;
    830             }
    831             result = NULL;
    832         }
    833         return result;
    834     }
    835 
    836     virtual const UnicodeString* snext(UErrorCode& status) {
    837         int32_t resultLength = 0;
    838         const char *s = next(&resultLength, status);
    839         return setChars(s, resultLength, status);
    840     }
    841 
    842     virtual void reset(UErrorCode& /*status*/) {
    843         index = 0;
    844     }
    845 };
    846 
    847 CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {}
    848 
    849 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
    850 
    851 
    852 // -------------------------------------
    853 
    854 StringEnumeration* U_EXPORT2
    855 Collator::getAvailableLocales(void)
    856 {
    857 #if !UCONFIG_NO_SERVICE
    858     if (hasService()) {
    859         return getService()->getAvailableLocales();
    860     }
    861 #endif /* UCONFIG_NO_SERVICE */
    862     UErrorCode status = U_ZERO_ERROR;
    863     if (isAvailableLocaleListInitialized(status)) {
    864         return new CollationLocaleListEnumeration();
    865     }
    866     return NULL;
    867 }
    868 
    869 StringEnumeration* U_EXPORT2
    870 Collator::getKeywords(UErrorCode& status) {
    871     // This is a wrapper over ucol_getKeywords
    872     UEnumeration* uenum = ucol_getKeywords(&status);
    873     if (U_FAILURE(status)) {
    874         uenum_close(uenum);
    875         return NULL;
    876     }
    877     return new UStringEnumeration(uenum);
    878 }
    879 
    880 StringEnumeration* U_EXPORT2
    881 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
    882     // This is a wrapper over ucol_getKeywordValues
    883     UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
    884     if (U_FAILURE(status)) {
    885         uenum_close(uenum);
    886         return NULL;
    887     }
    888     return new UStringEnumeration(uenum);
    889 }
    890 
    891 StringEnumeration* U_EXPORT2
    892 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
    893                                     UBool commonlyUsed, UErrorCode& status) {
    894     // This is a wrapper over ucol_getKeywordValuesForLocale
    895     UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(),
    896                                                         commonlyUsed, &status);
    897     if (U_FAILURE(status)) {
    898         uenum_close(uenum);
    899         return NULL;
    900     }
    901     return new UStringEnumeration(uenum);
    902 }
    903 
    904 Locale U_EXPORT2
    905 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
    906                                   UBool& isAvailable, UErrorCode& status) {
    907     // This is a wrapper over ucol_getFunctionalEquivalent
    908     char loc[ULOC_FULLNAME_CAPACITY];
    909     /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
    910                     keyword, locale.getName(), &isAvailable, &status);
    911     if (U_FAILURE(status)) {
    912         *loc = 0; // root
    913     }
    914     return Locale::createFromName(loc);
    915 }
    916 
    917 Collator::ECollationStrength
    918 Collator::getStrength(void) const {
    919     UErrorCode intStatus = U_ZERO_ERROR;
    920     return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus);
    921 }
    922 
    923 void
    924 Collator::setStrength(ECollationStrength newStrength) {
    925     UErrorCode intStatus = U_ZERO_ERROR;
    926     setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus);
    927 }
    928 
    929 Collator &
    930 Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) {
    931     if (U_SUCCESS(errorCode)) {
    932         errorCode = U_UNSUPPORTED_ERROR;
    933     }
    934     return *this;
    935 }
    936 
    937 UColReorderCode
    938 Collator::getMaxVariable() const {
    939     return UCOL_REORDER_CODE_PUNCTUATION;
    940 }
    941 
    942 int32_t
    943 Collator::getReorderCodes(int32_t* /* dest*/,
    944                           int32_t /* destCapacity*/,
    945                           UErrorCode& status) const
    946 {
    947     if (U_SUCCESS(status)) {
    948         status = U_UNSUPPORTED_ERROR;
    949     }
    950     return 0;
    951 }
    952 
    953 void
    954 Collator::setReorderCodes(const int32_t* /* reorderCodes */,
    955                           int32_t /* reorderCodesLength */,
    956                           UErrorCode& status)
    957 {
    958     if (U_SUCCESS(status)) {
    959         status = U_UNSUPPORTED_ERROR;
    960     }
    961 }
    962 
    963 int32_t
    964 Collator::getEquivalentReorderCodes(int32_t reorderCode,
    965                                     int32_t *dest, int32_t capacity,
    966                                     UErrorCode &errorCode) {
    967     if(U_FAILURE(errorCode)) { return 0; }
    968     if(capacity < 0 || (dest == NULL && capacity > 0)) {
    969         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    970         return 0;
    971     }
    972     const CollationData *baseData = CollationRoot::getData(errorCode);
    973     if(U_FAILURE(errorCode)) { return 0; }
    974     return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode);
    975 }
    976 
    977 int32_t
    978 Collator::internalGetShortDefinitionString(const char * /*locale*/,
    979                                                              char * /*buffer*/,
    980                                                              int32_t /*capacity*/,
    981                                                              UErrorCode &status) const {
    982   if(U_SUCCESS(status)) {
    983     status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */
    984   }
    985   return 0;
    986 }
    987 
    988 UCollationResult
    989 Collator::internalCompareUTF8(const char *left, int32_t leftLength,
    990                               const char *right, int32_t rightLength,
    991                               UErrorCode &errorCode) const {
    992     if(U_FAILURE(errorCode)) { return UCOL_EQUAL; }
    993     if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) {
    994         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    995         return UCOL_EQUAL;
    996     }
    997     return compareUTF8(
    998             StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength),
    999             StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength),
   1000             errorCode);
   1001 }
   1002 
   1003 int32_t
   1004 Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2],
   1005                                   uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const {
   1006     if (U_SUCCESS(errorCode)) {
   1007         errorCode = U_UNSUPPORTED_ERROR;
   1008     }
   1009     return 0;
   1010 }
   1011 
   1012 // UCollator private data members ----------------------------------------
   1013 
   1014 /* This is useless information */
   1015 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
   1016 
   1017 // -------------------------------------
   1018 
   1019 U_NAMESPACE_END
   1020 
   1021 #endif /* #if !UCONFIG_NO_COLLATION */
   1022 
   1023 /* eof */
   1024