1 /*
2 ******************************************************************************
3 * Copyright (C) 1996-2009, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 ******************************************************************************
6 */
7
8 /**
9 * File coll.cpp
10 *
11 * Created by: Helena Shih
12 *
13 * Modification History:
14 *
15 * Date Name Description
16 * 2/5/97 aliu Modified createDefault to load collation data from
17 * binary files when possible. Added related methods
18 * createCollationFromFile, chopLocale, createPathName.
19 * 2/11/97 aliu Added methods addToCache, findInCache, which implement
20 * a Collation cache. Modified createDefault to look in
21 * cache first, and also to store newly created Collation
22 * objects in the cache. Modified to not use gLocPath.
23 * 2/12/97 aliu Modified to create objects from RuleBasedCollator cache.
24 * Moved cache out of Collation class.
25 * 2/13/97 aliu Moved several methods out of this class and into
26 * RuleBasedCollator, with modifications. Modified
27 * createDefault() to call new RuleBasedCollator(Locale&)
28 * constructor. General clean up and documentation.
29 * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy
30 * constructor.
31 * 05/06/97 helena Added memory allocation error detection.
32 * 05/08/97 helena Added createInstance().
33 * 6/20/97 helena Java class name change.
34 * 04/23/99 stephen Removed EDecompositionMode, merged with
35 * Normalizer::EMode
36 * 11/23/9 srl Inlining of some critical functions
37 * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h)
38 */
39
40 #include "unicode/utypes.h"
41
42 #if !UCONFIG_NO_COLLATION
43
44 #include "unicode/coll.h"
45 #include "unicode/tblcoll.h"
46 #include "ucol_imp.h"
47 #include "cstring.h"
48 #include "cmemory.h"
49 #include "umutex.h"
50 #include "servloc.h"
51 #include "ustrenum.h"
52 #include "uresimp.h"
53 #include "ucln_in.h"
54
55 static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL;
56 static int32_t availableLocaleListCount;
57 static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
58
59 /**
60 * Release all static memory held by collator.
61 */
62 U_CDECL_BEGIN
collator_cleanup(void)63 static UBool U_CALLCONV collator_cleanup(void) {
64 #if !UCONFIG_NO_SERVICE
65 if (gService) {
66 delete gService;
67 gService = NULL;
68 }
69 #endif
70 if (availableLocaleList) {
71 delete []availableLocaleList;
72 availableLocaleList = NULL;
73 }
74 availableLocaleListCount = 0;
75
76 return TRUE;
77 }
78
79 U_CDECL_END
80
81 U_NAMESPACE_BEGIN
82
83 #if !UCONFIG_NO_SERVICE
84
85 // ------------------------------------------
86 //
87 // Registration
88 //
89
90 //-------------------------------------------
91
~CollatorFactory()92 CollatorFactory::~CollatorFactory() {}
93
94 //-------------------------------------------
95
96 UBool
visible(void) const97 CollatorFactory::visible(void) const {
98 return TRUE;
99 }
100
101 //-------------------------------------------
102
103 UnicodeString&
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & result)104 CollatorFactory::getDisplayName(const Locale& objectLocale,
105 const Locale& displayLocale,
106 UnicodeString& result)
107 {
108 return objectLocale.getDisplayName(displayLocale, result);
109 }
110
111 // -------------------------------------
112
113 class ICUCollatorFactory : public ICUResourceBundleFactory {
114 public:
ICUCollatorFactory()115 ICUCollatorFactory(): ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
116 protected:
117 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
118 };
119
120 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const121 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
122 if (handlesKey(key, status)) {
123 const LocaleKey& lkey = (const LocaleKey&)key;
124 Locale loc;
125 // make sure the requested locale is correct
126 // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
127 // but for ICU rb resources we use the actual one since it will fallback again
128 lkey.canonicalLocale(loc);
129
130 return Collator::makeInstance(loc, status);
131 }
132 return NULL;
133 }
134
135 // -------------------------------------
136
137 class ICUCollatorService : public ICULocaleService {
138 public:
ICUCollatorService()139 ICUCollatorService()
140 : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
141 {
142 UErrorCode status = U_ZERO_ERROR;
143 registerFactory(new ICUCollatorFactory(), status);
144 }
145
cloneInstance(UObject * instance) const146 virtual UObject* cloneInstance(UObject* instance) const {
147 return ((Collator*)instance)->clone();
148 }
149
handleDefault(const ICUServiceKey & key,UnicodeString * actualID,UErrorCode & status) const150 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
151 LocaleKey& lkey = (LocaleKey&)key;
152 if (actualID) {
153 // Ugly Hack Alert! We return an empty actualID to signal
154 // to callers that this is a default object, not a "real"
155 // service-created object. (TODO remove in 3.0) [aliu]
156 actualID->truncate(0);
157 }
158 Locale loc("");
159 lkey.canonicalLocale(loc);
160 return Collator::makeInstance(loc, status);
161 }
162
getKey(ICUServiceKey & key,UnicodeString * actualReturn,UErrorCode & status) const163 virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
164 UnicodeString ar;
165 if (actualReturn == NULL) {
166 actualReturn = &ar;
167 }
168 Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status);
169 // Ugly Hack Alert! If the actualReturn length is zero, this
170 // means we got a default object, not a "real" service-created
171 // object. We don't call setLocales() on a default object,
172 // because that will overwrite its correct built-in locale
173 // metadata (valid & actual) with our incorrect data (all we
174 // have is the requested locale). (TODO remove in 3.0) [aliu]
175 if (result && actualReturn->length() > 0) {
176 const LocaleKey& lkey = (const LocaleKey&)key;
177 Locale canonicalLocale("");
178 Locale currentLocale("");
179
180 LocaleUtility::initLocaleFromName(*actualReturn, currentLocale);
181 result->setLocales(lkey.canonicalLocale(canonicalLocale), currentLocale, currentLocale);
182 }
183 return result;
184 }
185
isDefault() const186 virtual UBool isDefault() const {
187 return countFactories() == 1;
188 }
189 };
190
191 // -------------------------------------
192
193 static ICULocaleService*
getService(void)194 getService(void)
195 {
196 UBool needInit;
197 UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
198 if(needInit) {
199 ICULocaleService *newservice = new ICUCollatorService();
200 if(newservice) {
201 umtx_lock(NULL);
202 if(gService == NULL) {
203 gService = newservice;
204 newservice = NULL;
205 }
206 umtx_unlock(NULL);
207 }
208 if(newservice) {
209 delete newservice;
210 }
211 else {
212 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
213 }
214 }
215 return gService;
216 }
217
218 // -------------------------------------
219
220 static inline UBool
hasService(void)221 hasService(void)
222 {
223 UBool retVal;
224 UMTX_CHECK(NULL, gService != NULL, retVal);
225 return retVal;
226 }
227
228 // -------------------------------------
229
230 UCollator*
createUCollator(const char * loc,UErrorCode * status)231 Collator::createUCollator(const char *loc,
232 UErrorCode *status)
233 {
234 UCollator *result = 0;
235 if (status && U_SUCCESS(*status) && hasService()) {
236 Locale desiredLocale(loc);
237 Collator *col = (Collator*)gService->get(desiredLocale, *status);
238 if (col && col->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
239 RuleBasedCollator *rbc = (RuleBasedCollator *)col;
240 if (!rbc->dataIsOwned) {
241 result = ucol_safeClone(rbc->ucollator, NULL, NULL, status);
242 } else {
243 result = rbc->ucollator;
244 rbc->ucollator = NULL; // to prevent free on delete
245 }
246 }
247 delete col;
248 }
249 return result;
250 }
251 #endif /* UCONFIG_NO_SERVICE */
252
isAvailableLocaleListInitialized(UErrorCode & status)253 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
254 // for now, there is a hardcoded list, so just walk through that list and set it up.
255 UBool needInit;
256 UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
257
258 if (needInit) {
259 UResourceBundle *index = NULL;
260 UResourceBundle installed;
261 Locale * temp;
262 int32_t i = 0;
263 int32_t localeCount;
264
265 ures_initStackObject(&installed);
266 index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
267 ures_getByKey(index, "InstalledLocales", &installed, &status);
268
269 if(U_SUCCESS(status)) {
270 localeCount = ures_getSize(&installed);
271 temp = new Locale[localeCount];
272
273 if (temp != NULL) {
274 ures_resetIterator(&installed);
275 while(ures_hasNext(&installed)) {
276 const char *tempKey = NULL;
277 ures_getNextString(&installed, NULL, &tempKey, &status);
278 temp[i++] = Locale(tempKey);
279 }
280
281 umtx_lock(NULL);
282 if (availableLocaleList == NULL)
283 {
284 availableLocaleListCount = localeCount;
285 availableLocaleList = temp;
286 temp = NULL;
287 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
288 }
289 umtx_unlock(NULL);
290
291 needInit = FALSE;
292 if (temp) {
293 delete []temp;
294 }
295 }
296
297 ures_close(&installed);
298 }
299 ures_close(index);
300 }
301 return !needInit;
302 }
303
304 // Collator public methods -----------------------------------------------
305
createInstance(UErrorCode & success)306 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
307 {
308 return createInstance(Locale::getDefault(), success);
309 }
310
createInstance(const Locale & desiredLocale,UErrorCode & status)311 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
312 UErrorCode& status)
313 {
314 if (U_FAILURE(status))
315 return 0;
316
317 #if !UCONFIG_NO_SERVICE
318 if (hasService()) {
319 Locale actualLoc;
320 Collator *result =
321 (Collator*)gService->get(desiredLocale, &actualLoc, status);
322 // Ugly Hack Alert! If the returned locale is empty (not root,
323 // but empty -- getName() == "") then that means the service
324 // returned a default object, not a "real" service object. In
325 // that case, the locale metadata (valid & actual) is setup
326 // correctly already, and we don't want to overwrite it. (TODO
327 // remove in 3.0) [aliu]
328 if (*actualLoc.getName() != 0) {
329 result->setLocales(desiredLocale, actualLoc, actualLoc);
330 }
331 return result;
332 }
333 #endif
334 return makeInstance(desiredLocale, status);
335 }
336
337
makeInstance(const Locale & desiredLocale,UErrorCode & status)338 Collator* Collator::makeInstance(const Locale& desiredLocale,
339 UErrorCode& status)
340 {
341 // A bit of explanation is required here. Although in the current
342 // implementation
343 // Collator::createInstance() is just turning around and calling
344 // RuleBasedCollator(Locale&), this will not necessarily always be the
345 // case. For example, suppose we modify this code to handle a
346 // non-table-based Collator, such as that for Thai. In this case,
347 // createInstance() will have to be modified to somehow determine this fact
348 // (perhaps a field in the resource bundle). Then it can construct the
349 // non-table-based Collator in some other way, when it sees that it needs
350 // to.
351 // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS
352 // return a valid collation object, if the system is functioning properly.
353 // The reason is that it will fall back, use the default locale, and even
354 // use the built-in default collation rules. THEREFORE, createInstance()
355 // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN
356 // ADVANCE that the given locale's collation is properly implemented as a
357 // RuleBasedCollator.
358 // Currently, we don't do this...we always return a RuleBasedCollator,
359 // whether it is strictly correct to do so or not, without checking, because
360 // we currently have no way of checking.
361
362 RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale,
363 status);
364 /* test for NULL */
365 if (collation == 0) {
366 status = U_MEMORY_ALLOCATION_ERROR;
367 return 0;
368 }
369 if (U_FAILURE(status))
370 {
371 delete collation;
372 collation = 0;
373 }
374 return collation;
375 }
376
377 #ifdef U_USE_COLLATION_OBSOLETE_2_6
378 // !!! dlf the following is obsolete, ignore registration for this
379
380 Collator *
createInstance(const Locale & loc,UVersionInfo version,UErrorCode & status)381 Collator::createInstance(const Locale &loc,
382 UVersionInfo version,
383 UErrorCode &status)
384 {
385 Collator *collator;
386 UVersionInfo info;
387
388 collator=new RuleBasedCollator(loc, status);
389 /* test for NULL */
390 if (collator == 0) {
391 status = U_MEMORY_ALLOCATION_ERROR;
392 return 0;
393 }
394
395 if(U_SUCCESS(status)) {
396 collator->getVersion(info);
397 if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) {
398 delete collator;
399 status=U_MISSING_RESOURCE_ERROR;
400 return 0;
401 }
402 }
403 return collator;
404 }
405 #endif
406
407 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target) const408 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
409 const UnicodeString& target) const
410 {
411 UErrorCode ec = U_ZERO_ERROR;
412 return (Collator::EComparisonResult)compare(source, target, ec);
413 }
414
415 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target,int32_t length) const416 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
417 const UnicodeString& target,
418 int32_t length) const
419 {
420 UErrorCode ec = U_ZERO_ERROR;
421 return (Collator::EComparisonResult)compare(source, target, length, ec);
422 }
423
424 // implement deprecated, previously abstract method
compare(const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength) const425 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
426 const UChar* target, int32_t targetLength)
427 const
428 {
429 UErrorCode ec = U_ZERO_ERROR;
430 return (Collator::EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
431 }
432
compare(UCharIterator &,UCharIterator &,UErrorCode & status) const433 UCollationResult Collator::compare(UCharIterator &/*sIter*/,
434 UCharIterator &/*tIter*/,
435 UErrorCode &status) const {
436 if(U_SUCCESS(status)) {
437 // Not implemented in the base class.
438 status = U_UNSUPPORTED_ERROR;
439 }
440 return UCOL_EQUAL;
441 }
442
compareUTF8(const StringPiece & source,const StringPiece & target,UErrorCode & status) const443 UCollationResult Collator::compareUTF8(const StringPiece &source,
444 const StringPiece &target,
445 UErrorCode &status) const {
446 if(U_FAILURE(status)) {
447 return UCOL_EQUAL;
448 }
449 UCharIterator sIter, tIter;
450 uiter_setUTF8(&sIter, source.data(), source.length());
451 uiter_setUTF8(&tIter, target.data(), target.length());
452 return compare(sIter, tIter, status);
453 }
454
equals(const UnicodeString & source,const UnicodeString & target) const455 UBool Collator::equals(const UnicodeString& source,
456 const UnicodeString& target) const
457 {
458 UErrorCode ec = U_ZERO_ERROR;
459 return (compare(source, target, ec) == UCOL_EQUAL);
460 }
461
greaterOrEqual(const UnicodeString & source,const UnicodeString & target) const462 UBool Collator::greaterOrEqual(const UnicodeString& source,
463 const UnicodeString& target) const
464 {
465 UErrorCode ec = U_ZERO_ERROR;
466 return (compare(source, target, ec) != UCOL_LESS);
467 }
468
greater(const UnicodeString & source,const UnicodeString & target) const469 UBool Collator::greater(const UnicodeString& source,
470 const UnicodeString& target) const
471 {
472 UErrorCode ec = U_ZERO_ERROR;
473 return (compare(source, target, ec) == UCOL_GREATER);
474 }
475
476 // this API ignores registered collators, since it returns an
477 // array of indefinite lifetime
getAvailableLocales(int32_t & count)478 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
479 {
480 UErrorCode status = U_ZERO_ERROR;
481 Locale *result = NULL;
482 count = 0;
483 if (isAvailableLocaleListInitialized(status))
484 {
485 result = availableLocaleList;
486 count = availableLocaleListCount;
487 }
488 return result;
489 }
490
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & name)491 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
492 const Locale& displayLocale,
493 UnicodeString& name)
494 {
495 #if !UCONFIG_NO_SERVICE
496 if (hasService()) {
497 UnicodeString locNameStr;
498 LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
499 return gService->getDisplayName(locNameStr, name, displayLocale);
500 }
501 #endif
502 return objectLocale.getDisplayName(displayLocale, name);
503 }
504
getDisplayName(const Locale & objectLocale,UnicodeString & name)505 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
506 UnicodeString& name)
507 {
508 return getDisplayName(objectLocale, Locale::getDefault(), name);
509 }
510
511 /* This is useless information */
512 /*void Collator::getVersion(UVersionInfo versionInfo) const
513 {
514 if (versionInfo!=NULL)
515 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
516 }
517 */
518
519 // UCollator protected constructor destructor ----------------------------
520
521 /**
522 * Default constructor.
523 * Constructor is different from the old default Collator constructor.
524 * The task for determing the default collation strength and normalization mode
525 * is left to the child class.
526 */
Collator()527 Collator::Collator()
528 : UObject()
529 {
530 }
531
532 /**
533 * Constructor.
534 * Empty constructor, does not handle the arguments.
535 * This constructor is done for backward compatibility with 1.7 and 1.8.
536 * The task for handling the argument collation strength and normalization
537 * mode is left to the child class.
538 * @param collationStrength collation strength
539 * @param decompositionMode
540 * @deprecated 2.4 use the default constructor instead
541 */
Collator(UCollationStrength,UNormalizationMode)542 Collator::Collator(UCollationStrength, UNormalizationMode )
543 : UObject()
544 {
545 }
546
~Collator()547 Collator::~Collator()
548 {
549 }
550
Collator(const Collator & other)551 Collator::Collator(const Collator &other)
552 : UObject(other)
553 {
554 }
555
operator ==(const Collator & other) const556 UBool Collator::operator==(const Collator& other) const
557 {
558 return (UBool)(this == &other);
559 }
560
operator !=(const Collator & other) const561 UBool Collator::operator!=(const Collator& other) const
562 {
563 return (UBool)!(*this == other);
564 }
565
getBound(const uint8_t * source,int32_t sourceLength,UColBoundMode boundType,uint32_t noOfLevels,uint8_t * result,int32_t resultLength,UErrorCode & status)566 int32_t U_EXPORT2 Collator::getBound(const uint8_t *source,
567 int32_t sourceLength,
568 UColBoundMode boundType,
569 uint32_t noOfLevels,
570 uint8_t *result,
571 int32_t resultLength,
572 UErrorCode &status)
573 {
574 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
575 }
576
577 void
setLocales(const Locale &,const Locale &,const Locale &)578 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
579 }
580
getTailoredSet(UErrorCode & status) const581 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
582 {
583 if(U_FAILURE(status)) {
584 return NULL;
585 }
586 // everything can be changed
587 return new UnicodeSet(0, 0x10FFFF);
588 }
589
590 // -------------------------------------
591
592 #if !UCONFIG_NO_SERVICE
593 URegistryKey U_EXPORT2
registerInstance(Collator * toAdopt,const Locale & locale,UErrorCode & status)594 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
595 {
596 if (U_SUCCESS(status)) {
597 return getService()->registerInstance(toAdopt, locale, status);
598 }
599 return NULL;
600 }
601
602 // -------------------------------------
603
604 class CFactory : public LocaleKeyFactory {
605 private:
606 CollatorFactory* _delegate;
607 Hashtable* _ids;
608
609 public:
CFactory(CollatorFactory * delegate,UErrorCode & status)610 CFactory(CollatorFactory* delegate, UErrorCode& status)
611 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
612 , _delegate(delegate)
613 , _ids(NULL)
614 {
615 if (U_SUCCESS(status)) {
616 int32_t count = 0;
617 _ids = new Hashtable(status);
618 if (_ids) {
619 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
620 for (int i = 0; i < count; ++i) {
621 _ids->put(idlist[i], (void*)this, status);
622 if (U_FAILURE(status)) {
623 delete _ids;
624 _ids = NULL;
625 return;
626 }
627 }
628 } else {
629 status = U_MEMORY_ALLOCATION_ERROR;
630 }
631 }
632 }
633
~CFactory()634 virtual ~CFactory()
635 {
636 delete _delegate;
637 delete _ids;
638 }
639
640 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
641
642 protected:
getSupportedIDs(UErrorCode & status) const643 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
644 {
645 if (U_SUCCESS(status)) {
646 return _ids;
647 }
648 return NULL;
649 }
650
651 virtual UnicodeString&
652 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
653 };
654
655 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const656 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
657 {
658 if (handlesKey(key, status)) {
659 const LocaleKey& lkey = (const LocaleKey&)key;
660 Locale validLoc;
661 lkey.currentLocale(validLoc);
662 return _delegate->createCollator(validLoc);
663 }
664 return NULL;
665 }
666
667 UnicodeString&
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const668 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
669 {
670 if ((_coverage & 0x1) == 0) {
671 UErrorCode status = U_ZERO_ERROR;
672 const Hashtable* ids = getSupportedIDs(status);
673 if (ids && (ids->get(id) != NULL)) {
674 Locale loc;
675 LocaleUtility::initLocaleFromName(id, loc);
676 return _delegate->getDisplayName(loc, locale, result);
677 }
678 }
679 result.setToBogus();
680 return result;
681 }
682
683 URegistryKey U_EXPORT2
registerFactory(CollatorFactory * toAdopt,UErrorCode & status)684 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
685 {
686 if (U_SUCCESS(status)) {
687 CFactory* f = new CFactory(toAdopt, status);
688 if (f) {
689 return getService()->registerFactory(f, status);
690 }
691 status = U_MEMORY_ALLOCATION_ERROR;
692 }
693 return NULL;
694 }
695
696 // -------------------------------------
697
698 UBool U_EXPORT2
unregister(URegistryKey key,UErrorCode & status)699 Collator::unregister(URegistryKey key, UErrorCode& status)
700 {
701 if (U_SUCCESS(status)) {
702 if (hasService()) {
703 return gService->unregister(key, status);
704 }
705 status = U_ILLEGAL_ARGUMENT_ERROR;
706 }
707 return FALSE;
708 }
709 #endif /* UCONFIG_NO_SERVICE */
710
711 class CollationLocaleListEnumeration : public StringEnumeration {
712 private:
713 int32_t index;
714 public:
715 static UClassID U_EXPORT2 getStaticClassID(void);
716 virtual UClassID getDynamicClassID(void) const;
717 public:
CollationLocaleListEnumeration()718 CollationLocaleListEnumeration()
719 : index(0)
720 {
721 // The global variables should already be initialized.
722 //isAvailableLocaleListInitialized(status);
723 }
724
~CollationLocaleListEnumeration()725 virtual ~CollationLocaleListEnumeration() {
726 }
727
clone() const728 virtual StringEnumeration * clone() const
729 {
730 CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
731 if (result) {
732 result->index = index;
733 }
734 return result;
735 }
736
count(UErrorCode &) const737 virtual int32_t count(UErrorCode &/*status*/) const {
738 return availableLocaleListCount;
739 }
740
next(int32_t * resultLength,UErrorCode &)741 virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
742 const char* result;
743 if(index < availableLocaleListCount) {
744 result = availableLocaleList[index++].getName();
745 if(resultLength != NULL) {
746 *resultLength = (int32_t)uprv_strlen(result);
747 }
748 } else {
749 if(resultLength != NULL) {
750 *resultLength = 0;
751 }
752 result = NULL;
753 }
754 return result;
755 }
756
snext(UErrorCode & status)757 virtual const UnicodeString* snext(UErrorCode& status) {
758 int32_t resultLength = 0;
759 const char *s = next(&resultLength, status);
760 return setChars(s, resultLength, status);
761 }
762
reset(UErrorCode &)763 virtual void reset(UErrorCode& /*status*/) {
764 index = 0;
765 }
766 };
767
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)768 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
769
770
771 // -------------------------------------
772
773 StringEnumeration* U_EXPORT2
774 Collator::getAvailableLocales(void)
775 {
776 #if !UCONFIG_NO_SERVICE
777 if (hasService()) {
778 return getService()->getAvailableLocales();
779 }
780 #endif /* UCONFIG_NO_SERVICE */
781 UErrorCode status = U_ZERO_ERROR;
782 if (isAvailableLocaleListInitialized(status)) {
783 return new CollationLocaleListEnumeration();
784 }
785 return NULL;
786 }
787
788 StringEnumeration* U_EXPORT2
getKeywords(UErrorCode & status)789 Collator::getKeywords(UErrorCode& status) {
790 // This is a wrapper over ucol_getKeywords
791 UEnumeration* uenum = ucol_getKeywords(&status);
792 if (U_FAILURE(status)) {
793 uenum_close(uenum);
794 return NULL;
795 }
796 return new UStringEnumeration(uenum);
797 }
798
799 StringEnumeration* U_EXPORT2
getKeywordValues(const char * keyword,UErrorCode & status)800 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
801 // This is a wrapper over ucol_getKeywordValues
802 UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
803 if (U_FAILURE(status)) {
804 uenum_close(uenum);
805 return NULL;
806 }
807 return new UStringEnumeration(uenum);
808 }
809
810 StringEnumeration* U_EXPORT2
getKeywordValuesForLocale(const char * key,const Locale & locale,UBool commonlyUsed,UErrorCode & status)811 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
812 UBool commonlyUsed, UErrorCode& status) {
813 // This is a wrapper over ucol_getKeywordValuesForLocale
814 UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(),
815 commonlyUsed, &status);
816 if (U_FAILURE(status)) {
817 uenum_close(uenum);
818 return NULL;
819 }
820 return new UStringEnumeration(uenum);
821 }
822
823 Locale U_EXPORT2
getFunctionalEquivalent(const char * keyword,const Locale & locale,UBool & isAvailable,UErrorCode & status)824 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
825 UBool& isAvailable, UErrorCode& status) {
826 // This is a wrapper over ucol_getFunctionalEquivalent
827 char loc[ULOC_FULLNAME_CAPACITY];
828 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
829 keyword, locale.getName(), &isAvailable, &status);
830 if (U_FAILURE(status)) {
831 *loc = 0; // root
832 }
833 return Locale::createFromName(loc);
834 }
835
836 // UCollator private data members ----------------------------------------
837
838 /* This is useless information */
839 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
840
841 // -------------------------------------
842
843 U_NAMESPACE_END
844
845 #endif /* #if !UCONFIG_NO_COLLATION */
846
847 /* eof */
848