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