2 ******************************************************************************
3 * Copyright (C) 1996-2004, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 ******************************************************************************
11 * Created by: Helena Shih
13 * Modification History:
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
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
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)
40 #include "unicode/utypes.h"
42 #if !UCONFIG_NO_COLLATION
44 #include "unicode/coll.h"
45 #include "unicode/tblcoll.h"
54 #if !UCONFIG_NO_SERVICE
57 static ICULocaleService
* gService
= NULL
;
59 * Release all static memory held by collator.
62 static UBool U_CALLCONV
collator_cleanup(void) {
73 // ------------------------------------------
78 //-------------------------------------------
80 CollatorFactory::~CollatorFactory() {}
82 //-------------------------------------------
85 CollatorFactory::visible(void) const {
89 //-------------------------------------------
92 CollatorFactory::getDisplayName(const Locale
& objectLocale
,
93 const Locale
& displayLocale
,
94 UnicodeString
& result
)
96 return objectLocale
.getDisplayName(displayLocale
, result
);
99 // -------------------------------------
101 class ICUCollatorFactory
: public ICUResourceBundleFactory
{
103 ICUCollatorFactory(): ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL
, (char*)NULL
)) { }
105 virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const;
109 ICUCollatorFactory::create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& status
) const {
110 if (handlesKey(key
, status
)) {
111 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
113 // make sure the requested locale is correct
114 // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
115 // but for ICU rb resources we use the actual one since it will fallback again
116 lkey
.canonicalLocale(loc
);
118 return Collator::makeInstance(loc
, status
);
123 // -------------------------------------
125 class ICUCollatorService
: public ICULocaleService
{
128 : ICULocaleService("Collator")
130 UErrorCode status
= U_ZERO_ERROR
;
131 registerFactory(new ICUCollatorFactory(), status
);
134 virtual UObject
* cloneInstance(UObject
* instance
) const {
135 return ((Collator
*)instance
)->clone();
138 virtual UObject
* handleDefault(const ICUServiceKey
& key
, UnicodeString
* actualID
, UErrorCode
& status
) const {
139 LocaleKey
& lkey
= (LocaleKey
&)key
;
141 // Ugly Hack Alert! We return an empty actualID to signal
142 // to callers that this is a default object, not a "real"
143 // service-created object. (TODO remove in 3.0) [aliu]
144 actualID
->truncate(0);
147 lkey
.canonicalLocale(loc
);
148 return Collator::makeInstance(loc
, status
);
151 virtual UObject
* getKey(ICUServiceKey
& key
, UnicodeString
* actualReturn
, UErrorCode
& status
) const {
153 if (actualReturn
== NULL
) {
156 Collator
* result
= (Collator
*)ICULocaleService::getKey(key
, actualReturn
, status
);
157 // Ugly Hack Alert! If the actualReturn length is zero, this
158 // means we got a default object, not a "real" service-created
159 // object. We don't call setLocales() on a default object,
160 // because that will overwrite its correct built-in locale
161 // metadata (valid & actual) with our incorrect data (all we
162 // have is the requested locale). (TODO remove in 3.0) [aliu]
163 if (result
&& actualReturn
->length() > 0) {
164 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
165 Locale
canonicalLocale("");
166 Locale
currentLocale("");
168 result
->setLocales(lkey
.canonicalLocale(canonicalLocale
),
169 LocaleUtility::initLocaleFromName(*actualReturn
, currentLocale
));
174 virtual UBool
isDefault() const {
175 return countFactories() == 1;
179 // -------------------------------------
181 class ICUCollatorService
;
183 static ICULocaleService
*
189 needInit
= (UBool
)(gService
== NULL
);
192 ICULocaleService
*newservice
= new ICUCollatorService();
195 if(gService
== NULL
) {
196 gService
= newservice
;
204 #if !UCONFIG_NO_SERVICE
205 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR
, collator_cleanup
);
212 // -------------------------------------
218 return gService
!= NULL
;
221 // -------------------------------------
224 Collator::createUCollator(const char *loc
,
227 UCollator
*result
= 0;
228 if (status
&& U_SUCCESS(*status
) && hasService()) {
229 Locale
desiredLocale(loc
);
230 Collator
*col
= (Collator
*)gService
->get(desiredLocale
, *status
);
231 if (col
&& col
->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
232 RuleBasedCollator
*rbc
= (RuleBasedCollator
*)col
;
233 if (!rbc
->dataIsOwned
) {
234 result
= ucol_safeClone(rbc
->ucollator
, NULL
, NULL
, status
);
236 result
= rbc
->ucollator
;
237 rbc
->ucollator
= NULL
; // to prevent free on delete
244 #endif /* UCONFIG_NO_SERVICE */
246 // Collator public methods -----------------------------------------------
248 Collator
* U_EXPORT2
Collator::createInstance(UErrorCode
& success
)
250 return createInstance(Locale::getDefault(), success
);
253 Collator
* U_EXPORT2
Collator::createInstance(const Locale
& desiredLocale
,
256 if (U_FAILURE(status
))
259 #if !UCONFIG_NO_SERVICE
263 (Collator
*)gService
->get(desiredLocale
, &actualLoc
, status
);
264 // Ugly Hack Alert! If the returned locale is empty (not root,
265 // but empty -- getName() == "") then that means the service
266 // returned a default object, not a "real" service object. In
267 // that case, the locale metadata (valid & actual) is setup
268 // correctly already, and we don't want to overwrite it. (TODO
269 // remove in 3.0) [aliu]
270 if (*actualLoc
.getName() != 0) {
271 result
->setLocales(desiredLocale
, actualLoc
);
276 return makeInstance(desiredLocale
, status
);
280 Collator
* Collator::makeInstance(const Locale
& desiredLocale
,
283 // A bit of explanation is required here. Although in the current
285 // Collator::createInstance() is just turning around and calling
286 // RuleBasedCollator(Locale&), this will not necessarily always be the
287 // case. For example, suppose we modify this code to handle a
288 // non-table-based Collator, such as that for Thai. In this case,
289 // createInstance() will have to be modified to somehow determine this fact
290 // (perhaps a field in the resource bundle). Then it can construct the
291 // non-table-based Collator in some other way, when it sees that it needs
293 // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS
294 // return a valid collation object, if the system if functioning properly.
295 // The reason is that it will fall back, use the default locale, and even
296 // use the built-in default collation rules. THEREFORE, createInstance()
297 // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN
298 // ADVANCE that the given locale's collation is properly implemented as a
299 // RuleBasedCollator.
300 // Currently, we don't do this...we always return a RuleBasedCollator,
301 // whether it is strictly correct to do so or not, without checking, because
302 // we currently have no way of checking.
304 RuleBasedCollator
* collation
= new RuleBasedCollator(desiredLocale
,
307 if (collation
== 0) {
308 status
= U_MEMORY_ALLOCATION_ERROR
;
311 if (U_FAILURE(status
))
319 #ifdef U_USE_COLLATION_OBSOLETE_2_6
320 // !!! dlf the following is obsolete, ignore registration for this
323 Collator::createInstance(const Locale
&loc
,
324 UVersionInfo version
,
330 collator
=new RuleBasedCollator(loc
, status
);
333 status
= U_MEMORY_ALLOCATION_ERROR
;
337 if(U_SUCCESS(status
)) {
338 collator
->getVersion(info
);
339 if(0!=uprv_memcmp(version
, info
, sizeof(UVersionInfo
))) {
341 status
=U_MISSING_RESOURCE_ERROR
;
349 // implement deprecated, previously abstract method
350 Collator::EComparisonResult
Collator::compare(const UnicodeString
& source
,
351 const UnicodeString
& target
) const
353 UErrorCode ec
= U_ZERO_ERROR
;
354 return (Collator::EComparisonResult
)compare(source
, target
, ec
);
357 // implement deprecated, previously abstract method
358 Collator::EComparisonResult
Collator::compare(const UnicodeString
& source
,
359 const UnicodeString
& target
,
360 int32_t length
) const
362 UErrorCode ec
= U_ZERO_ERROR
;
363 return (Collator::EComparisonResult
)compare(source
, target
, length
, ec
);
366 // implement deprecated, previously abstract method
367 Collator::EComparisonResult
Collator::compare(const UChar
* source
, int32_t sourceLength
,
368 const UChar
* target
, int32_t targetLength
)
371 UErrorCode ec
= U_ZERO_ERROR
;
372 return (Collator::EComparisonResult
)compare(source
, sourceLength
, target
, targetLength
, ec
);
375 UBool
Collator::equals(const UnicodeString
& source
,
376 const UnicodeString
& target
) const
378 UErrorCode ec
= U_ZERO_ERROR
;
379 return (compare(source
, target
, ec
) == UCOL_EQUAL
);
382 UBool
Collator::greaterOrEqual(const UnicodeString
& source
,
383 const UnicodeString
& target
) const
385 UErrorCode ec
= U_ZERO_ERROR
;
386 return (compare(source
, target
, ec
) != UCOL_LESS
);
389 UBool
Collator::greater(const UnicodeString
& source
,
390 const UnicodeString
& target
) const
392 UErrorCode ec
= U_ZERO_ERROR
;
393 return (compare(source
, target
, ec
) == UCOL_GREATER
);
396 // this API ignores registered collators, since it returns an
397 // array of indefinite lifetime
398 const Locale
* U_EXPORT2
Collator::getAvailableLocales(int32_t& count
)
400 return Locale::getAvailableLocales(count
);
403 UnicodeString
& U_EXPORT2
Collator::getDisplayName(const Locale
& objectLocale
,
404 const Locale
& displayLocale
,
407 #if !UCONFIG_NO_SERVICE
409 return gService
->getDisplayName(objectLocale
.getName(), name
, displayLocale
);
412 return objectLocale
.getDisplayName(displayLocale
, name
);
415 UnicodeString
& U_EXPORT2
Collator::getDisplayName(const Locale
& objectLocale
,
418 return getDisplayName(objectLocale
, Locale::getDefault(), name
);
421 /* This is useless information */
422 /*void Collator::getVersion(UVersionInfo versionInfo) const
424 if (versionInfo!=NULL)
425 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
429 // UCollator protected constructor destructor ----------------------------
432 * Default constructor.
433 * Constructor is different from the old default Collator constructor.
434 * The task for determing the default collation strength and normalization mode
435 * is left to the child class.
444 * Empty constructor, does not handle the arguments.
445 * This constructor is done for backward compatibility with 1.7 and 1.8.
446 * The task for handling the argument collation strength and normalization
447 * mode is left to the child class.
448 * @param collationStrength collation strength
449 * @param decompositionMode
450 * @deprecated 2.4 use the default constructor instead
452 Collator::Collator(UCollationStrength
, UNormalizationMode
)
457 Collator::~Collator()
461 Collator::Collator(const Collator
&other
)
466 UBool
Collator::operator==(const Collator
& other
) const
468 return (UBool
)(this == &other
);
471 UBool
Collator::operator!=(const Collator
& other
) const
473 return (UBool
)!(*this == other
);
476 int32_t U_EXPORT2
Collator::getBound(const uint8_t *source
,
477 int32_t sourceLength
,
478 UColBoundMode boundType
,
481 int32_t resultLength
,
484 return ucol_getBound(source
, sourceLength
, boundType
, noOfLevels
, result
, resultLength
, &status
);
488 Collator::setLocales(const Locale
& /* requestedLocale */, const Locale
& /* validLocale */) {
491 UnicodeSet
*Collator::getTailoredSet(UErrorCode
&status
) const
493 if(U_FAILURE(status
)) {
496 // everything can be changed
497 return new UnicodeSet(0, 0x10FFFF);
500 // -------------------------------------
502 #if !UCONFIG_NO_SERVICE
503 URegistryKey U_EXPORT2
504 Collator::registerInstance(Collator
* toAdopt
, const Locale
& locale
, UErrorCode
& status
)
506 if (U_SUCCESS(status
)) {
507 return getService()->registerInstance(toAdopt
, locale
, status
);
512 // -------------------------------------
514 class CFactory
: public LocaleKeyFactory
{
516 CollatorFactory
* _delegate
;
520 CFactory(CollatorFactory
* delegate
, UErrorCode
& status
)
521 : LocaleKeyFactory(delegate
->visible() ? VISIBLE
: INVISIBLE
)
522 , _delegate(delegate
)
525 if (U_SUCCESS(status
)) {
527 _ids
= new Hashtable(status
);
529 const UnicodeString
* idlist
= _delegate
->getSupportedIDs(count
, status
);
530 for (int i
= 0; i
< count
; ++i
) {
531 _ids
->put(idlist
[i
], (void*)this, status
);
532 if (U_FAILURE(status
)) {
539 status
= U_MEMORY_ALLOCATION_ERROR
;
550 virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const;
553 virtual const Hashtable
* getSupportedIDs(UErrorCode
& status
) const
555 if (U_SUCCESS(status
)) {
561 virtual UnicodeString
&
562 getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const;
566 CFactory::create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& status
) const
568 if (handlesKey(key
, status
)) {
569 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
571 lkey
.currentLocale(validLoc
);
572 return _delegate
->createCollator(validLoc
);
578 CFactory::getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const
580 if ((_coverage
& 0x1) == 0) {
581 UErrorCode status
= U_ZERO_ERROR
;
582 const Hashtable
* ids
= getSupportedIDs(status
);
583 if (ids
&& (ids
->get(id
) != NULL
)) {
585 LocaleUtility::initLocaleFromName(id
, loc
);
586 return _delegate
->getDisplayName(loc
, locale
, result
);
593 URegistryKey U_EXPORT2
594 Collator::registerFactory(CollatorFactory
* toAdopt
, UErrorCode
& status
)
596 if (U_SUCCESS(status
)) {
597 CFactory
* f
= new CFactory(toAdopt
, status
);
599 return getService()->registerFactory(f
, status
);
601 status
= U_MEMORY_ALLOCATION_ERROR
;
606 // -------------------------------------
609 Collator::unregister(URegistryKey key
, UErrorCode
& status
)
611 if (U_SUCCESS(status
)) {
613 return gService
->unregister(key
, status
);
615 status
= U_ILLEGAL_ARGUMENT_ERROR
;
620 // -------------------------------------
622 StringEnumeration
* U_EXPORT2
623 Collator::getAvailableLocales(void)
625 return getService()->getAvailableLocales();
627 #endif /* UCONFIG_NO_SERVICE */
629 StringEnumeration
* U_EXPORT2
630 Collator::getKeywords(UErrorCode
& status
) {
631 // This is a wrapper over ucol_getKeywords
632 UEnumeration
* uenum
= ucol_getKeywords(&status
);
633 if (U_FAILURE(status
)) {
637 return new UStringEnumeration(uenum
);
640 StringEnumeration
* U_EXPORT2
641 Collator::getKeywordValues(const char *keyword
, UErrorCode
& status
) {
642 // This is a wrapper over ucol_getKeywordValues
643 UEnumeration
* uenum
= ucol_getKeywordValues(keyword
, &status
);
644 if (U_FAILURE(status
)) {
648 return new UStringEnumeration(uenum
);
652 Collator::getFunctionalEquivalent(const char* keyword
, const Locale
& locale
,
653 UBool
& isAvailable
, UErrorCode
& status
) {
654 // This is a wrapper over ucol_getFunctionalEquivalent
655 char loc
[ULOC_FULLNAME_CAPACITY
];
656 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc
, sizeof(loc
),
657 keyword
, locale
.getName(), &isAvailable
, &status
);
658 if (U_FAILURE(status
)) {
661 return Locale::createFromName(loc
);
664 // UCollator private data members ----------------------------------------
666 /* This is useless information */
667 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
669 // -------------------------------------
673 #endif /* #if !UCONFIG_NO_COLLATION */