137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang/*
22da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang ******************************************************************************
32da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * Copyright (C) 1996-2014, International Business Machines Corporation and
437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * others. All Rights Reserved.
537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang ******************************************************************************
637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang */
72da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang
82da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang/**
937fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * File coll.cpp
1037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
1137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * Created by: Helena Shih
1237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
1337fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * Modification History:
1437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
1537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *  Date        Name        Description
162da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang *  2/5/97      aliu        Modified createDefault to load collation data from
172da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang *                          binary files when possible.  Added related methods
182da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang *                          createCollationFromFile, chopLocale, createPathName.
192da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang *  2/11/97     aliu        Added methods addToCache, findInCache, which implement
2037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          a Collation cache.  Modified createDefault to look in
2137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          cache first, and also to store newly created Collation
2237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          objects in the cache.  Modified to not use gLocPath.
2337fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *  2/12/97     aliu        Modified to create objects from RuleBasedCollator cache.
2437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          Moved cache out of Collation class.
2537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *  2/13/97     aliu        Moved several methods out of this class and into
2637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          RuleBasedCollator, with modifications.  Modified
2737fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          createDefault() to call new RuleBasedCollator(Locale&)
2837fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          constructor.  General clean up and documentation.
2937fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *  2/20/97     helena      Added clone, operator==, operator!=, operator=, and copy
3037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *                          constructor.
3137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * 05/06/97     helena      Added memory allocation error detection.
3237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * 05/08/97     helena      Added createInstance().
337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang *  6/20/97     helena      Java class name change.
347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * 04/23/99     stephen     Removed EDecompositionMode, merged with
357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang *                          Normalizer::EMode
3637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * 11/23/9      srl         Inlining of some critical functions
377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * 01/29/01     synwee      Modified into a C++ wrapper calling C APIs (ucol.h)
387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * 2012-2014    markus      Rewritten in C++ again.
397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang */
407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "utypeinfo.h"  // for 'typeid' to work
427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "unicode/utypes.h"
447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#if !UCONFIG_NO_COLLATION
467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "unicode/coll.h"
487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "unicode/tblcoll.h"
497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "collationdata.h"
507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "collationroot.h"
517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "collationtailoring.h"
527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "ucol_imp.h"
537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "cstring.h"
547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "cmemory.h"
557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "umutex.h"
561a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber#include "servloc.h"
577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "uassert.h"
587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "ustrenum.h"
597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "uresimp.h"
607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "ucln_in.h"
617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic icu::Locale* availableLocaleList = NULL;
657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int32_t  availableLocaleListCount;
667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic icu::ICULocaleService* gService = NULL;
677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic icu::UInitOnce gAvailableLocaleListInitOnce;
697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/**
717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * Release all static memory held by collator.
727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang */
737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangU_CDECL_BEGIN
747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic UBool U_CALLCONV collator_cleanup(void) {
757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#if !UCONFIG_NO_SERVICE
767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (gService) {
777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        delete gService;
787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        gService = NULL;
797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    gServiceInitOnce.reset();
817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#endif
827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (availableLocaleList) {
837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        delete []availableLocaleList;
847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        availableLocaleList = NULL;
857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    availableLocaleListCount = 0;
877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    gAvailableLocaleListInitOnce.reset();
887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return TRUE;
897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangU_CDECL_END
927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangU_NAMESPACE_BEGIN
947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#if !UCONFIG_NO_SERVICE
967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang// ------------------------------------------
987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang//
997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang// Registration
1007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang//
1017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang//-------------------------------------------
1037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangCollatorFactory::~CollatorFactory() {}
1057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang//-------------------------------------------
1077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangUBool
1097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangCollatorFactory::visible(void) const {
1107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return TRUE;
1117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang//-------------------------------------------
1147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangUnicodeString&
1167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangCollatorFactory::getDisplayName(const Locale& objectLocale,
1177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                                const Locale& displayLocale,
1187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                                UnicodeString& result)
1197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
1207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return objectLocale.getDisplayName(displayLocale, result);
1217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1221a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber
1231a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber// -------------------------------------
1247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1251a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huberclass ICUCollatorFactory : public ICUResourceBundleFactory {
1261a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber public:
1277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ICUCollatorFactory() : ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
1281a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber    virtual ~ICUCollatorFactory();
1291a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber protected:
1307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
1311a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber};
1321a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber
1331a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas HuberICUCollatorFactory::~ICUCollatorFactory() {}
1341a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber
1351a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas HuberUObject*
1361a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas HuberICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
1377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (handlesKey(key, status)) {
1387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        const LocaleKey& lkey = (const LocaleKey&)key;
1397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        Locale loc;
1407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        // make sure the requested locale is correct
1417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
1427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        // but for ICU rb resources we use the actual one since it will fallback again
1437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        lkey.canonicalLocale(loc);
1447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1451a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber        return Collator::makeInstance(loc, status);
1467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return NULL;
1487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang// -------------------------------------
1517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangclass ICUCollatorService : public ICULocaleService {
1537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangpublic:
1547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ICUCollatorService()
1557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
1567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    {
1571a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber        UErrorCode status = U_ZERO_ERROR;
1587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        registerFactory(new ICUCollatorFactory(), status);
1597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    virtual ~ICUCollatorService();
1627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    virtual UObject* cloneInstance(UObject* instance) const {
1647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return ((Collator*)instance)->clone();
1657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
1687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        LocaleKey& lkey = (LocaleKey&)key;
1697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        if (actualID) {
1707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            // Ugly Hack Alert! We return an empty actualID to signal
1717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            // to callers that this is a default object, not a "real"
1727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            // service-created object. (TODO remove in 3.0) [aliu]
1737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            actualID->truncate(0);
1747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        }
1757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        Locale loc("");
1767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        lkey.canonicalLocale(loc);
1777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return Collator::makeInstance(loc, status);
1787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
1817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        UnicodeString ar;
1827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        if (actualReturn == NULL) {
1837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            actualReturn = &ar;
1847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        }
1857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return (Collator*)ICULocaleService::getKey(key, actualReturn, status);
1867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    virtual UBool isDefault() const {
1897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return countFactories() == 1;
1907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang};
1927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WangICUCollatorService::~ICUCollatorService() {}
1947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang// -------------------------------------
1967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void U_CALLCONV initService() {
1987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    gService = new ICUCollatorService();
1997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
2007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic ICULocaleService*
2047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WanggetService(void)
2057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
2067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    umtx_initOnce(gServiceInitOnce, &initService);
2077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return gService;
2087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang// -------------------------------------
2117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic inline UBool
2137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WanghasService(void)
2147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
2157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL);
2167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return retVal;
2177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#endif /* UCONFIG_NO_SERVICE */
2207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void U_CALLCONV
2227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria WanginitAvailableLocaleList(UErrorCode &status) {
2237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    U_ASSERT(availableLocaleListCount == 0);
2247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    U_ASSERT(availableLocaleList == NULL);
2257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    // for now, there is a hardcoded list, so just walk through that list and set it up.
2267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    UResourceBundle *index = NULL;
2277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    UResourceBundle installed;
2287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int32_t i = 0;
2297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ures_initStackObject(&installed);
2317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
2327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ures_getByKey(index, "InstalledLocales", &installed, &status);
2337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(U_SUCCESS(status)) {
2357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        availableLocaleListCount = ures_getSize(&installed);
2367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        availableLocaleList = new Locale[availableLocaleListCount];
2377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        if (availableLocaleList != NULL) {
2397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            ures_resetIterator(&installed);
2407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            while(ures_hasNext(&installed)) {
2417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                const char *tempKey = NULL;
2427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                ures_getNextString(&installed, NULL, &tempKey, &status);
2437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                availableLocaleList[i++] = Locale(tempKey);
2447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            }
2457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        }
2467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        U_ASSERT(availableLocaleListCount == i);
2477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        ures_close(&installed);
2487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
2497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ures_close(index);
2507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
2517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic UBool isAvailableLocaleListInitialized(UErrorCode &status) {
2547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status);
2557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return U_SUCCESS(status);
2567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang// Collator public methods -----------------------------------------------
2607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangnamespace {
2627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic const struct {
2647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    const char *name;
2657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    UColAttribute attr;
2667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang} collAttributes[] = {
2677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "colStrength", UCOL_STRENGTH },
2687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "colBackwards", UCOL_FRENCH_COLLATION },
2697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "colCaseLevel", UCOL_CASE_LEVEL },
2707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "colCaseFirst", UCOL_CASE_FIRST },
2717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "colAlternate", UCOL_ALTERNATE_HANDLING },
2727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "colNormalization", UCOL_NORMALIZATION_MODE },
2737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "colNumeric", UCOL_NUMERIC_COLLATION }
2747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang};
2757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic const struct {
2777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    const char *name;
2787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    UColAttributeValue value;
2797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang} collAttributeValues[] = {
2807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "primary", UCOL_PRIMARY },
2817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "secondary", UCOL_SECONDARY },
2827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "tertiary", UCOL_TERTIARY },
2837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "quaternary", UCOL_QUATERNARY },
2847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    // Note: Not supporting typo "quarternary" because it was never supported in locale IDs.
2857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "identical", UCOL_IDENTICAL },
2867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "no", UCOL_OFF },
2877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "yes", UCOL_ON },
2887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "shifted", UCOL_SHIFTED },
2897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "non-ignorable", UCOL_NON_IGNORABLE },
2907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "lower", UCOL_LOWER_FIRST },
2917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    { "upper", UCOL_UPPER_FIRST }
2927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang};
2937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic const char *collReorderCodes[UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST] = {
2957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    "space", "punct", "symbol", "currency", "digit"
2967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang};
2977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint32_t getReorderCode(const char *s) {
2997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for (int32_t i = 0; i < LENGTHOF(collReorderCodes); ++i) {
3007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        if (uprv_stricmp(s, collReorderCodes[i]) == 0) {
3017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            return UCOL_REORDER_CODE_FIRST + i;
3027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        }
3037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return -1;
3057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
3061a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber
3071a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber/**
3087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * Sets collation attributes according to locale keywords. See
3097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings
3107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang *
3117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * Using "alias" keywords and values where defined:
3127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * http://www.unicode.org/reports/tr35/tr35.html#Old_Locale_Extension_Syntax
3131a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
3147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang */
3157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangvoid setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) {
3167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (U_FAILURE(errorCode)) {
3177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
3187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3191a7ca64dd19ab9a5af3c4c3c58c815f764877bf7Andreas Huber    if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) {
3207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        // No keywords.
3217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
3227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    char value[1024];  // The reordering value could be long.
3247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    // Check for collation keywords that were already deprecated
3257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    // before any were supported in createInstance() (except for "collation").
3267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, LENGTHOF(value), errorCode);
3277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (U_FAILURE(errorCode)) {
3287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
3297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
3307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (length != 0) {
3327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        errorCode = U_UNSUPPORTED_ERROR;
3337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
3347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    length = loc.getKeywordValue("variableTop", value, LENGTHOF(value), errorCode);
3367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (U_FAILURE(errorCode)) {
3377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
3387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
3397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (length != 0) {
3417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        errorCode = U_UNSUPPORTED_ERROR;
3427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
3437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    // Parse known collation keywords, ignore others.
3457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (errorCode == U_STRING_NOT_TERMINATED_WARNING) {
3467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        errorCode = U_ZERO_ERROR;
3477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for (int32_t i = 0; i < LENGTHOF(collAttributes); ++i) {
3497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        length = loc.getKeywordValue(collAttributes[i].name, value, LENGTHOF(value), errorCode);
3507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
3517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            errorCode = U_ILLEGAL_ARGUMENT_ERROR;
3527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            return;
3537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        }
3547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        if (length == 0) { continue; }
3557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        for (int32_t j = 0;; ++j) {
3567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            if (j == LENGTHOF(collAttributeValues)) {
3577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                errorCode = U_ILLEGAL_ARGUMENT_ERROR;
3587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                return;
3597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            }
3607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            if (uprv_stricmp(value, collAttributeValues[j].name) == 0) {
3617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode);
3627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                break;
3637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            }
3647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        }
3657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    length = loc.getKeywordValue("colReorder", value, LENGTHOF(value), errorCode);
3677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
3687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
3697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
3707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (length != 0) {
3727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST];
3737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        int32_t codesLength = 0;
3747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        char *scriptName = value;
3757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        for (;;) {
3767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            if (codesLength == LENGTHOF(codes)) {
3777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                errorCode = U_ILLEGAL_ARGUMENT_ERROR;
3787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                return;
3797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            }
3807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            char *limit = scriptName;
3817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            char c;
3827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            while ((c = *limit) != 0 && c != '-') { ++limit; }
3837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            *limit = 0;
3847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            int32_t code;
3857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            if ((limit - scriptName) == 4) {
3867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                // Strict parsing, accept only 4-letter script codes, not long names.
3877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName);
3887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            } else {
3897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                code = getReorderCode(scriptName);
3907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            }
3917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            if (code < 0) {
3927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                errorCode = U_ILLEGAL_ARGUMENT_ERROR;
3937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                return;
3947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            }
3957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            codes[codesLength++] = code;
3967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            if (c == 0) { break; }
3977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            scriptName = limit + 1;
3987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        }
3997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        coll.setReorderCodes(codes, codesLength, errorCode);
4007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
4017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    length = loc.getKeywordValue("kv", value, LENGTHOF(value), errorCode);
4027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
4037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
4047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        return;
4057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
4067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if (length != 0) {
407        int32_t code = getReorderCode(value);
408        if (code < 0) {
409            errorCode = U_ILLEGAL_ARGUMENT_ERROR;
410            return;
411        }
412        coll.setMaxVariable((UColReorderCode)code, errorCode);
413    }
414    if (U_FAILURE(errorCode)) {
415        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
416    }
417}
418
419}  // namespace
420
421Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
422{
423    return createInstance(Locale::getDefault(), success);
424}
425
426Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
427                                   UErrorCode& status)
428{
429    if (U_FAILURE(status))
430        return 0;
431    if (desiredLocale.isBogus()) {
432        // Locale constructed from malformed locale ID or language tag.
433        status = U_ILLEGAL_ARGUMENT_ERROR;
434        return NULL;
435    }
436
437    Collator* coll;
438#if !UCONFIG_NO_SERVICE
439    if (hasService()) {
440        Locale actualLoc;
441        coll = (Collator*)gService->get(desiredLocale, &actualLoc, status);
442    } else
443#endif
444    {
445        coll = makeInstance(desiredLocale, status);
446    }
447    setAttributesFromKeywords(desiredLocale, *coll, status);
448    if (U_FAILURE(status)) {
449        delete coll;
450        return NULL;
451    }
452    return coll;
453}
454
455
456Collator* Collator::makeInstance(const Locale&  desiredLocale,
457                                         UErrorCode& status)
458{
459    Locale validLocale("");
460    const CollationTailoring *t =
461        CollationLoader::loadTailoring(desiredLocale, validLocale, status);
462    if (U_SUCCESS(status)) {
463        Collator *result = new RuleBasedCollator(t, validLocale);
464        if (result != NULL) {
465            return result;
466        }
467        status = U_MEMORY_ALLOCATION_ERROR;
468    }
469    if (t != NULL) {
470        t->deleteIfZeroRefCount();
471    }
472    return NULL;
473}
474
475Collator *
476Collator::safeClone() const {
477    return clone();
478}
479
480// implement deprecated, previously abstract method
481Collator::EComparisonResult Collator::compare(const UnicodeString& source,
482                                    const UnicodeString& target) const
483{
484    UErrorCode ec = U_ZERO_ERROR;
485    return (EComparisonResult)compare(source, target, ec);
486}
487
488// implement deprecated, previously abstract method
489Collator::EComparisonResult Collator::compare(const UnicodeString& source,
490                                    const UnicodeString& target,
491                                    int32_t length) const
492{
493    UErrorCode ec = U_ZERO_ERROR;
494    return (EComparisonResult)compare(source, target, length, ec);
495}
496
497// implement deprecated, previously abstract method
498Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
499                                    const UChar* target, int32_t targetLength)
500                                    const
501{
502    UErrorCode ec = U_ZERO_ERROR;
503    return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
504}
505
506UCollationResult Collator::compare(UCharIterator &/*sIter*/,
507                                   UCharIterator &/*tIter*/,
508                                   UErrorCode &status) const {
509    if(U_SUCCESS(status)) {
510        // Not implemented in the base class.
511        status = U_UNSUPPORTED_ERROR;
512    }
513    return UCOL_EQUAL;
514}
515
516UCollationResult Collator::compareUTF8(const StringPiece &source,
517                                       const StringPiece &target,
518                                       UErrorCode &status) const {
519    if(U_FAILURE(status)) {
520        return UCOL_EQUAL;
521    }
522    UCharIterator sIter, tIter;
523    uiter_setUTF8(&sIter, source.data(), source.length());
524    uiter_setUTF8(&tIter, target.data(), target.length());
525    return compare(sIter, tIter, status);
526}
527
528UBool Collator::equals(const UnicodeString& source,
529                       const UnicodeString& target) const
530{
531    UErrorCode ec = U_ZERO_ERROR;
532    return (compare(source, target, ec) == UCOL_EQUAL);
533}
534
535UBool Collator::greaterOrEqual(const UnicodeString& source,
536                               const UnicodeString& target) const
537{
538    UErrorCode ec = U_ZERO_ERROR;
539    return (compare(source, target, ec) != UCOL_LESS);
540}
541
542UBool Collator::greater(const UnicodeString& source,
543                        const UnicodeString& target) const
544{
545    UErrorCode ec = U_ZERO_ERROR;
546    return (compare(source, target, ec) == UCOL_GREATER);
547}
548
549// this API  ignores registered collators, since it returns an
550// array of indefinite lifetime
551const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
552{
553    UErrorCode status = U_ZERO_ERROR;
554    Locale *result = NULL;
555    count = 0;
556    if (isAvailableLocaleListInitialized(status))
557    {
558        result = availableLocaleList;
559        count = availableLocaleListCount;
560    }
561    return result;
562}
563
564UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
565                                        const Locale& displayLocale,
566                                        UnicodeString& name)
567{
568#if !UCONFIG_NO_SERVICE
569    if (hasService()) {
570        UnicodeString locNameStr;
571        LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
572        return gService->getDisplayName(locNameStr, name, displayLocale);
573    }
574#endif
575    return objectLocale.getDisplayName(displayLocale, name);
576}
577
578UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
579                                        UnicodeString& name)
580{
581    return getDisplayName(objectLocale, Locale::getDefault(), name);
582}
583
584/* This is useless information */
585/*void Collator::getVersion(UVersionInfo versionInfo) const
586{
587  if (versionInfo!=NULL)
588    uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
589}
590*/
591
592// UCollator protected constructor destructor ----------------------------
593
594/**
595* Default constructor.
596* Constructor is different from the old default Collator constructor.
597* The task for determing the default collation strength and normalization mode
598* is left to the child class.
599*/
600Collator::Collator()
601: UObject()
602{
603}
604
605/**
606* Constructor.
607* Empty constructor, does not handle the arguments.
608* This constructor is done for backward compatibility with 1.7 and 1.8.
609* The task for handling the argument collation strength and normalization
610* mode is left to the child class.
611* @param collationStrength collation strength
612* @param decompositionMode
613* @deprecated 2.4 use the default constructor instead
614*/
615Collator::Collator(UCollationStrength, UNormalizationMode )
616: UObject()
617{
618}
619
620Collator::~Collator()
621{
622}
623
624Collator::Collator(const Collator &other)
625    : UObject(other)
626{
627}
628
629UBool Collator::operator==(const Collator& other) const
630{
631    // Subclasses: Call this method and then add more specific checks.
632    return typeid(*this) == typeid(other);
633}
634
635UBool Collator::operator!=(const Collator& other) const
636{
637    return (UBool)!(*this == other);
638}
639
640int32_t U_EXPORT2 Collator::getBound(const uint8_t       *source,
641                           int32_t             sourceLength,
642                           UColBoundMode       boundType,
643                           uint32_t            noOfLevels,
644                           uint8_t             *result,
645                           int32_t             resultLength,
646                           UErrorCode          &status)
647{
648    return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
649}
650
651void
652Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
653}
654
655UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
656{
657    if(U_FAILURE(status)) {
658        return NULL;
659    }
660    // everything can be changed
661    return new UnicodeSet(0, 0x10FFFF);
662}
663
664// -------------------------------------
665
666#if !UCONFIG_NO_SERVICE
667URegistryKey U_EXPORT2
668Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
669{
670    if (U_SUCCESS(status)) {
671        // Set the collator locales while registering so that createInstance()
672        // need not guess whether the collator's locales are already set properly
673        // (as they are by the data loader).
674        toAdopt->setLocales(locale, locale, locale);
675        return getService()->registerInstance(toAdopt, locale, status);
676    }
677    return NULL;
678}
679
680// -------------------------------------
681
682class CFactory : public LocaleKeyFactory {
683private:
684    CollatorFactory* _delegate;
685    Hashtable* _ids;
686
687public:
688    CFactory(CollatorFactory* delegate, UErrorCode& status)
689        : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
690        , _delegate(delegate)
691        , _ids(NULL)
692    {
693        if (U_SUCCESS(status)) {
694            int32_t count = 0;
695            _ids = new Hashtable(status);
696            if (_ids) {
697                const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
698                for (int i = 0; i < count; ++i) {
699                    _ids->put(idlist[i], (void*)this, status);
700                    if (U_FAILURE(status)) {
701                        delete _ids;
702                        _ids = NULL;
703                        return;
704                    }
705                }
706            } else {
707                status = U_MEMORY_ALLOCATION_ERROR;
708            }
709        }
710    }
711
712    virtual ~CFactory();
713
714    virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
715
716protected:
717    virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
718    {
719        if (U_SUCCESS(status)) {
720            return _ids;
721        }
722        return NULL;
723    }
724
725    virtual UnicodeString&
726        getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
727};
728
729CFactory::~CFactory()
730{
731    delete _delegate;
732    delete _ids;
733}
734
735UObject*
736CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
737{
738    if (handlesKey(key, status)) {
739        const LocaleKey& lkey = (const LocaleKey&)key;
740        Locale validLoc;
741        lkey.currentLocale(validLoc);
742        return _delegate->createCollator(validLoc);
743    }
744    return NULL;
745}
746
747UnicodeString&
748CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
749{
750    if ((_coverage & 0x1) == 0) {
751        UErrorCode status = U_ZERO_ERROR;
752        const Hashtable* ids = getSupportedIDs(status);
753        if (ids && (ids->get(id) != NULL)) {
754            Locale loc;
755            LocaleUtility::initLocaleFromName(id, loc);
756            return _delegate->getDisplayName(loc, locale, result);
757        }
758    }
759    result.setToBogus();
760    return result;
761}
762
763URegistryKey U_EXPORT2
764Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
765{
766    if (U_SUCCESS(status)) {
767        CFactory* f = new CFactory(toAdopt, status);
768        if (f) {
769            return getService()->registerFactory(f, status);
770        }
771        status = U_MEMORY_ALLOCATION_ERROR;
772    }
773    return NULL;
774}
775
776// -------------------------------------
777
778UBool U_EXPORT2
779Collator::unregister(URegistryKey key, UErrorCode& status)
780{
781    if (U_SUCCESS(status)) {
782        if (hasService()) {
783            return gService->unregister(key, status);
784        }
785        status = U_ILLEGAL_ARGUMENT_ERROR;
786    }
787    return FALSE;
788}
789#endif /* UCONFIG_NO_SERVICE */
790
791class CollationLocaleListEnumeration : public StringEnumeration {
792private:
793    int32_t index;
794public:
795    static UClassID U_EXPORT2 getStaticClassID(void);
796    virtual UClassID getDynamicClassID(void) const;
797public:
798    CollationLocaleListEnumeration()
799        : index(0)
800    {
801        // The global variables should already be initialized.
802        //isAvailableLocaleListInitialized(status);
803    }
804
805    virtual ~CollationLocaleListEnumeration();
806
807    virtual StringEnumeration * clone() const
808    {
809        CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
810        if (result) {
811            result->index = index;
812        }
813        return result;
814    }
815
816    virtual int32_t count(UErrorCode &/*status*/) const {
817        return availableLocaleListCount;
818    }
819
820    virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
821        const char* result;
822        if(index < availableLocaleListCount) {
823            result = availableLocaleList[index++].getName();
824            if(resultLength != NULL) {
825                *resultLength = (int32_t)uprv_strlen(result);
826            }
827        } else {
828            if(resultLength != NULL) {
829                *resultLength = 0;
830            }
831            result = NULL;
832        }
833        return result;
834    }
835
836    virtual const UnicodeString* snext(UErrorCode& status) {
837        int32_t resultLength = 0;
838        const char *s = next(&resultLength, status);
839        return setChars(s, resultLength, status);
840    }
841
842    virtual void reset(UErrorCode& /*status*/) {
843        index = 0;
844    }
845};
846
847CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {}
848
849UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
850
851
852// -------------------------------------
853
854StringEnumeration* U_EXPORT2
855Collator::getAvailableLocales(void)
856{
857#if !UCONFIG_NO_SERVICE
858    if (hasService()) {
859        return getService()->getAvailableLocales();
860    }
861#endif /* UCONFIG_NO_SERVICE */
862    UErrorCode status = U_ZERO_ERROR;
863    if (isAvailableLocaleListInitialized(status)) {
864        return new CollationLocaleListEnumeration();
865    }
866    return NULL;
867}
868
869StringEnumeration* U_EXPORT2
870Collator::getKeywords(UErrorCode& status) {
871    // This is a wrapper over ucol_getKeywords
872    UEnumeration* uenum = ucol_getKeywords(&status);
873    if (U_FAILURE(status)) {
874        uenum_close(uenum);
875        return NULL;
876    }
877    return new UStringEnumeration(uenum);
878}
879
880StringEnumeration* U_EXPORT2
881Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
882    // This is a wrapper over ucol_getKeywordValues
883    UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
884    if (U_FAILURE(status)) {
885        uenum_close(uenum);
886        return NULL;
887    }
888    return new UStringEnumeration(uenum);
889}
890
891StringEnumeration* U_EXPORT2
892Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
893                                    UBool commonlyUsed, UErrorCode& status) {
894    // This is a wrapper over ucol_getKeywordValuesForLocale
895    UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(),
896                                                        commonlyUsed, &status);
897    if (U_FAILURE(status)) {
898        uenum_close(uenum);
899        return NULL;
900    }
901    return new UStringEnumeration(uenum);
902}
903
904Locale U_EXPORT2
905Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
906                                  UBool& isAvailable, UErrorCode& status) {
907    // This is a wrapper over ucol_getFunctionalEquivalent
908    char loc[ULOC_FULLNAME_CAPACITY];
909    /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
910                    keyword, locale.getName(), &isAvailable, &status);
911    if (U_FAILURE(status)) {
912        *loc = 0; // root
913    }
914    return Locale::createFromName(loc);
915}
916
917Collator::ECollationStrength
918Collator::getStrength(void) const {
919    UErrorCode intStatus = U_ZERO_ERROR;
920    return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus);
921}
922
923void
924Collator::setStrength(ECollationStrength newStrength) {
925    UErrorCode intStatus = U_ZERO_ERROR;
926    setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus);
927}
928
929Collator &
930Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) {
931    if (U_SUCCESS(errorCode)) {
932        errorCode = U_UNSUPPORTED_ERROR;
933    }
934    return *this;
935}
936
937UColReorderCode
938Collator::getMaxVariable() const {
939    return UCOL_REORDER_CODE_PUNCTUATION;
940}
941
942int32_t
943Collator::getReorderCodes(int32_t* /* dest*/,
944                          int32_t /* destCapacity*/,
945                          UErrorCode& status) const
946{
947    if (U_SUCCESS(status)) {
948        status = U_UNSUPPORTED_ERROR;
949    }
950    return 0;
951}
952
953void
954Collator::setReorderCodes(const int32_t* /* reorderCodes */,
955                          int32_t /* reorderCodesLength */,
956                          UErrorCode& status)
957{
958    if (U_SUCCESS(status)) {
959        status = U_UNSUPPORTED_ERROR;
960    }
961}
962
963int32_t
964Collator::getEquivalentReorderCodes(int32_t reorderCode,
965                                    int32_t *dest, int32_t capacity,
966                                    UErrorCode &errorCode) {
967    if(U_FAILURE(errorCode)) { return 0; }
968    if(capacity < 0 || (dest == NULL && capacity > 0)) {
969        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
970        return 0;
971    }
972    const CollationData *baseData = CollationRoot::getData(errorCode);
973    if(U_FAILURE(errorCode)) { return 0; }
974    return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode);
975}
976
977int32_t
978Collator::internalGetShortDefinitionString(const char * /*locale*/,
979                                                             char * /*buffer*/,
980                                                             int32_t /*capacity*/,
981                                                             UErrorCode &status) const {
982  if(U_SUCCESS(status)) {
983    status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */
984  }
985  return 0;
986}
987
988UCollationResult
989Collator::internalCompareUTF8(const char *left, int32_t leftLength,
990                              const char *right, int32_t rightLength,
991                              UErrorCode &errorCode) const {
992    if(U_FAILURE(errorCode)) { return UCOL_EQUAL; }
993    if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) {
994        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
995        return UCOL_EQUAL;
996    }
997    return compareUTF8(
998            StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength),
999            StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength),
1000            errorCode);
1001}
1002
1003int32_t
1004Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2],
1005                                  uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const {
1006    if (U_SUCCESS(errorCode)) {
1007        errorCode = U_UNSUPPORTED_ERROR;
1008    }
1009    return 0;
1010}
1011
1012// UCollator private data members ----------------------------------------
1013
1014/* This is useless information */
1015/*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
1016
1017// -------------------------------------
1018
1019U_NAMESPACE_END
1020
1021#endif /* #if !UCONFIG_NO_COLLATION */
1022
1023/* eof */
1024