• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ******************************************************************************
3  * Copyright (C) 1996-2012, 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 "utypeinfo.h"  // for 'typeid' to work
41 
42 #include "unicode/utypes.h"
43 
44 #if !UCONFIG_NO_COLLATION
45 
46 #include "unicode/coll.h"
47 #include "unicode/tblcoll.h"
48 #include "ucol_imp.h"
49 #include "cstring.h"
50 #include "cmemory.h"
51 #include "umutex.h"
52 #include "servloc.h"
53 #include "ustrenum.h"
54 #include "uresimp.h"
55 #include "ucln_in.h"
56 
57 static icu::Locale* availableLocaleList = NULL;
58 static int32_t  availableLocaleListCount;
59 static icu::ICULocaleService* gService = NULL;
60 
61 /**
62  * Release all static memory held by collator.
63  */
64 U_CDECL_BEGIN
collator_cleanup(void)65 static UBool U_CALLCONV collator_cleanup(void) {
66 #if !UCONFIG_NO_SERVICE
67     if (gService) {
68         delete gService;
69         gService = NULL;
70     }
71 #endif
72     if (availableLocaleList) {
73         delete []availableLocaleList;
74         availableLocaleList = NULL;
75     }
76     availableLocaleListCount = 0;
77 
78     return TRUE;
79 }
80 
81 U_CDECL_END
82 
83 U_NAMESPACE_BEGIN
84 
85 #if !UCONFIG_NO_SERVICE
86 
87 // ------------------------------------------
88 //
89 // Registration
90 //
91 
92 //-------------------------------------------
93 
~CollatorFactory()94 CollatorFactory::~CollatorFactory() {}
95 
96 //-------------------------------------------
97 
98 UBool
visible(void) const99 CollatorFactory::visible(void) const {
100     return TRUE;
101 }
102 
103 //-------------------------------------------
104 
105 UnicodeString&
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & result)106 CollatorFactory::getDisplayName(const Locale& objectLocale,
107                                 const Locale& displayLocale,
108                                 UnicodeString& result)
109 {
110   return objectLocale.getDisplayName(displayLocale, result);
111 }
112 
113 // -------------------------------------
114 
115 class ICUCollatorFactory : public ICUResourceBundleFactory {
116  public:
ICUCollatorFactory()117     ICUCollatorFactory() : ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
118     virtual ~ICUCollatorFactory();
119  protected:
120     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
121 };
122 
~ICUCollatorFactory()123 ICUCollatorFactory::~ICUCollatorFactory() {}
124 
125 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const126 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
127     if (handlesKey(key, status)) {
128         const LocaleKey& lkey = (const LocaleKey&)key;
129         Locale loc;
130         // make sure the requested locale is correct
131         // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
132         // but for ICU rb resources we use the actual one since it will fallback again
133         lkey.canonicalLocale(loc);
134 
135         return Collator::makeInstance(loc, status);
136     }
137     return NULL;
138 }
139 
140 // -------------------------------------
141 
142 class ICUCollatorService : public ICULocaleService {
143 public:
ICUCollatorService()144     ICUCollatorService()
145         : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
146     {
147         UErrorCode status = U_ZERO_ERROR;
148         registerFactory(new ICUCollatorFactory(), status);
149     }
150 
151     virtual ~ICUCollatorService();
152 
cloneInstance(UObject * instance) const153     virtual UObject* cloneInstance(UObject* instance) const {
154         return ((Collator*)instance)->clone();
155     }
156 
handleDefault(const ICUServiceKey & key,UnicodeString * actualID,UErrorCode & status) const157     virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
158         LocaleKey& lkey = (LocaleKey&)key;
159         if (actualID) {
160             // Ugly Hack Alert! We return an empty actualID to signal
161             // to callers that this is a default object, not a "real"
162             // service-created object. (TODO remove in 3.0) [aliu]
163             actualID->truncate(0);
164         }
165         Locale loc("");
166         lkey.canonicalLocale(loc);
167         return Collator::makeInstance(loc, status);
168     }
169 
getKey(ICUServiceKey & key,UnicodeString * actualReturn,UErrorCode & status) const170     virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
171         UnicodeString ar;
172         if (actualReturn == NULL) {
173             actualReturn = &ar;
174         }
175         Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status);
176         // Ugly Hack Alert! If the actualReturn length is zero, this
177         // means we got a default object, not a "real" service-created
178         // object.  We don't call setLocales() on a default object,
179         // because that will overwrite its correct built-in locale
180         // metadata (valid & actual) with our incorrect data (all we
181         // have is the requested locale). (TODO remove in 3.0) [aliu]
182         if (result && actualReturn->length() > 0) {
183             const LocaleKey& lkey = (const LocaleKey&)key;
184             Locale canonicalLocale("");
185             Locale currentLocale("");
186 
187             LocaleUtility::initLocaleFromName(*actualReturn, currentLocale);
188             result->setLocales(lkey.canonicalLocale(canonicalLocale), currentLocale, currentLocale);
189         }
190         return result;
191     }
192 
isDefault() const193     virtual UBool isDefault() const {
194         return countFactories() == 1;
195     }
196 };
197 
~ICUCollatorService()198 ICUCollatorService::~ICUCollatorService() {}
199 
200 // -------------------------------------
201 
202 static ICULocaleService*
getService(void)203 getService(void)
204 {
205     UBool needInit;
206     UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
207     if(needInit) {
208         ICULocaleService *newservice = new ICUCollatorService();
209         if(newservice) {
210             umtx_lock(NULL);
211             if(gService == NULL) {
212                 gService = newservice;
213                 newservice = NULL;
214             }
215             umtx_unlock(NULL);
216         }
217         if(newservice) {
218             delete newservice;
219         }
220         else {
221             ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
222         }
223     }
224     return gService;
225 }
226 
227 // -------------------------------------
228 
229 static inline UBool
hasService(void)230 hasService(void)
231 {
232     UBool retVal;
233     UMTX_CHECK(NULL, gService != NULL, retVal);
234     return retVal;
235 }
236 
237 // -------------------------------------
238 
239 UCollator*
createUCollator(const char * loc,UErrorCode * status)240 Collator::createUCollator(const char *loc,
241                           UErrorCode *status)
242 {
243     UCollator *result = 0;
244     if (status && U_SUCCESS(*status) && hasService()) {
245         Locale desiredLocale(loc);
246         Collator *col = (Collator*)gService->get(desiredLocale, *status);
247         RuleBasedCollator *rbc;
248         if (col && (rbc = dynamic_cast<RuleBasedCollator *>(col))) {
249             if (!rbc->dataIsOwned) {
250                 result = ucol_safeClone(rbc->ucollator, NULL, NULL, status);
251             } else {
252                 result = rbc->ucollator;
253                 rbc->ucollator = NULL; // to prevent free on delete
254             }
255         } else {
256           // should go in a function- ucol_initDelegate(delegate)
257           result = (UCollator *)uprv_malloc(sizeof(UCollator));
258           if(result == NULL) {
259             *status = U_MEMORY_ALLOCATION_ERROR;
260           } else {
261             uprv_memset(result, 0, sizeof(UCollator));
262             result->delegate = col;
263             result->freeOnClose = TRUE; // do free on close.
264             col = NULL; // to prevent free on delete.
265           }
266         }
267         delete col;
268     }
269     return result;
270 }
271 #endif /* UCONFIG_NO_SERVICE */
272 
isAvailableLocaleListInitialized(UErrorCode & status)273 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
274     // for now, there is a hardcoded list, so just walk through that list and set it up.
275     UBool needInit;
276     UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
277 
278     if (needInit) {
279         UResourceBundle *index = NULL;
280         UResourceBundle installed;
281         Locale * temp;
282         int32_t i = 0;
283         int32_t localeCount;
284 
285         ures_initStackObject(&installed);
286         index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
287         ures_getByKey(index, "InstalledLocales", &installed, &status);
288 
289         if(U_SUCCESS(status)) {
290             localeCount = ures_getSize(&installed);
291             temp = new Locale[localeCount];
292 
293             if (temp != NULL) {
294                 ures_resetIterator(&installed);
295                 while(ures_hasNext(&installed)) {
296                     const char *tempKey = NULL;
297                     ures_getNextString(&installed, NULL, &tempKey, &status);
298                     temp[i++] = Locale(tempKey);
299                 }
300 
301                 umtx_lock(NULL);
302                 if (availableLocaleList == NULL)
303                 {
304                     availableLocaleListCount = localeCount;
305                     availableLocaleList = temp;
306                     temp = NULL;
307                     ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
308                 }
309                 umtx_unlock(NULL);
310 
311                 needInit = FALSE;
312                 if (temp) {
313                     delete []temp;
314                 }
315             }
316 
317             ures_close(&installed);
318         }
319         ures_close(index);
320     }
321     return !needInit;
322 }
323 
324 // Collator public methods -----------------------------------------------
325 
createInstance(UErrorCode & success)326 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
327 {
328     return createInstance(Locale::getDefault(), success);
329 }
330 
createInstance(const Locale & desiredLocale,UErrorCode & status)331 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
332                                    UErrorCode& status)
333 {
334     if (U_FAILURE(status))
335         return 0;
336 
337 #if !UCONFIG_NO_SERVICE
338     if (hasService()) {
339         Locale actualLoc;
340         Collator *result =
341             (Collator*)gService->get(desiredLocale, &actualLoc, status);
342 
343         // Ugly Hack Alert! If the returned locale is empty (not root,
344         // but empty -- getName() == "") then that means the service
345         // returned a default object, not a "real" service object.  In
346         // that case, the locale metadata (valid & actual) is setup
347         // correctly already, and we don't want to overwrite it. (TODO
348         // remove in 3.0) [aliu]
349         if (*actualLoc.getName() != 0) {
350             result->setLocales(desiredLocale, actualLoc, actualLoc);
351         }
352         return result;
353     }
354 #endif
355     return makeInstance(desiredLocale, status);
356 }
357 
358 
makeInstance(const Locale & desiredLocale,UErrorCode & status)359 Collator* Collator::makeInstance(const Locale&  desiredLocale,
360                                          UErrorCode& status)
361 {
362     // A bit of explanation is required here. Although in the current
363     // implementation
364     // Collator::createInstance() is just turning around and calling
365     // RuleBasedCollator(Locale&), this will not necessarily always be the
366     // case. For example, suppose we modify this code to handle a
367     // non-table-based Collator, such as that for Thai. In this case,
368     // createInstance() will have to be modified to somehow determine this fact
369     // (perhaps a field in the resource bundle). Then it can construct the
370     // non-table-based Collator in some other way, when it sees that it needs
371     // to.
372     // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS
373     // return a valid collation object, if the system is functioning properly.
374     // The reason is that it will fall back, use the default locale, and even
375     // use the built-in default collation rules. THEREFORE, createInstance()
376     // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN
377     // ADVANCE that the given locale's collation is properly implemented as a
378     // RuleBasedCollator.
379     // Currently, we don't do this...we always return a RuleBasedCollator,
380     // whether it is strictly correct to do so or not, without checking, because
381     // we currently have no way of checking.
382 
383     RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale,
384         status);
385     /* test for NULL */
386     if (collation == 0) {
387         status = U_MEMORY_ALLOCATION_ERROR;
388         return 0;
389     }
390     if (U_FAILURE(status))
391     {
392         delete collation;
393         collation = 0;
394     }
395     return collation;
396 }
397 
398 #ifdef U_USE_COLLATION_OBSOLETE_2_6
399 // !!! dlf the following is obsolete, ignore registration for this
400 
401 Collator *
createInstance(const Locale & loc,UVersionInfo version,UErrorCode & status)402 Collator::createInstance(const Locale &loc,
403                          UVersionInfo version,
404                          UErrorCode &status)
405 {
406     Collator *collator;
407     UVersionInfo info;
408 
409     collator=new RuleBasedCollator(loc, status);
410     /* test for NULL */
411     if (collator == 0) {
412         status = U_MEMORY_ALLOCATION_ERROR;
413         return 0;
414     }
415 
416     if(U_SUCCESS(status)) {
417         collator->getVersion(info);
418         if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) {
419             delete collator;
420             status=U_MISSING_RESOURCE_ERROR;
421             return 0;
422         }
423     }
424     return collator;
425 }
426 #endif
427 
428 Collator *
safeClone() const429 Collator::safeClone() const {
430     return clone();
431 }
432 
433 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target) const434 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
435                                     const UnicodeString& target) const
436 {
437     UErrorCode ec = U_ZERO_ERROR;
438     return (EComparisonResult)compare(source, target, ec);
439 }
440 
441 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target,int32_t length) const442 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
443                                     const UnicodeString& target,
444                                     int32_t length) const
445 {
446     UErrorCode ec = U_ZERO_ERROR;
447     return (EComparisonResult)compare(source, target, length, ec);
448 }
449 
450 // implement deprecated, previously abstract method
compare(const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength) const451 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
452                                     const UChar* target, int32_t targetLength)
453                                     const
454 {
455     UErrorCode ec = U_ZERO_ERROR;
456     return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
457 }
458 
compare(UCharIterator &,UCharIterator &,UErrorCode & status) const459 UCollationResult Collator::compare(UCharIterator &/*sIter*/,
460                                    UCharIterator &/*tIter*/,
461                                    UErrorCode &status) const {
462     if(U_SUCCESS(status)) {
463         // Not implemented in the base class.
464         status = U_UNSUPPORTED_ERROR;
465     }
466     return UCOL_EQUAL;
467 }
468 
compareUTF8(const StringPiece & source,const StringPiece & target,UErrorCode & status) const469 UCollationResult Collator::compareUTF8(const StringPiece &source,
470                                        const StringPiece &target,
471                                        UErrorCode &status) const {
472     if(U_FAILURE(status)) {
473         return UCOL_EQUAL;
474     }
475     UCharIterator sIter, tIter;
476     uiter_setUTF8(&sIter, source.data(), source.length());
477     uiter_setUTF8(&tIter, target.data(), target.length());
478     return compare(sIter, tIter, status);
479 }
480 
equals(const UnicodeString & source,const UnicodeString & target) const481 UBool Collator::equals(const UnicodeString& source,
482                        const UnicodeString& target) const
483 {
484     UErrorCode ec = U_ZERO_ERROR;
485     return (compare(source, target, ec) == UCOL_EQUAL);
486 }
487 
greaterOrEqual(const UnicodeString & source,const UnicodeString & target) const488 UBool Collator::greaterOrEqual(const UnicodeString& source,
489                                const UnicodeString& target) const
490 {
491     UErrorCode ec = U_ZERO_ERROR;
492     return (compare(source, target, ec) != UCOL_LESS);
493 }
494 
greater(const UnicodeString & source,const UnicodeString & target) const495 UBool Collator::greater(const UnicodeString& source,
496                         const UnicodeString& target) const
497 {
498     UErrorCode ec = U_ZERO_ERROR;
499     return (compare(source, target, ec) == UCOL_GREATER);
500 }
501 
502 // this API  ignores registered collators, since it returns an
503 // array of indefinite lifetime
getAvailableLocales(int32_t & count)504 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
505 {
506     UErrorCode status = U_ZERO_ERROR;
507     Locale *result = NULL;
508     count = 0;
509     if (isAvailableLocaleListInitialized(status))
510     {
511         result = availableLocaleList;
512         count = availableLocaleListCount;
513     }
514     return result;
515 }
516 
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & name)517 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
518                                         const Locale& displayLocale,
519                                         UnicodeString& name)
520 {
521 #if !UCONFIG_NO_SERVICE
522     if (hasService()) {
523         UnicodeString locNameStr;
524         LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
525         return gService->getDisplayName(locNameStr, name, displayLocale);
526     }
527 #endif
528     return objectLocale.getDisplayName(displayLocale, name);
529 }
530 
getDisplayName(const Locale & objectLocale,UnicodeString & name)531 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
532                                         UnicodeString& name)
533 {
534     return getDisplayName(objectLocale, Locale::getDefault(), name);
535 }
536 
537 /* This is useless information */
538 /*void Collator::getVersion(UVersionInfo versionInfo) const
539 {
540   if (versionInfo!=NULL)
541     uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
542 }
543 */
544 
545 // UCollator protected constructor destructor ----------------------------
546 
547 /**
548 * Default constructor.
549 * Constructor is different from the old default Collator constructor.
550 * The task for determing the default collation strength and normalization mode
551 * is left to the child class.
552 */
Collator()553 Collator::Collator()
554 : UObject()
555 {
556 }
557 
558 /**
559 * Constructor.
560 * Empty constructor, does not handle the arguments.
561 * This constructor is done for backward compatibility with 1.7 and 1.8.
562 * The task for handling the argument collation strength and normalization
563 * mode is left to the child class.
564 * @param collationStrength collation strength
565 * @param decompositionMode
566 * @deprecated 2.4 use the default constructor instead
567 */
Collator(UCollationStrength,UNormalizationMode)568 Collator::Collator(UCollationStrength, UNormalizationMode )
569 : UObject()
570 {
571 }
572 
~Collator()573 Collator::~Collator()
574 {
575 }
576 
Collator(const Collator & other)577 Collator::Collator(const Collator &other)
578     : UObject(other)
579 {
580 }
581 
operator ==(const Collator & other) const582 UBool Collator::operator==(const Collator& other) const
583 {
584     // Subclasses: Call this method and then add more specific checks.
585     return typeid(*this) == typeid(other);
586 }
587 
operator !=(const Collator & other) const588 UBool Collator::operator!=(const Collator& other) const
589 {
590     return (UBool)!(*this == other);
591 }
592 
getBound(const uint8_t * source,int32_t sourceLength,UColBoundMode boundType,uint32_t noOfLevels,uint8_t * result,int32_t resultLength,UErrorCode & status)593 int32_t U_EXPORT2 Collator::getBound(const uint8_t       *source,
594                            int32_t             sourceLength,
595                            UColBoundMode       boundType,
596                            uint32_t            noOfLevels,
597                            uint8_t             *result,
598                            int32_t             resultLength,
599                            UErrorCode          &status)
600 {
601     return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
602 }
603 
604 void
setLocales(const Locale &,const Locale &,const Locale &)605 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
606 }
607 
getTailoredSet(UErrorCode & status) const608 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
609 {
610     if(U_FAILURE(status)) {
611         return NULL;
612     }
613     // everything can be changed
614     return new UnicodeSet(0, 0x10FFFF);
615 }
616 
617 // -------------------------------------
618 
619 #if !UCONFIG_NO_SERVICE
620 URegistryKey U_EXPORT2
registerInstance(Collator * toAdopt,const Locale & locale,UErrorCode & status)621 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
622 {
623     if (U_SUCCESS(status)) {
624         return getService()->registerInstance(toAdopt, locale, status);
625     }
626     return NULL;
627 }
628 
629 // -------------------------------------
630 
631 class CFactory : public LocaleKeyFactory {
632 private:
633     CollatorFactory* _delegate;
634     Hashtable* _ids;
635 
636 public:
CFactory(CollatorFactory * delegate,UErrorCode & status)637     CFactory(CollatorFactory* delegate, UErrorCode& status)
638         : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
639         , _delegate(delegate)
640         , _ids(NULL)
641     {
642         if (U_SUCCESS(status)) {
643             int32_t count = 0;
644             _ids = new Hashtable(status);
645             if (_ids) {
646                 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
647                 for (int i = 0; i < count; ++i) {
648                     _ids->put(idlist[i], (void*)this, status);
649                     if (U_FAILURE(status)) {
650                         delete _ids;
651                         _ids = NULL;
652                         return;
653                     }
654                 }
655             } else {
656                 status = U_MEMORY_ALLOCATION_ERROR;
657             }
658         }
659     }
660 
661     virtual ~CFactory();
662 
663     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
664 
665 protected:
getSupportedIDs(UErrorCode & status) const666     virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
667     {
668         if (U_SUCCESS(status)) {
669             return _ids;
670         }
671         return NULL;
672     }
673 
674     virtual UnicodeString&
675         getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
676 };
677 
~CFactory()678 CFactory::~CFactory()
679 {
680     delete _delegate;
681     delete _ids;
682 }
683 
684 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const685 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
686 {
687     if (handlesKey(key, status)) {
688         const LocaleKey& lkey = (const LocaleKey&)key;
689         Locale validLoc;
690         lkey.currentLocale(validLoc);
691         return _delegate->createCollator(validLoc);
692     }
693     return NULL;
694 }
695 
696 UnicodeString&
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const697 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
698 {
699     if ((_coverage & 0x1) == 0) {
700         UErrorCode status = U_ZERO_ERROR;
701         const Hashtable* ids = getSupportedIDs(status);
702         if (ids && (ids->get(id) != NULL)) {
703             Locale loc;
704             LocaleUtility::initLocaleFromName(id, loc);
705             return _delegate->getDisplayName(loc, locale, result);
706         }
707     }
708     result.setToBogus();
709     return result;
710 }
711 
712 URegistryKey U_EXPORT2
registerFactory(CollatorFactory * toAdopt,UErrorCode & status)713 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
714 {
715     if (U_SUCCESS(status)) {
716         CFactory* f = new CFactory(toAdopt, status);
717         if (f) {
718             return getService()->registerFactory(f, status);
719         }
720         status = U_MEMORY_ALLOCATION_ERROR;
721     }
722     return NULL;
723 }
724 
725 // -------------------------------------
726 
727 UBool U_EXPORT2
unregister(URegistryKey key,UErrorCode & status)728 Collator::unregister(URegistryKey key, UErrorCode& status)
729 {
730     if (U_SUCCESS(status)) {
731         if (hasService()) {
732             return gService->unregister(key, status);
733         }
734         status = U_ILLEGAL_ARGUMENT_ERROR;
735     }
736     return FALSE;
737 }
738 #endif /* UCONFIG_NO_SERVICE */
739 
740 class CollationLocaleListEnumeration : public StringEnumeration {
741 private:
742     int32_t index;
743 public:
744     static UClassID U_EXPORT2 getStaticClassID(void);
745     virtual UClassID getDynamicClassID(void) const;
746 public:
CollationLocaleListEnumeration()747     CollationLocaleListEnumeration()
748         : index(0)
749     {
750         // The global variables should already be initialized.
751         //isAvailableLocaleListInitialized(status);
752     }
753 
754     virtual ~CollationLocaleListEnumeration();
755 
clone() const756     virtual StringEnumeration * clone() const
757     {
758         CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
759         if (result) {
760             result->index = index;
761         }
762         return result;
763     }
764 
count(UErrorCode &) const765     virtual int32_t count(UErrorCode &/*status*/) const {
766         return availableLocaleListCount;
767     }
768 
next(int32_t * resultLength,UErrorCode &)769     virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
770         const char* result;
771         if(index < availableLocaleListCount) {
772             result = availableLocaleList[index++].getName();
773             if(resultLength != NULL) {
774                 *resultLength = (int32_t)uprv_strlen(result);
775             }
776         } else {
777             if(resultLength != NULL) {
778                 *resultLength = 0;
779             }
780             result = NULL;
781         }
782         return result;
783     }
784 
snext(UErrorCode & status)785     virtual const UnicodeString* snext(UErrorCode& status) {
786         int32_t resultLength = 0;
787         const char *s = next(&resultLength, status);
788         return setChars(s, resultLength, status);
789     }
790 
reset(UErrorCode &)791     virtual void reset(UErrorCode& /*status*/) {
792         index = 0;
793     }
794 };
795 
~CollationLocaleListEnumeration()796 CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {}
797 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)798 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
799 
800 
801 // -------------------------------------
802 
803 StringEnumeration* U_EXPORT2
804 Collator::getAvailableLocales(void)
805 {
806 #if !UCONFIG_NO_SERVICE
807     if (hasService()) {
808         return getService()->getAvailableLocales();
809     }
810 #endif /* UCONFIG_NO_SERVICE */
811     UErrorCode status = U_ZERO_ERROR;
812     if (isAvailableLocaleListInitialized(status)) {
813         return new CollationLocaleListEnumeration();
814     }
815     return NULL;
816 }
817 
818 StringEnumeration* U_EXPORT2
getKeywords(UErrorCode & status)819 Collator::getKeywords(UErrorCode& status) {
820     // This is a wrapper over ucol_getKeywords
821     UEnumeration* uenum = ucol_getKeywords(&status);
822     if (U_FAILURE(status)) {
823         uenum_close(uenum);
824         return NULL;
825     }
826     return new UStringEnumeration(uenum);
827 }
828 
829 StringEnumeration* U_EXPORT2
getKeywordValues(const char * keyword,UErrorCode & status)830 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
831     // This is a wrapper over ucol_getKeywordValues
832     UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
833     if (U_FAILURE(status)) {
834         uenum_close(uenum);
835         return NULL;
836     }
837     return new UStringEnumeration(uenum);
838 }
839 
840 StringEnumeration* U_EXPORT2
getKeywordValuesForLocale(const char * key,const Locale & locale,UBool commonlyUsed,UErrorCode & status)841 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
842                                     UBool commonlyUsed, UErrorCode& status) {
843     // This is a wrapper over ucol_getKeywordValuesForLocale
844     UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(),
845                                                         commonlyUsed, &status);
846     if (U_FAILURE(status)) {
847         uenum_close(uenum);
848         return NULL;
849     }
850     return new UStringEnumeration(uenum);
851 }
852 
853 Locale U_EXPORT2
getFunctionalEquivalent(const char * keyword,const Locale & locale,UBool & isAvailable,UErrorCode & status)854 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
855                                   UBool& isAvailable, UErrorCode& status) {
856     // This is a wrapper over ucol_getFunctionalEquivalent
857     char loc[ULOC_FULLNAME_CAPACITY];
858     /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
859                     keyword, locale.getName(), &isAvailable, &status);
860     if (U_FAILURE(status)) {
861         *loc = 0; // root
862     }
863     return Locale::createFromName(loc);
864 }
865 
866 Collator::ECollationStrength
getStrength(void) const867 Collator::getStrength(void) const {
868     UErrorCode intStatus = U_ZERO_ERROR;
869     return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus);
870 }
871 
872 void
setStrength(ECollationStrength newStrength)873 Collator::setStrength(ECollationStrength newStrength) {
874     UErrorCode intStatus = U_ZERO_ERROR;
875     setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus);
876 }
877 
878 int32_t
getReorderCodes(int32_t *,int32_t,UErrorCode & status) const879 Collator::getReorderCodes(int32_t* /* dest*/,
880                           int32_t /* destCapacity*/,
881                           UErrorCode& status) const
882 {
883     if (U_SUCCESS(status)) {
884         status = U_UNSUPPORTED_ERROR;
885     }
886     return 0;
887 }
888 
889 void
setReorderCodes(const int32_t *,int32_t,UErrorCode & status)890 Collator::setReorderCodes(const int32_t* /* reorderCodes */,
891                           int32_t /* reorderCodesLength */,
892                           UErrorCode& status)
893 {
894     if (U_SUCCESS(status)) {
895         status = U_UNSUPPORTED_ERROR;
896     }
897 }
898 
899 int32_t U_EXPORT2
getEquivalentReorderCodes(int32_t,int32_t *,int32_t,UErrorCode & status)900 Collator::getEquivalentReorderCodes(int32_t /* reorderCode */,
901                                     int32_t* /* dest */,
902                                     int32_t /* destCapacity */,
903                                     UErrorCode& status)
904 {
905     if (U_SUCCESS(status)) {
906         status = U_UNSUPPORTED_ERROR;
907     }
908     return 0;
909 }
910 
911 int32_t
internalGetShortDefinitionString(const char *,char *,int32_t,UErrorCode & status) const912 Collator::internalGetShortDefinitionString(const char * /*locale*/,
913                                                              char * /*buffer*/,
914                                                              int32_t /*capacity*/,
915                                                              UErrorCode &status) const {
916   if(U_SUCCESS(status)) {
917     status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */
918   }
919   return 0;
920 }
921 
922 // UCollator private data members ----------------------------------------
923 
924 /* This is useless information */
925 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
926 
927 // -------------------------------------
928 
929 U_NAMESPACE_END
930 
931 #endif /* #if !UCONFIG_NO_COLLATION */
932 
933 /* eof */
934