Home | History | Annotate | Download | only in i18n
      1 /*
      2  ******************************************************************************
      3  * Copyright (C) 1996-2009, 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  */
     39 
     40 #include "unicode/utypes.h"
     41 
     42 #if !UCONFIG_NO_COLLATION
     43 
     44 #include "unicode/coll.h"
     45 #include "unicode/tblcoll.h"
     46 #include "ucol_imp.h"
     47 #include "cstring.h"
     48 #include "cmemory.h"
     49 #include "umutex.h"
     50 #include "servloc.h"
     51 #include "ustrenum.h"
     52 #include "uresimp.h"
     53 #include "ucln_in.h"
     54 
     55 static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL;
     56 static int32_t  availableLocaleListCount;
     57 static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
     58 
     59 /**
     60  * Release all static memory held by collator.
     61  */
     62 U_CDECL_BEGIN
     63 static UBool U_CALLCONV collator_cleanup(void) {
     64 #if !UCONFIG_NO_SERVICE
     65     if (gService) {
     66         delete gService;
     67         gService = NULL;
     68     }
     69 #endif
     70     if (availableLocaleList) {
     71         delete []availableLocaleList;
     72         availableLocaleList = NULL;
     73     }
     74     availableLocaleListCount = 0;
     75 
     76     return TRUE;
     77 }
     78 
     79 U_CDECL_END
     80 
     81 U_NAMESPACE_BEGIN
     82 
     83 #if !UCONFIG_NO_SERVICE
     84 
     85 // ------------------------------------------
     86 //
     87 // Registration
     88 //
     89 
     90 //-------------------------------------------
     91 
     92 CollatorFactory::~CollatorFactory() {}
     93 
     94 //-------------------------------------------
     95 
     96 UBool
     97 CollatorFactory::visible(void) const {
     98     return TRUE;
     99 }
    100 
    101 //-------------------------------------------
    102 
    103 UnicodeString&
    104 CollatorFactory::getDisplayName(const Locale& objectLocale,
    105                                 const Locale& displayLocale,
    106                                 UnicodeString& result)
    107 {
    108   return objectLocale.getDisplayName(displayLocale, result);
    109 }
    110 
    111 // -------------------------------------
    112 
    113 class ICUCollatorFactory : public ICUResourceBundleFactory {
    114  public:
    115     ICUCollatorFactory():  ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
    116  protected:
    117     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
    118 };
    119 
    120 UObject*
    121 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
    122     if (handlesKey(key, status)) {
    123         const LocaleKey& lkey = (const LocaleKey&)key;
    124         Locale loc;
    125         // make sure the requested locale is correct
    126         // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
    127         // but for ICU rb resources we use the actual one since it will fallback again
    128         lkey.canonicalLocale(loc);
    129 
    130         return Collator::makeInstance(loc, status);
    131     }
    132     return NULL;
    133 }
    134 
    135 // -------------------------------------
    136 
    137 class ICUCollatorService : public ICULocaleService {
    138 public:
    139     ICUCollatorService()
    140         : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
    141     {
    142         UErrorCode status = U_ZERO_ERROR;
    143         registerFactory(new ICUCollatorFactory(), status);
    144     }
    145 
    146     virtual UObject* cloneInstance(UObject* instance) const {
    147         return ((Collator*)instance)->clone();
    148     }
    149 
    150     virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
    151         LocaleKey& lkey = (LocaleKey&)key;
    152         if (actualID) {
    153             // Ugly Hack Alert! We return an empty actualID to signal
    154             // to callers that this is a default object, not a "real"
    155             // service-created object. (TODO remove in 3.0) [aliu]
    156             actualID->truncate(0);
    157         }
    158         Locale loc("");
    159         lkey.canonicalLocale(loc);
    160         return Collator::makeInstance(loc, status);
    161     }
    162 
    163     virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
    164         UnicodeString ar;
    165         if (actualReturn == NULL) {
    166             actualReturn = &ar;
    167         }
    168         Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status);
    169         // Ugly Hack Alert! If the actualReturn length is zero, this
    170         // means we got a default object, not a "real" service-created
    171         // object.  We don't call setLocales() on a default object,
    172         // because that will overwrite its correct built-in locale
    173         // metadata (valid & actual) with our incorrect data (all we
    174         // have is the requested locale). (TODO remove in 3.0) [aliu]
    175         if (result && actualReturn->length() > 0) {
    176             const LocaleKey& lkey = (const LocaleKey&)key;
    177             Locale canonicalLocale("");
    178             Locale currentLocale("");
    179 
    180             LocaleUtility::initLocaleFromName(*actualReturn, currentLocale);
    181             result->setLocales(lkey.canonicalLocale(canonicalLocale), currentLocale, currentLocale);
    182         }
    183         return result;
    184     }
    185 
    186     virtual UBool isDefault() const {
    187         return countFactories() == 1;
    188     }
    189 };
    190 
    191 // -------------------------------------
    192 
    193 static ICULocaleService*
    194 getService(void)
    195 {
    196     UBool needInit;
    197     UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
    198     if(needInit) {
    199         ICULocaleService *newservice = new ICUCollatorService();
    200         if(newservice) {
    201             umtx_lock(NULL);
    202             if(gService == NULL) {
    203                 gService = newservice;
    204                 newservice = NULL;
    205             }
    206             umtx_unlock(NULL);
    207         }
    208         if(newservice) {
    209             delete newservice;
    210         }
    211         else {
    212             ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
    213         }
    214     }
    215     return gService;
    216 }
    217 
    218 // -------------------------------------
    219 
    220 static inline UBool
    221 hasService(void)
    222 {
    223     UBool retVal;
    224     UMTX_CHECK(NULL, gService != NULL, retVal);
    225     return retVal;
    226 }
    227 
    228 // -------------------------------------
    229 
    230 UCollator*
    231 Collator::createUCollator(const char *loc,
    232                           UErrorCode *status)
    233 {
    234     UCollator *result = 0;
    235     if (status && U_SUCCESS(*status) && hasService()) {
    236         Locale desiredLocale(loc);
    237         Collator *col = (Collator*)gService->get(desiredLocale, *status);
    238         if (col && col->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
    239             RuleBasedCollator *rbc = (RuleBasedCollator *)col;
    240             if (!rbc->dataIsOwned) {
    241                 result = ucol_safeClone(rbc->ucollator, NULL, NULL, status);
    242             } else {
    243                 result = rbc->ucollator;
    244                 rbc->ucollator = NULL; // to prevent free on delete
    245             }
    246         }
    247         delete col;
    248     }
    249     return result;
    250 }
    251 #endif /* UCONFIG_NO_SERVICE */
    252 
    253 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
    254     // for now, there is a hardcoded list, so just walk through that list and set it up.
    255     UBool needInit;
    256     UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
    257 
    258     if (needInit) {
    259         UResourceBundle *index = NULL;
    260         UResourceBundle installed;
    261         Locale * temp;
    262         int32_t i = 0;
    263         int32_t localeCount;
    264 
    265         ures_initStackObject(&installed);
    266         index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
    267         ures_getByKey(index, "InstalledLocales", &installed, &status);
    268 
    269         if(U_SUCCESS(status)) {
    270             localeCount = ures_getSize(&installed);
    271             temp = new Locale[localeCount];
    272 
    273             if (temp != NULL) {
    274                 ures_resetIterator(&installed);
    275                 while(ures_hasNext(&installed)) {
    276                     const char *tempKey = NULL;
    277                     ures_getNextString(&installed, NULL, &tempKey, &status);
    278                     temp[i++] = Locale(tempKey);
    279                 }
    280 
    281                 umtx_lock(NULL);
    282                 if (availableLocaleList == NULL)
    283                 {
    284                     availableLocaleListCount = localeCount;
    285                     availableLocaleList = temp;
    286                     temp = NULL;
    287                     ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
    288                 }
    289                 umtx_unlock(NULL);
    290 
    291                 needInit = FALSE;
    292                 if (temp) {
    293                     delete []temp;
    294                 }
    295             }
    296 
    297             ures_close(&installed);
    298         }
    299         ures_close(index);
    300     }
    301     return !needInit;
    302 }
    303 
    304 // Collator public methods -----------------------------------------------
    305 
    306 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
    307 {
    308     return createInstance(Locale::getDefault(), success);
    309 }
    310 
    311 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
    312                                    UErrorCode& status)
    313 {
    314     if (U_FAILURE(status))
    315         return 0;
    316 
    317 #if !UCONFIG_NO_SERVICE
    318     if (hasService()) {
    319         Locale actualLoc;
    320         Collator *result =
    321             (Collator*)gService->get(desiredLocale, &actualLoc, status);
    322         // Ugly Hack Alert! If the returned locale is empty (not root,
    323         // but empty -- getName() == "") then that means the service
    324         // returned a default object, not a "real" service object.  In
    325         // that case, the locale metadata (valid & actual) is setup
    326         // correctly already, and we don't want to overwrite it. (TODO
    327         // remove in 3.0) [aliu]
    328         if (*actualLoc.getName() != 0) {
    329             result->setLocales(desiredLocale, actualLoc, actualLoc);
    330         }
    331         return result;
    332     }
    333 #endif
    334     return makeInstance(desiredLocale, status);
    335 }
    336 
    337 
    338 Collator* Collator::makeInstance(const Locale&  desiredLocale,
    339                                          UErrorCode& status)
    340 {
    341     // A bit of explanation is required here. Although in the current
    342     // implementation
    343     // Collator::createInstance() is just turning around and calling
    344     // RuleBasedCollator(Locale&), this will not necessarily always be the
    345     // case. For example, suppose we modify this code to handle a
    346     // non-table-based Collator, such as that for Thai. In this case,
    347     // createInstance() will have to be modified to somehow determine this fact
    348     // (perhaps a field in the resource bundle). Then it can construct the
    349     // non-table-based Collator in some other way, when it sees that it needs
    350     // to.
    351     // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS
    352     // return a valid collation object, if the system is functioning properly.
    353     // The reason is that it will fall back, use the default locale, and even
    354     // use the built-in default collation rules. THEREFORE, createInstance()
    355     // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN
    356     // ADVANCE that the given locale's collation is properly implemented as a
    357     // RuleBasedCollator.
    358     // Currently, we don't do this...we always return a RuleBasedCollator,
    359     // whether it is strictly correct to do so or not, without checking, because
    360     // we currently have no way of checking.
    361 
    362     RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale,
    363         status);
    364     /* test for NULL */
    365     if (collation == 0) {
    366         status = U_MEMORY_ALLOCATION_ERROR;
    367         return 0;
    368     }
    369     if (U_FAILURE(status))
    370     {
    371         delete collation;
    372         collation = 0;
    373     }
    374     return collation;
    375 }
    376 
    377 #ifdef U_USE_COLLATION_OBSOLETE_2_6
    378 // !!! dlf the following is obsolete, ignore registration for this
    379 
    380 Collator *
    381 Collator::createInstance(const Locale &loc,
    382                          UVersionInfo version,
    383                          UErrorCode &status)
    384 {
    385     Collator *collator;
    386     UVersionInfo info;
    387 
    388     collator=new RuleBasedCollator(loc, status);
    389     /* test for NULL */
    390     if (collator == 0) {
    391         status = U_MEMORY_ALLOCATION_ERROR;
    392         return 0;
    393     }
    394 
    395     if(U_SUCCESS(status)) {
    396         collator->getVersion(info);
    397         if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) {
    398             delete collator;
    399             status=U_MISSING_RESOURCE_ERROR;
    400             return 0;
    401         }
    402     }
    403     return collator;
    404 }
    405 #endif
    406 
    407 // implement deprecated, previously abstract method
    408 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
    409                                     const UnicodeString& target) const
    410 {
    411     UErrorCode ec = U_ZERO_ERROR;
    412     return (Collator::EComparisonResult)compare(source, target, ec);
    413 }
    414 
    415 // implement deprecated, previously abstract method
    416 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
    417                                     const UnicodeString& target,
    418                                     int32_t length) const
    419 {
    420     UErrorCode ec = U_ZERO_ERROR;
    421     return (Collator::EComparisonResult)compare(source, target, length, ec);
    422 }
    423 
    424 // implement deprecated, previously abstract method
    425 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
    426                                     const UChar* target, int32_t targetLength)
    427                                     const
    428 {
    429     UErrorCode ec = U_ZERO_ERROR;
    430     return (Collator::EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
    431 }
    432 
    433 UCollationResult Collator::compare(UCharIterator &/*sIter*/,
    434                                    UCharIterator &/*tIter*/,
    435                                    UErrorCode &status) const {
    436     if(U_SUCCESS(status)) {
    437         // Not implemented in the base class.
    438         status = U_UNSUPPORTED_ERROR;
    439     }
    440     return UCOL_EQUAL;
    441 }
    442 
    443 UCollationResult Collator::compareUTF8(const StringPiece &source,
    444                                        const StringPiece &target,
    445                                        UErrorCode &status) const {
    446     if(U_FAILURE(status)) {
    447         return UCOL_EQUAL;
    448     }
    449     UCharIterator sIter, tIter;
    450     uiter_setUTF8(&sIter, source.data(), source.length());
    451     uiter_setUTF8(&tIter, target.data(), target.length());
    452     return compare(sIter, tIter, status);
    453 }
    454 
    455 UBool Collator::equals(const UnicodeString& source,
    456                        const UnicodeString& target) const
    457 {
    458     UErrorCode ec = U_ZERO_ERROR;
    459     return (compare(source, target, ec) == UCOL_EQUAL);
    460 }
    461 
    462 UBool Collator::greaterOrEqual(const UnicodeString& source,
    463                                const UnicodeString& target) const
    464 {
    465     UErrorCode ec = U_ZERO_ERROR;
    466     return (compare(source, target, ec) != UCOL_LESS);
    467 }
    468 
    469 UBool Collator::greater(const UnicodeString& source,
    470                         const UnicodeString& target) const
    471 {
    472     UErrorCode ec = U_ZERO_ERROR;
    473     return (compare(source, target, ec) == UCOL_GREATER);
    474 }
    475 
    476 // this API  ignores registered collators, since it returns an
    477 // array of indefinite lifetime
    478 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
    479 {
    480     UErrorCode status = U_ZERO_ERROR;
    481     Locale *result = NULL;
    482     count = 0;
    483     if (isAvailableLocaleListInitialized(status))
    484     {
    485         result = availableLocaleList;
    486         count = availableLocaleListCount;
    487     }
    488     return result;
    489 }
    490 
    491 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
    492                                         const Locale& displayLocale,
    493                                         UnicodeString& name)
    494 {
    495 #if !UCONFIG_NO_SERVICE
    496     if (hasService()) {
    497         UnicodeString locNameStr;
    498         LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
    499         return gService->getDisplayName(locNameStr, name, displayLocale);
    500     }
    501 #endif
    502     return objectLocale.getDisplayName(displayLocale, name);
    503 }
    504 
    505 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
    506                                         UnicodeString& name)
    507 {
    508     return getDisplayName(objectLocale, Locale::getDefault(), name);
    509 }
    510 
    511 /* This is useless information */
    512 /*void Collator::getVersion(UVersionInfo versionInfo) const
    513 {
    514   if (versionInfo!=NULL)
    515     uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
    516 }
    517 */
    518 
    519 // UCollator protected constructor destructor ----------------------------
    520 
    521 /**
    522 * Default constructor.
    523 * Constructor is different from the old default Collator constructor.
    524 * The task for determing the default collation strength and normalization mode
    525 * is left to the child class.
    526 */
    527 Collator::Collator()
    528 : UObject()
    529 {
    530 }
    531 
    532 /**
    533 * Constructor.
    534 * Empty constructor, does not handle the arguments.
    535 * This constructor is done for backward compatibility with 1.7 and 1.8.
    536 * The task for handling the argument collation strength and normalization
    537 * mode is left to the child class.
    538 * @param collationStrength collation strength
    539 * @param decompositionMode
    540 * @deprecated 2.4 use the default constructor instead
    541 */
    542 Collator::Collator(UCollationStrength, UNormalizationMode )
    543 : UObject()
    544 {
    545 }
    546 
    547 Collator::~Collator()
    548 {
    549 }
    550 
    551 Collator::Collator(const Collator &other)
    552     : UObject(other)
    553 {
    554 }
    555 
    556 UBool Collator::operator==(const Collator& other) const
    557 {
    558     return (UBool)(this == &other);
    559 }
    560 
    561 UBool Collator::operator!=(const Collator& other) const
    562 {
    563     return (UBool)!(*this == other);
    564 }
    565 
    566 int32_t U_EXPORT2 Collator::getBound(const uint8_t       *source,
    567                            int32_t             sourceLength,
    568                            UColBoundMode       boundType,
    569                            uint32_t            noOfLevels,
    570                            uint8_t             *result,
    571                            int32_t             resultLength,
    572                            UErrorCode          &status)
    573 {
    574     return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
    575 }
    576 
    577 void
    578 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
    579 }
    580 
    581 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
    582 {
    583     if(U_FAILURE(status)) {
    584         return NULL;
    585     }
    586     // everything can be changed
    587     return new UnicodeSet(0, 0x10FFFF);
    588 }
    589 
    590 // -------------------------------------
    591 
    592 #if !UCONFIG_NO_SERVICE
    593 URegistryKey U_EXPORT2
    594 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
    595 {
    596     if (U_SUCCESS(status)) {
    597         return getService()->registerInstance(toAdopt, locale, status);
    598     }
    599     return NULL;
    600 }
    601 
    602 // -------------------------------------
    603 
    604 class CFactory : public LocaleKeyFactory {
    605 private:
    606     CollatorFactory* _delegate;
    607     Hashtable* _ids;
    608 
    609 public:
    610     CFactory(CollatorFactory* delegate, UErrorCode& status)
    611         : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
    612         , _delegate(delegate)
    613         , _ids(NULL)
    614     {
    615         if (U_SUCCESS(status)) {
    616             int32_t count = 0;
    617             _ids = new Hashtable(status);
    618             if (_ids) {
    619                 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
    620                 for (int i = 0; i < count; ++i) {
    621                     _ids->put(idlist[i], (void*)this, status);
    622                     if (U_FAILURE(status)) {
    623                         delete _ids;
    624                         _ids = NULL;
    625                         return;
    626                     }
    627                 }
    628             } else {
    629                 status = U_MEMORY_ALLOCATION_ERROR;
    630             }
    631         }
    632     }
    633 
    634     virtual ~CFactory()
    635     {
    636         delete _delegate;
    637         delete _ids;
    638     }
    639 
    640     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
    641 
    642 protected:
    643     virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
    644     {
    645         if (U_SUCCESS(status)) {
    646             return _ids;
    647         }
    648         return NULL;
    649     }
    650 
    651     virtual UnicodeString&
    652         getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
    653 };
    654 
    655 UObject*
    656 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
    657 {
    658     if (handlesKey(key, status)) {
    659         const LocaleKey& lkey = (const LocaleKey&)key;
    660         Locale validLoc;
    661         lkey.currentLocale(validLoc);
    662         return _delegate->createCollator(validLoc);
    663     }
    664     return NULL;
    665 }
    666 
    667 UnicodeString&
    668 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
    669 {
    670     if ((_coverage & 0x1) == 0) {
    671         UErrorCode status = U_ZERO_ERROR;
    672         const Hashtable* ids = getSupportedIDs(status);
    673         if (ids && (ids->get(id) != NULL)) {
    674             Locale loc;
    675             LocaleUtility::initLocaleFromName(id, loc);
    676             return _delegate->getDisplayName(loc, locale, result);
    677         }
    678     }
    679     result.setToBogus();
    680     return result;
    681 }
    682 
    683 URegistryKey U_EXPORT2
    684 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
    685 {
    686     if (U_SUCCESS(status)) {
    687         CFactory* f = new CFactory(toAdopt, status);
    688         if (f) {
    689             return getService()->registerFactory(f, status);
    690         }
    691         status = U_MEMORY_ALLOCATION_ERROR;
    692     }
    693     return NULL;
    694 }
    695 
    696 // -------------------------------------
    697 
    698 UBool U_EXPORT2
    699 Collator::unregister(URegistryKey key, UErrorCode& status)
    700 {
    701     if (U_SUCCESS(status)) {
    702         if (hasService()) {
    703             return gService->unregister(key, status);
    704         }
    705         status = U_ILLEGAL_ARGUMENT_ERROR;
    706     }
    707     return FALSE;
    708 }
    709 #endif /* UCONFIG_NO_SERVICE */
    710 
    711 class CollationLocaleListEnumeration : public StringEnumeration {
    712 private:
    713     int32_t index;
    714 public:
    715     static UClassID U_EXPORT2 getStaticClassID(void);
    716     virtual UClassID getDynamicClassID(void) const;
    717 public:
    718     CollationLocaleListEnumeration()
    719         : index(0)
    720     {
    721         // The global variables should already be initialized.
    722         //isAvailableLocaleListInitialized(status);
    723     }
    724 
    725     virtual ~CollationLocaleListEnumeration() {
    726     }
    727 
    728     virtual StringEnumeration * clone() const
    729     {
    730         CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
    731         if (result) {
    732             result->index = index;
    733         }
    734         return result;
    735     }
    736 
    737     virtual int32_t count(UErrorCode &/*status*/) const {
    738         return availableLocaleListCount;
    739     }
    740 
    741     virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
    742         const char* result;
    743         if(index < availableLocaleListCount) {
    744             result = availableLocaleList[index++].getName();
    745             if(resultLength != NULL) {
    746                 *resultLength = uprv_strlen(result);
    747             }
    748         } else {
    749             if(resultLength != NULL) {
    750                 *resultLength = 0;
    751             }
    752             result = NULL;
    753         }
    754         return result;
    755     }
    756 
    757     virtual const UnicodeString* snext(UErrorCode& status) {
    758         int32_t resultLength = 0;
    759         const char *s = next(&resultLength, status);
    760         return setChars(s, resultLength, status);
    761     }
    762 
    763     virtual void reset(UErrorCode& /*status*/) {
    764         index = 0;
    765     }
    766 };
    767 
    768 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
    769 
    770 
    771 // -------------------------------------
    772 
    773 StringEnumeration* U_EXPORT2
    774 Collator::getAvailableLocales(void)
    775 {
    776 #if !UCONFIG_NO_SERVICE
    777     if (hasService()) {
    778         return getService()->getAvailableLocales();
    779     }
    780 #endif /* UCONFIG_NO_SERVICE */
    781     UErrorCode status = U_ZERO_ERROR;
    782     if (isAvailableLocaleListInitialized(status)) {
    783         return new CollationLocaleListEnumeration();
    784     }
    785     return NULL;
    786 }
    787 
    788 StringEnumeration* U_EXPORT2
    789 Collator::getKeywords(UErrorCode& status) {
    790     // This is a wrapper over ucol_getKeywords
    791     UEnumeration* uenum = ucol_getKeywords(&status);
    792     if (U_FAILURE(status)) {
    793         uenum_close(uenum);
    794         return NULL;
    795     }
    796     return new UStringEnumeration(uenum);
    797 }
    798 
    799 StringEnumeration* U_EXPORT2
    800 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
    801     // This is a wrapper over ucol_getKeywordValues
    802     UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
    803     if (U_FAILURE(status)) {
    804         uenum_close(uenum);
    805         return NULL;
    806     }
    807     return new UStringEnumeration(uenum);
    808 }
    809 
    810 StringEnumeration* U_EXPORT2
    811 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
    812                                     UBool commonlyUsed, UErrorCode& status) {
    813     // This is a wrapper over ucol_getKeywordValuesForLocale
    814     UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(),
    815                                                         commonlyUsed, &status);
    816     if (U_FAILURE(status)) {
    817         uenum_close(uenum);
    818         return NULL;
    819     }
    820     return new UStringEnumeration(uenum);
    821 }
    822 
    823 Locale U_EXPORT2
    824 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
    825                                   UBool& isAvailable, UErrorCode& status) {
    826     // This is a wrapper over ucol_getFunctionalEquivalent
    827     char loc[ULOC_FULLNAME_CAPACITY];
    828     /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
    829                     keyword, locale.getName(), &isAvailable, &status);
    830     if (U_FAILURE(status)) {
    831         *loc = 0; // root
    832     }
    833     return Locale::createFromName(loc);
    834 }
    835 
    836 // UCollator private data members ----------------------------------------
    837 
    838 /* This is useless information */
    839 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
    840 
    841 // -------------------------------------
    842 
    843 U_NAMESPACE_END
    844 
    845 #endif /* #if !UCONFIG_NO_COLLATION */
    846 
    847 /* eof */
    848