michael@0: /* michael@0: ****************************************************************************** michael@0: * Copyright (C) 1996-2013, International Business Machines Corporation and michael@0: * others. All Rights Reserved. michael@0: ****************************************************************************** michael@0: */ michael@0: michael@0: /** michael@0: * File coll.cpp michael@0: * michael@0: * Created by: Helena Shih michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 2/5/97 aliu Modified createDefault to load collation data from michael@0: * binary files when possible. Added related methods michael@0: * createCollationFromFile, chopLocale, createPathName. michael@0: * 2/11/97 aliu Added methods addToCache, findInCache, which implement michael@0: * a Collation cache. Modified createDefault to look in michael@0: * cache first, and also to store newly created Collation michael@0: * objects in the cache. Modified to not use gLocPath. michael@0: * 2/12/97 aliu Modified to create objects from RuleBasedCollator cache. michael@0: * Moved cache out of Collation class. michael@0: * 2/13/97 aliu Moved several methods out of this class and into michael@0: * RuleBasedCollator, with modifications. Modified michael@0: * createDefault() to call new RuleBasedCollator(Locale&) michael@0: * constructor. General clean up and documentation. michael@0: * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy michael@0: * constructor. michael@0: * 05/06/97 helena Added memory allocation error detection. michael@0: * 05/08/97 helena Added createInstance(). michael@0: * 6/20/97 helena Java class name change. michael@0: * 04/23/99 stephen Removed EDecompositionMode, merged with michael@0: * Normalizer::EMode michael@0: * 11/23/9 srl Inlining of some critical functions michael@0: * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h) michael@0: */ michael@0: michael@0: #include "utypeinfo.h" // for 'typeid' to work michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_COLLATION michael@0: michael@0: #include "unicode/coll.h" michael@0: #include "unicode/tblcoll.h" michael@0: #include "ucol_imp.h" michael@0: #include "cstring.h" michael@0: #include "cmemory.h" michael@0: #include "umutex.h" michael@0: #include "servloc.h" michael@0: #include "uassert.h" michael@0: #include "ustrenum.h" michael@0: #include "uresimp.h" michael@0: #include "ucln_in.h" michael@0: michael@0: static icu::Locale* availableLocaleList = NULL; michael@0: static int32_t availableLocaleListCount; michael@0: static icu::ICULocaleService* gService = NULL; michael@0: static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER; michael@0: static icu::UInitOnce gAvailableLocaleListInitOnce; michael@0: michael@0: /** michael@0: * Release all static memory held by collator. michael@0: */ michael@0: U_CDECL_BEGIN michael@0: static UBool U_CALLCONV collator_cleanup(void) { michael@0: #if !UCONFIG_NO_SERVICE michael@0: if (gService) { michael@0: delete gService; michael@0: gService = NULL; michael@0: } michael@0: gServiceInitOnce.reset(); michael@0: #endif michael@0: if (availableLocaleList) { michael@0: delete []availableLocaleList; michael@0: availableLocaleList = NULL; michael@0: } michael@0: availableLocaleListCount = 0; michael@0: gAvailableLocaleListInitOnce.reset(); michael@0: return TRUE; michael@0: } michael@0: michael@0: U_CDECL_END michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: #if !UCONFIG_NO_SERVICE michael@0: michael@0: // ------------------------------------------ michael@0: // michael@0: // Registration michael@0: // michael@0: michael@0: //------------------------------------------- michael@0: michael@0: CollatorFactory::~CollatorFactory() {} michael@0: michael@0: //------------------------------------------- michael@0: michael@0: UBool michael@0: CollatorFactory::visible(void) const { michael@0: return TRUE; michael@0: } michael@0: michael@0: //------------------------------------------- michael@0: michael@0: UnicodeString& michael@0: CollatorFactory::getDisplayName(const Locale& objectLocale, michael@0: const Locale& displayLocale, michael@0: UnicodeString& result) michael@0: { michael@0: return objectLocale.getDisplayName(displayLocale, result); michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: michael@0: class ICUCollatorFactory : public ICUResourceBundleFactory { michael@0: public: michael@0: ICUCollatorFactory() : ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { } michael@0: virtual ~ICUCollatorFactory(); michael@0: protected: michael@0: virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const; michael@0: }; michael@0: michael@0: ICUCollatorFactory::~ICUCollatorFactory() {} michael@0: michael@0: UObject* michael@0: ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const { michael@0: if (handlesKey(key, status)) { michael@0: const LocaleKey& lkey = (const LocaleKey&)key; michael@0: Locale loc; michael@0: // make sure the requested locale is correct michael@0: // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey michael@0: // but for ICU rb resources we use the actual one since it will fallback again michael@0: lkey.canonicalLocale(loc); michael@0: michael@0: return Collator::makeInstance(loc, status); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: michael@0: class ICUCollatorService : public ICULocaleService { michael@0: public: michael@0: ICUCollatorService() michael@0: : ICULocaleService(UNICODE_STRING_SIMPLE("Collator")) michael@0: { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: registerFactory(new ICUCollatorFactory(), status); michael@0: } michael@0: michael@0: virtual ~ICUCollatorService(); michael@0: michael@0: virtual UObject* cloneInstance(UObject* instance) const { michael@0: return ((Collator*)instance)->clone(); michael@0: } michael@0: michael@0: virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const { michael@0: LocaleKey& lkey = (LocaleKey&)key; michael@0: if (actualID) { michael@0: // Ugly Hack Alert! We return an empty actualID to signal michael@0: // to callers that this is a default object, not a "real" michael@0: // service-created object. (TODO remove in 3.0) [aliu] michael@0: actualID->truncate(0); michael@0: } michael@0: Locale loc(""); michael@0: lkey.canonicalLocale(loc); michael@0: return Collator::makeInstance(loc, status); michael@0: } michael@0: michael@0: virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const { michael@0: UnicodeString ar; michael@0: if (actualReturn == NULL) { michael@0: actualReturn = &ar; michael@0: } michael@0: Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status); michael@0: // Ugly Hack Alert! If the actualReturn length is zero, this michael@0: // means we got a default object, not a "real" service-created michael@0: // object. We don't call setLocales() on a default object, michael@0: // because that will overwrite its correct built-in locale michael@0: // metadata (valid & actual) with our incorrect data (all we michael@0: // have is the requested locale). (TODO remove in 3.0) [aliu] michael@0: if (result && actualReturn->length() > 0) { michael@0: const LocaleKey& lkey = (const LocaleKey&)key; michael@0: Locale canonicalLocale(""); michael@0: Locale currentLocale(""); michael@0: michael@0: LocaleUtility::initLocaleFromName(*actualReturn, currentLocale); michael@0: result->setLocales(lkey.canonicalLocale(canonicalLocale), currentLocale, currentLocale); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: virtual UBool isDefault() const { michael@0: return countFactories() == 1; michael@0: } michael@0: }; michael@0: michael@0: ICUCollatorService::~ICUCollatorService() {} michael@0: michael@0: // ------------------------------------- michael@0: michael@0: static void U_CALLCONV initService() { michael@0: gService = new ICUCollatorService(); michael@0: ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); michael@0: } michael@0: michael@0: michael@0: static ICULocaleService* michael@0: getService(void) michael@0: { michael@0: umtx_initOnce(gServiceInitOnce, &initService); michael@0: return gService; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: michael@0: static inline UBool michael@0: hasService(void) michael@0: { michael@0: UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL); michael@0: return retVal; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: michael@0: UCollator* michael@0: Collator::createUCollator(const char *loc, michael@0: UErrorCode *status) michael@0: { michael@0: UCollator *result = 0; michael@0: if (status && U_SUCCESS(*status) && hasService()) { michael@0: Locale desiredLocale(loc); michael@0: Collator *col = (Collator*)gService->get(desiredLocale, *status); michael@0: RuleBasedCollator *rbc; michael@0: if (col && (rbc = dynamic_cast(col))) { michael@0: if (!rbc->dataIsOwned) { michael@0: result = ucol_safeClone(rbc->ucollator, NULL, NULL, status); michael@0: } else { michael@0: result = rbc->ucollator; michael@0: rbc->ucollator = NULL; // to prevent free on delete michael@0: } michael@0: } else { michael@0: // should go in a function- ucol_initDelegate(delegate) michael@0: result = (UCollator *)uprv_malloc(sizeof(UCollator)); michael@0: if(result == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: } else { michael@0: uprv_memset(result, 0, sizeof(UCollator)); michael@0: result->delegate = col; michael@0: result->freeOnClose = TRUE; // do free on close. michael@0: col = NULL; // to prevent free on delete. michael@0: } michael@0: } michael@0: delete col; michael@0: } michael@0: return result; michael@0: } michael@0: #endif /* UCONFIG_NO_SERVICE */ michael@0: michael@0: static void U_CALLCONV michael@0: initAvailableLocaleList(UErrorCode &status) { michael@0: U_ASSERT(availableLocaleListCount == 0); michael@0: U_ASSERT(availableLocaleList == NULL); michael@0: // for now, there is a hardcoded list, so just walk through that list and set it up. michael@0: UResourceBundle *index = NULL; michael@0: UResourceBundle installed; michael@0: int32_t i = 0; michael@0: michael@0: ures_initStackObject(&installed); michael@0: index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status); michael@0: ures_getByKey(index, "InstalledLocales", &installed, &status); michael@0: michael@0: if(U_SUCCESS(status)) { michael@0: availableLocaleListCount = ures_getSize(&installed); michael@0: availableLocaleList = new Locale[availableLocaleListCount]; michael@0: michael@0: if (availableLocaleList != NULL) { michael@0: ures_resetIterator(&installed); michael@0: while(ures_hasNext(&installed)) { michael@0: const char *tempKey = NULL; michael@0: ures_getNextString(&installed, NULL, &tempKey, &status); michael@0: availableLocaleList[i++] = Locale(tempKey); michael@0: } michael@0: } michael@0: U_ASSERT(availableLocaleListCount == i); michael@0: ures_close(&installed); michael@0: } michael@0: ures_close(index); michael@0: ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); michael@0: } michael@0: michael@0: static UBool isAvailableLocaleListInitialized(UErrorCode &status) { michael@0: umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status); michael@0: return U_SUCCESS(status); michael@0: } michael@0: michael@0: michael@0: // Collator public methods ----------------------------------------------- michael@0: michael@0: Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success) michael@0: { michael@0: return createInstance(Locale::getDefault(), success); michael@0: } michael@0: michael@0: Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale, michael@0: UErrorCode& status) michael@0: { michael@0: if (U_FAILURE(status)) michael@0: return 0; michael@0: michael@0: #if !UCONFIG_NO_SERVICE michael@0: if (hasService()) { michael@0: Locale actualLoc; michael@0: Collator *result = michael@0: (Collator*)gService->get(desiredLocale, &actualLoc, status); michael@0: michael@0: // Ugly Hack Alert! If the returned locale is empty (not root, michael@0: // but empty -- getName() == "") then that means the service michael@0: // returned a default object, not a "real" service object. In michael@0: // that case, the locale metadata (valid & actual) is setup michael@0: // correctly already, and we don't want to overwrite it. (TODO michael@0: // remove in 3.0) [aliu] michael@0: if (*actualLoc.getName() != 0) { michael@0: result->setLocales(desiredLocale, actualLoc, actualLoc); michael@0: } michael@0: return result; michael@0: } michael@0: #endif michael@0: return makeInstance(desiredLocale, status); michael@0: } michael@0: michael@0: michael@0: Collator* Collator::makeInstance(const Locale& desiredLocale, michael@0: UErrorCode& status) michael@0: { michael@0: // A bit of explanation is required here. Although in the current michael@0: // implementation michael@0: // Collator::createInstance() is just turning around and calling michael@0: // RuleBasedCollator(Locale&), this will not necessarily always be the michael@0: // case. For example, suppose we modify this code to handle a michael@0: // non-table-based Collator, such as that for Thai. In this case, michael@0: // createInstance() will have to be modified to somehow determine this fact michael@0: // (perhaps a field in the resource bundle). Then it can construct the michael@0: // non-table-based Collator in some other way, when it sees that it needs michael@0: // to. michael@0: // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS michael@0: // return a valid collation object, if the system is functioning properly. michael@0: // The reason is that it will fall back, use the default locale, and even michael@0: // use the built-in default collation rules. THEREFORE, createInstance() michael@0: // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN michael@0: // ADVANCE that the given locale's collation is properly implemented as a michael@0: // RuleBasedCollator. michael@0: // Currently, we don't do this...we always return a RuleBasedCollator, michael@0: // whether it is strictly correct to do so or not, without checking, because michael@0: // we currently have no way of checking. michael@0: michael@0: RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale, michael@0: status); michael@0: /* test for NULL */ michael@0: if (collation == 0) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: if (U_FAILURE(status)) michael@0: { michael@0: delete collation; michael@0: collation = 0; michael@0: } michael@0: return collation; michael@0: } michael@0: michael@0: #ifdef U_USE_COLLATION_OBSOLETE_2_6 michael@0: // !!! dlf the following is obsolete, ignore registration for this michael@0: michael@0: Collator * michael@0: Collator::createInstance(const Locale &loc, michael@0: UVersionInfo version, michael@0: UErrorCode &status) michael@0: { michael@0: Collator *collator; michael@0: UVersionInfo info; michael@0: michael@0: collator=new RuleBasedCollator(loc, status); michael@0: /* test for NULL */ michael@0: if (collator == 0) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: michael@0: if(U_SUCCESS(status)) { michael@0: collator->getVersion(info); michael@0: if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) { michael@0: delete collator; michael@0: status=U_MISSING_RESOURCE_ERROR; michael@0: return 0; michael@0: } michael@0: } michael@0: return collator; michael@0: } michael@0: #endif michael@0: michael@0: Collator * michael@0: Collator::safeClone() const { michael@0: return clone(); michael@0: } michael@0: michael@0: // implement deprecated, previously abstract method michael@0: Collator::EComparisonResult Collator::compare(const UnicodeString& source, michael@0: const UnicodeString& target) const michael@0: { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: return (EComparisonResult)compare(source, target, ec); michael@0: } michael@0: michael@0: // implement deprecated, previously abstract method michael@0: Collator::EComparisonResult Collator::compare(const UnicodeString& source, michael@0: const UnicodeString& target, michael@0: int32_t length) const michael@0: { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: return (EComparisonResult)compare(source, target, length, ec); michael@0: } michael@0: michael@0: // implement deprecated, previously abstract method michael@0: Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength, michael@0: const UChar* target, int32_t targetLength) michael@0: const michael@0: { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec); michael@0: } michael@0: michael@0: UCollationResult Collator::compare(UCharIterator &/*sIter*/, michael@0: UCharIterator &/*tIter*/, michael@0: UErrorCode &status) const { michael@0: if(U_SUCCESS(status)) { michael@0: // Not implemented in the base class. michael@0: status = U_UNSUPPORTED_ERROR; michael@0: } michael@0: return UCOL_EQUAL; michael@0: } michael@0: michael@0: UCollationResult Collator::compareUTF8(const StringPiece &source, michael@0: const StringPiece &target, michael@0: UErrorCode &status) const { michael@0: if(U_FAILURE(status)) { michael@0: return UCOL_EQUAL; michael@0: } michael@0: UCharIterator sIter, tIter; michael@0: uiter_setUTF8(&sIter, source.data(), source.length()); michael@0: uiter_setUTF8(&tIter, target.data(), target.length()); michael@0: return compare(sIter, tIter, status); michael@0: } michael@0: michael@0: UBool Collator::equals(const UnicodeString& source, michael@0: const UnicodeString& target) const michael@0: { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: return (compare(source, target, ec) == UCOL_EQUAL); michael@0: } michael@0: michael@0: UBool Collator::greaterOrEqual(const UnicodeString& source, michael@0: const UnicodeString& target) const michael@0: { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: return (compare(source, target, ec) != UCOL_LESS); michael@0: } michael@0: michael@0: UBool Collator::greater(const UnicodeString& source, michael@0: const UnicodeString& target) const michael@0: { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: return (compare(source, target, ec) == UCOL_GREATER); michael@0: } michael@0: michael@0: // this API ignores registered collators, since it returns an michael@0: // array of indefinite lifetime michael@0: const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count) michael@0: { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: Locale *result = NULL; michael@0: count = 0; michael@0: if (isAvailableLocaleListInitialized(status)) michael@0: { michael@0: result = availableLocaleList; michael@0: count = availableLocaleListCount; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, michael@0: const Locale& displayLocale, michael@0: UnicodeString& name) michael@0: { michael@0: #if !UCONFIG_NO_SERVICE michael@0: if (hasService()) { michael@0: UnicodeString locNameStr; michael@0: LocaleUtility::initNameFromLocale(objectLocale, locNameStr); michael@0: return gService->getDisplayName(locNameStr, name, displayLocale); michael@0: } michael@0: #endif michael@0: return objectLocale.getDisplayName(displayLocale, name); michael@0: } michael@0: michael@0: UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, michael@0: UnicodeString& name) michael@0: { michael@0: return getDisplayName(objectLocale, Locale::getDefault(), name); michael@0: } michael@0: michael@0: /* This is useless information */ michael@0: /*void Collator::getVersion(UVersionInfo versionInfo) const michael@0: { michael@0: if (versionInfo!=NULL) michael@0: uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH); michael@0: } michael@0: */ michael@0: michael@0: // UCollator protected constructor destructor ---------------------------- michael@0: michael@0: /** michael@0: * Default constructor. michael@0: * Constructor is different from the old default Collator constructor. michael@0: * The task for determing the default collation strength and normalization mode michael@0: * is left to the child class. michael@0: */ michael@0: Collator::Collator() michael@0: : UObject() michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Constructor. michael@0: * Empty constructor, does not handle the arguments. michael@0: * This constructor is done for backward compatibility with 1.7 and 1.8. michael@0: * The task for handling the argument collation strength and normalization michael@0: * mode is left to the child class. michael@0: * @param collationStrength collation strength michael@0: * @param decompositionMode michael@0: * @deprecated 2.4 use the default constructor instead michael@0: */ michael@0: Collator::Collator(UCollationStrength, UNormalizationMode ) michael@0: : UObject() michael@0: { michael@0: } michael@0: michael@0: Collator::~Collator() michael@0: { michael@0: } michael@0: michael@0: Collator::Collator(const Collator &other) michael@0: : UObject(other) michael@0: { michael@0: } michael@0: michael@0: UBool Collator::operator==(const Collator& other) const michael@0: { michael@0: // Subclasses: Call this method and then add more specific checks. michael@0: return typeid(*this) == typeid(other); michael@0: } michael@0: michael@0: UBool Collator::operator!=(const Collator& other) const michael@0: { michael@0: return (UBool)!(*this == other); michael@0: } michael@0: michael@0: int32_t U_EXPORT2 Collator::getBound(const uint8_t *source, michael@0: int32_t sourceLength, michael@0: UColBoundMode boundType, michael@0: uint32_t noOfLevels, michael@0: uint8_t *result, michael@0: int32_t resultLength, michael@0: UErrorCode &status) michael@0: { michael@0: return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status); michael@0: } michael@0: michael@0: void michael@0: Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) { michael@0: } michael@0: michael@0: UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const michael@0: { michael@0: if(U_FAILURE(status)) { michael@0: return NULL; michael@0: } michael@0: // everything can be changed michael@0: return new UnicodeSet(0, 0x10FFFF); michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: michael@0: #if !UCONFIG_NO_SERVICE michael@0: URegistryKey U_EXPORT2 michael@0: Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status) michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: return getService()->registerInstance(toAdopt, locale, status); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: michael@0: class CFactory : public LocaleKeyFactory { michael@0: private: michael@0: CollatorFactory* _delegate; michael@0: Hashtable* _ids; michael@0: michael@0: public: michael@0: CFactory(CollatorFactory* delegate, UErrorCode& status) michael@0: : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE) michael@0: , _delegate(delegate) michael@0: , _ids(NULL) michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: int32_t count = 0; michael@0: _ids = new Hashtable(status); michael@0: if (_ids) { michael@0: const UnicodeString * idlist = _delegate->getSupportedIDs(count, status); michael@0: for (int i = 0; i < count; ++i) { michael@0: _ids->put(idlist[i], (void*)this, status); michael@0: if (U_FAILURE(status)) { michael@0: delete _ids; michael@0: _ids = NULL; michael@0: return; michael@0: } michael@0: } michael@0: } else { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: } michael@0: } michael@0: } michael@0: michael@0: virtual ~CFactory(); michael@0: michael@0: virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const; michael@0: michael@0: protected: michael@0: virtual const Hashtable* getSupportedIDs(UErrorCode& status) const michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: return _ids; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: virtual UnicodeString& michael@0: getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const; michael@0: }; michael@0: michael@0: CFactory::~CFactory() michael@0: { michael@0: delete _delegate; michael@0: delete _ids; michael@0: } michael@0: michael@0: UObject* michael@0: CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const michael@0: { michael@0: if (handlesKey(key, status)) { michael@0: const LocaleKey& lkey = (const LocaleKey&)key; michael@0: Locale validLoc; michael@0: lkey.currentLocale(validLoc); michael@0: return _delegate->createCollator(validLoc); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: UnicodeString& michael@0: CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const michael@0: { michael@0: if ((_coverage & 0x1) == 0) { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: const Hashtable* ids = getSupportedIDs(status); michael@0: if (ids && (ids->get(id) != NULL)) { michael@0: Locale loc; michael@0: LocaleUtility::initLocaleFromName(id, loc); michael@0: return _delegate->getDisplayName(loc, locale, result); michael@0: } michael@0: } michael@0: result.setToBogus(); michael@0: return result; michael@0: } michael@0: michael@0: URegistryKey U_EXPORT2 michael@0: Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status) michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: CFactory* f = new CFactory(toAdopt, status); michael@0: if (f) { michael@0: return getService()->registerFactory(f, status); michael@0: } michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: michael@0: UBool U_EXPORT2 michael@0: Collator::unregister(URegistryKey key, UErrorCode& status) michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: if (hasService()) { michael@0: return gService->unregister(key, status); michael@0: } michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: } michael@0: return FALSE; michael@0: } michael@0: #endif /* UCONFIG_NO_SERVICE */ michael@0: michael@0: class CollationLocaleListEnumeration : public StringEnumeration { michael@0: private: michael@0: int32_t index; michael@0: public: michael@0: static UClassID U_EXPORT2 getStaticClassID(void); michael@0: virtual UClassID getDynamicClassID(void) const; michael@0: public: michael@0: CollationLocaleListEnumeration() michael@0: : index(0) michael@0: { michael@0: // The global variables should already be initialized. michael@0: //isAvailableLocaleListInitialized(status); michael@0: } michael@0: michael@0: virtual ~CollationLocaleListEnumeration(); michael@0: michael@0: virtual StringEnumeration * clone() const michael@0: { michael@0: CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration(); michael@0: if (result) { michael@0: result->index = index; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: virtual int32_t count(UErrorCode &/*status*/) const { michael@0: return availableLocaleListCount; michael@0: } michael@0: michael@0: virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) { michael@0: const char* result; michael@0: if(index < availableLocaleListCount) { michael@0: result = availableLocaleList[index++].getName(); michael@0: if(resultLength != NULL) { michael@0: *resultLength = (int32_t)uprv_strlen(result); michael@0: } michael@0: } else { michael@0: if(resultLength != NULL) { michael@0: *resultLength = 0; michael@0: } michael@0: result = NULL; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: virtual const UnicodeString* snext(UErrorCode& status) { michael@0: int32_t resultLength = 0; michael@0: const char *s = next(&resultLength, status); michael@0: return setChars(s, resultLength, status); michael@0: } michael@0: michael@0: virtual void reset(UErrorCode& /*status*/) { michael@0: index = 0; michael@0: } michael@0: }; michael@0: michael@0: CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {} michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration) michael@0: michael@0: michael@0: // ------------------------------------- michael@0: michael@0: StringEnumeration* U_EXPORT2 michael@0: Collator::getAvailableLocales(void) michael@0: { michael@0: #if !UCONFIG_NO_SERVICE michael@0: if (hasService()) { michael@0: return getService()->getAvailableLocales(); michael@0: } michael@0: #endif /* UCONFIG_NO_SERVICE */ michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: if (isAvailableLocaleListInitialized(status)) { michael@0: return new CollationLocaleListEnumeration(); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: StringEnumeration* U_EXPORT2 michael@0: Collator::getKeywords(UErrorCode& status) { michael@0: // This is a wrapper over ucol_getKeywords michael@0: UEnumeration* uenum = ucol_getKeywords(&status); michael@0: if (U_FAILURE(status)) { michael@0: uenum_close(uenum); michael@0: return NULL; michael@0: } michael@0: return new UStringEnumeration(uenum); michael@0: } michael@0: michael@0: StringEnumeration* U_EXPORT2 michael@0: Collator::getKeywordValues(const char *keyword, UErrorCode& status) { michael@0: // This is a wrapper over ucol_getKeywordValues michael@0: UEnumeration* uenum = ucol_getKeywordValues(keyword, &status); michael@0: if (U_FAILURE(status)) { michael@0: uenum_close(uenum); michael@0: return NULL; michael@0: } michael@0: return new UStringEnumeration(uenum); michael@0: } michael@0: michael@0: StringEnumeration* U_EXPORT2 michael@0: Collator::getKeywordValuesForLocale(const char* key, const Locale& locale, michael@0: UBool commonlyUsed, UErrorCode& status) { michael@0: // This is a wrapper over ucol_getKeywordValuesForLocale michael@0: UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(), michael@0: commonlyUsed, &status); michael@0: if (U_FAILURE(status)) { michael@0: uenum_close(uenum); michael@0: return NULL; michael@0: } michael@0: return new UStringEnumeration(uenum); michael@0: } michael@0: michael@0: Locale U_EXPORT2 michael@0: Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale, michael@0: UBool& isAvailable, UErrorCode& status) { michael@0: // This is a wrapper over ucol_getFunctionalEquivalent michael@0: char loc[ULOC_FULLNAME_CAPACITY]; michael@0: /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc), michael@0: keyword, locale.getName(), &isAvailable, &status); michael@0: if (U_FAILURE(status)) { michael@0: *loc = 0; // root michael@0: } michael@0: return Locale::createFromName(loc); michael@0: } michael@0: michael@0: Collator::ECollationStrength michael@0: Collator::getStrength(void) const { michael@0: UErrorCode intStatus = U_ZERO_ERROR; michael@0: return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus); michael@0: } michael@0: michael@0: void michael@0: Collator::setStrength(ECollationStrength newStrength) { michael@0: UErrorCode intStatus = U_ZERO_ERROR; michael@0: setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus); michael@0: } michael@0: michael@0: int32_t michael@0: Collator::getReorderCodes(int32_t* /* dest*/, michael@0: int32_t /* destCapacity*/, michael@0: UErrorCode& status) const michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: status = U_UNSUPPORTED_ERROR; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: void michael@0: Collator::setReorderCodes(const int32_t* /* reorderCodes */, michael@0: int32_t /* reorderCodesLength */, michael@0: UErrorCode& status) michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: status = U_UNSUPPORTED_ERROR; michael@0: } michael@0: } michael@0: michael@0: int32_t U_EXPORT2 michael@0: Collator::getEquivalentReorderCodes(int32_t /* reorderCode */, michael@0: int32_t* /* dest */, michael@0: int32_t /* destCapacity */, michael@0: UErrorCode& status) michael@0: { michael@0: if (U_SUCCESS(status)) { michael@0: status = U_UNSUPPORTED_ERROR; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: int32_t michael@0: Collator::internalGetShortDefinitionString(const char * /*locale*/, michael@0: char * /*buffer*/, michael@0: int32_t /*capacity*/, michael@0: UErrorCode &status) const { michael@0: if(U_SUCCESS(status)) { michael@0: status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */ michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: // UCollator private data members ---------------------------------------- michael@0: michael@0: /* This is useless information */ michael@0: /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/ michael@0: michael@0: // ------------------------------------- michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: #endif /* #if !UCONFIG_NO_COLLATION */ michael@0: michael@0: /* eof */