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