• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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