2 ******************************************************************************
3 * Copyright (C) 1996-2005, 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
, -1, US_INV
)) { }
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(UNICODE_STRING_SIMPLE("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 UnicodeString locNameStr
;
410 LocaleUtility::initNameFromLocale(objectLocale
, locNameStr
);
411 return gService
->getDisplayName(locNameStr
, name
, displayLocale
);
414 return objectLocale
.getDisplayName(displayLocale
, name
);
417 UnicodeString
& U_EXPORT2
Collator::getDisplayName(const Locale
& objectLocale
,
420 return getDisplayName(objectLocale
, Locale::getDefault(), name
);
423 /* This is useless information */
424 /*void Collator::getVersion(UVersionInfo versionInfo) const
426 if (versionInfo!=NULL)
427 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
431 // UCollator protected constructor destructor ----------------------------
434 * Default constructor.
435 * Constructor is different from the old default Collator constructor.
436 * The task for determing the default collation strength and normalization mode
437 * is left to the child class.
446 * Empty constructor, does not handle the arguments.
447 * This constructor is done for backward compatibility with 1.7 and 1.8.
448 * The task for handling the argument collation strength and normalization
449 * mode is left to the child class.
450 * @param collationStrength collation strength
451 * @param decompositionMode
452 * @deprecated 2.4 use the default constructor instead
454 Collator::Collator(UCollationStrength
, UNormalizationMode
)
459 Collator::~Collator()
463 Collator::Collator(const Collator
&other
)
468 UBool
Collator::operator==(const Collator
& other
) const
470 return (UBool
)(this == &other
);
473 UBool
Collator::operator!=(const Collator
& other
) const
475 return (UBool
)!(*this == other
);
478 int32_t U_EXPORT2
Collator::getBound(const uint8_t *source
,
479 int32_t sourceLength
,
480 UColBoundMode boundType
,
483 int32_t resultLength
,
486 return ucol_getBound(source
, sourceLength
, boundType
, noOfLevels
, result
, resultLength
, &status
);
490 Collator::setLocales(const Locale
& /* requestedLocale */, const Locale
& /* validLocale */) {
493 UnicodeSet
*Collator::getTailoredSet(UErrorCode
&status
) const
495 if(U_FAILURE(status
)) {
498 // everything can be changed
499 return new UnicodeSet(0, 0x10FFFF);
502 // -------------------------------------
504 #if !UCONFIG_NO_SERVICE
505 URegistryKey U_EXPORT2
506 Collator::registerInstance(Collator
* toAdopt
, const Locale
& locale
, UErrorCode
& status
)
508 if (U_SUCCESS(status
)) {
509 return getService()->registerInstance(toAdopt
, locale
, status
);
514 // -------------------------------------
516 class CFactory
: public LocaleKeyFactory
{
518 CollatorFactory
* _delegate
;
522 CFactory(CollatorFactory
* delegate
, UErrorCode
& status
)
523 : LocaleKeyFactory(delegate
->visible() ? VISIBLE
: INVISIBLE
)
524 , _delegate(delegate
)
527 if (U_SUCCESS(status
)) {
529 _ids
= new Hashtable(status
);
531 const UnicodeString
* idlist
= _delegate
->getSupportedIDs(count
, status
);
532 for (int i
= 0; i
< count
; ++i
) {
533 _ids
->put(idlist
[i
], (void*)this, status
);
534 if (U_FAILURE(status
)) {
541 status
= U_MEMORY_ALLOCATION_ERROR
;
552 virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const;
555 virtual const Hashtable
* getSupportedIDs(UErrorCode
& status
) const
557 if (U_SUCCESS(status
)) {
563 virtual UnicodeString
&
564 getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const;
568 CFactory::create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& status
) const
570 if (handlesKey(key
, status
)) {
571 const LocaleKey
& lkey
= (const LocaleKey
&)key
;
573 lkey
.currentLocale(validLoc
);
574 return _delegate
->createCollator(validLoc
);
580 CFactory::getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const
582 if ((_coverage
& 0x1) == 0) {
583 UErrorCode status
= U_ZERO_ERROR
;
584 const Hashtable
* ids
= getSupportedIDs(status
);
585 if (ids
&& (ids
->get(id
) != NULL
)) {
587 LocaleUtility::initLocaleFromName(id
, loc
);
588 return _delegate
->getDisplayName(loc
, locale
, result
);
595 URegistryKey U_EXPORT2
596 Collator::registerFactory(CollatorFactory
* toAdopt
, UErrorCode
& status
)
598 if (U_SUCCESS(status
)) {
599 CFactory
* f
= new CFactory(toAdopt
, status
);
601 return getService()->registerFactory(f
, status
);
603 status
= U_MEMORY_ALLOCATION_ERROR
;
608 // -------------------------------------
611 Collator::unregister(URegistryKey key
, UErrorCode
& status
)
613 if (U_SUCCESS(status
)) {
615 return gService
->unregister(key
, status
);
617 status
= U_ILLEGAL_ARGUMENT_ERROR
;
622 // -------------------------------------
624 StringEnumeration
* U_EXPORT2
625 Collator::getAvailableLocales(void)
627 return getService()->getAvailableLocales();
629 #endif /* UCONFIG_NO_SERVICE */
631 StringEnumeration
* U_EXPORT2
632 Collator::getKeywords(UErrorCode
& status
) {
633 // This is a wrapper over ucol_getKeywords
634 UEnumeration
* uenum
= ucol_getKeywords(&status
);
635 if (U_FAILURE(status
)) {
639 return new UStringEnumeration(uenum
);
642 StringEnumeration
* U_EXPORT2
643 Collator::getKeywordValues(const char *keyword
, UErrorCode
& status
) {
644 // This is a wrapper over ucol_getKeywordValues
645 UEnumeration
* uenum
= ucol_getKeywordValues(keyword
, &status
);
646 if (U_FAILURE(status
)) {
650 return new UStringEnumeration(uenum
);
654 Collator::getFunctionalEquivalent(const char* keyword
, const Locale
& locale
,
655 UBool
& isAvailable
, UErrorCode
& status
) {
656 // This is a wrapper over ucol_getFunctionalEquivalent
657 char loc
[ULOC_FULLNAME_CAPACITY
];
658 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc
, sizeof(loc
),
659 keyword
, locale
.getName(), &isAvailable
, &status
);
660 if (U_FAILURE(status
)) {
663 return Locale::createFromName(loc
);
666 // UCollator private data members ----------------------------------------
668 /* This is useless information */
669 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
671 // -------------------------------------
675 #endif /* #if !UCONFIG_NO_COLLATION */