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