1 /*
2 ******************************************************************************
3 * Copyright (C) 1996-2007, 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 "ucln_in.h"
53
54 static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL;
55 static int32_t availableLocaleListCount;
56 static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
57
58 /**
59 * Release all static memory held by collator.
60 */
61 U_CDECL_BEGIN
collator_cleanup(void)62 static UBool U_CALLCONV collator_cleanup(void) {
63 #if !UCONFIG_NO_SERVICE
64 if (gService) {
65 delete gService;
66 gService = NULL;
67 }
68 #endif
69 if (availableLocaleList) {
70 delete []availableLocaleList;
71 availableLocaleList = NULL;
72 }
73 availableLocaleListCount = 0;
74
75 return TRUE;
76 }
77
78 U_CDECL_END
79
80 U_NAMESPACE_BEGIN
81
82 #if !UCONFIG_NO_SERVICE
83
84 // ------------------------------------------
85 //
86 // Registration
87 //
88
89 //-------------------------------------------
90
~CollatorFactory()91 CollatorFactory::~CollatorFactory() {}
92
93 //-------------------------------------------
94
95 UBool
visible(void) const96 CollatorFactory::visible(void) const {
97 return TRUE;
98 }
99
100 //-------------------------------------------
101
102 UnicodeString&
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & result)103 CollatorFactory::getDisplayName(const Locale& objectLocale,
104 const Locale& displayLocale,
105 UnicodeString& result)
106 {
107 return objectLocale.getDisplayName(displayLocale, result);
108 }
109
110 // -------------------------------------
111
112 class ICUCollatorFactory : public ICUResourceBundleFactory {
113 public:
ICUCollatorFactory()114 ICUCollatorFactory(): ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
115 protected:
116 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
117 };
118
119 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const120 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
121 if (handlesKey(key, status)) {
122 const LocaleKey& lkey = (const LocaleKey&)key;
123 Locale loc;
124 // make sure the requested locale is correct
125 // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
126 // but for ICU rb resources we use the actual one since it will fallback again
127 lkey.canonicalLocale(loc);
128
129 return Collator::makeInstance(loc, status);
130 }
131 return NULL;
132 }
133
134 // -------------------------------------
135
136 class ICUCollatorService : public ICULocaleService {
137 public:
ICUCollatorService()138 ICUCollatorService()
139 : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
140 {
141 UErrorCode status = U_ZERO_ERROR;
142 registerFactory(new ICUCollatorFactory(), status);
143 }
144
cloneInstance(UObject * instance) const145 virtual UObject* cloneInstance(UObject* instance) const {
146 return ((Collator*)instance)->clone();
147 }
148
handleDefault(const ICUServiceKey & key,UnicodeString * actualID,UErrorCode & status) const149 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
150 LocaleKey& lkey = (LocaleKey&)key;
151 if (actualID) {
152 // Ugly Hack Alert! We return an empty actualID to signal
153 // to callers that this is a default object, not a "real"
154 // service-created object. (TODO remove in 3.0) [aliu]
155 actualID->truncate(0);
156 }
157 Locale loc("");
158 lkey.canonicalLocale(loc);
159 return Collator::makeInstance(loc, status);
160 }
161
getKey(ICUServiceKey & key,UnicodeString * actualReturn,UErrorCode & status) const162 virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
163 UnicodeString ar;
164 if (actualReturn == NULL) {
165 actualReturn = &ar;
166 }
167 Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status);
168 // Ugly Hack Alert! If the actualReturn length is zero, this
169 // means we got a default object, not a "real" service-created
170 // object. We don't call setLocales() on a default object,
171 // because that will overwrite its correct built-in locale
172 // metadata (valid & actual) with our incorrect data (all we
173 // have is the requested locale). (TODO remove in 3.0) [aliu]
174 if (result && actualReturn->length() > 0) {
175 const LocaleKey& lkey = (const LocaleKey&)key;
176 Locale canonicalLocale("");
177 Locale currentLocale("");
178
179 result->setLocales(lkey.canonicalLocale(canonicalLocale),
180 LocaleUtility::initLocaleFromName(*actualReturn, currentLocale));
181 }
182 return result;
183 }
184
isDefault() const185 virtual UBool isDefault() const {
186 return countFactories() == 1;
187 }
188 };
189
190 // -------------------------------------
191
192 static ICULocaleService*
getService(void)193 getService(void)
194 {
195 UBool needInit;
196 UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
197 if(needInit) {
198 ICULocaleService *newservice = new ICUCollatorService();
199 if(newservice) {
200 umtx_lock(NULL);
201 if(gService == NULL) {
202 gService = newservice;
203 newservice = NULL;
204 }
205 umtx_unlock(NULL);
206 }
207 if(newservice) {
208 delete newservice;
209 }
210 else {
211 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
212 }
213 }
214 return gService;
215 }
216
217 // -------------------------------------
218
219 static inline UBool
hasService(void)220 hasService(void)
221 {
222 UBool retVal;
223 UMTX_CHECK(NULL, gService != NULL, retVal);
224 return retVal;
225 }
226
227 // -------------------------------------
228
229 UCollator*
createUCollator(const char * loc,UErrorCode * status)230 Collator::createUCollator(const char *loc,
231 UErrorCode *status)
232 {
233 UCollator *result = 0;
234 if (status && U_SUCCESS(*status) && hasService()) {
235 Locale desiredLocale(loc);
236 Collator *col = (Collator*)gService->get(desiredLocale, *status);
237 if (col && col->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
238 RuleBasedCollator *rbc = (RuleBasedCollator *)col;
239 if (!rbc->dataIsOwned) {
240 result = ucol_safeClone(rbc->ucollator, NULL, NULL, status);
241 } else {
242 result = rbc->ucollator;
243 rbc->ucollator = NULL; // to prevent free on delete
244 }
245 }
246 delete col;
247 }
248 return result;
249 }
250 #endif /* UCONFIG_NO_SERVICE */
251
isAvailableLocaleListInitialized(UErrorCode & status)252 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
253 // for now, there is a hardcoded list, so just walk through that list and set it up.
254 UBool needInit;
255 UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
256
257 if (needInit) {
258 UResourceBundle *index = NULL;
259 UResourceBundle installed;
260 Locale * temp;
261 int32_t i = 0;
262 int32_t localeCount;
263
264 ures_initStackObject(&installed);
265 index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
266 ures_getByKey(index, "InstalledLocales", &installed, &status);
267
268 if(U_SUCCESS(status)) {
269 localeCount = ures_getSize(&installed);
270 temp = new Locale[localeCount];
271
272 if (temp != NULL) {
273 ures_resetIterator(&installed);
274 while(ures_hasNext(&installed)) {
275 const char *tempKey = NULL;
276 ures_getNextString(&installed, NULL, &tempKey, &status);
277 temp[i++] = Locale(tempKey);
278 }
279
280 umtx_lock(NULL);
281 if (availableLocaleList == NULL)
282 {
283 availableLocaleList = temp;
284 availableLocaleListCount = localeCount;
285 temp = NULL;
286 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
287 }
288 umtx_unlock(NULL);
289
290 needInit = FALSE;
291 if (temp) {
292 delete []temp;
293 }
294 }
295
296 ures_close(&installed);
297 }
298 ures_close(index);
299 }
300 return !needInit;
301 }
302
303 // Collator public methods -----------------------------------------------
304
createInstance(UErrorCode & success)305 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
306 {
307 return createInstance(Locale::getDefault(), success);
308 }
309
createInstance(const Locale & desiredLocale,UErrorCode & status)310 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
311 UErrorCode& status)
312 {
313 if (U_FAILURE(status))
314 return 0;
315
316 #if !UCONFIG_NO_SERVICE
317 if (hasService()) {
318 Locale actualLoc;
319 Collator *result =
320 (Collator*)gService->get(desiredLocale, &actualLoc, status);
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);
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 if 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 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target) const407 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
408 const UnicodeString& target) const
409 {
410 UErrorCode ec = U_ZERO_ERROR;
411 return (Collator::EComparisonResult)compare(source, target, ec);
412 }
413
414 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target,int32_t length) const415 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
416 const UnicodeString& target,
417 int32_t length) const
418 {
419 UErrorCode ec = U_ZERO_ERROR;
420 return (Collator::EComparisonResult)compare(source, target, length, ec);
421 }
422
423 // implement deprecated, previously abstract method
compare(const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength) const424 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
425 const UChar* target, int32_t targetLength)
426 const
427 {
428 UErrorCode ec = U_ZERO_ERROR;
429 return (Collator::EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
430 }
431
equals(const UnicodeString & source,const UnicodeString & target) const432 UBool Collator::equals(const UnicodeString& source,
433 const UnicodeString& target) const
434 {
435 UErrorCode ec = U_ZERO_ERROR;
436 return (compare(source, target, ec) == UCOL_EQUAL);
437 }
438
greaterOrEqual(const UnicodeString & source,const UnicodeString & target) const439 UBool Collator::greaterOrEqual(const UnicodeString& source,
440 const UnicodeString& target) const
441 {
442 UErrorCode ec = U_ZERO_ERROR;
443 return (compare(source, target, ec) != UCOL_LESS);
444 }
445
greater(const UnicodeString & source,const UnicodeString & target) const446 UBool Collator::greater(const UnicodeString& source,
447 const UnicodeString& target) const
448 {
449 UErrorCode ec = U_ZERO_ERROR;
450 return (compare(source, target, ec) == UCOL_GREATER);
451 }
452
453 // this API ignores registered collators, since it returns an
454 // array of indefinite lifetime
getAvailableLocales(int32_t & count)455 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
456 {
457 UErrorCode status = U_ZERO_ERROR;
458 Locale *result = NULL;
459 count = 0;
460 if (isAvailableLocaleListInitialized(status))
461 {
462 result = availableLocaleList;
463 count = availableLocaleListCount;
464 }
465 return result;
466 }
467
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & name)468 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
469 const Locale& displayLocale,
470 UnicodeString& name)
471 {
472 #if !UCONFIG_NO_SERVICE
473 if (hasService()) {
474 UnicodeString locNameStr;
475 LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
476 return gService->getDisplayName(locNameStr, name, displayLocale);
477 }
478 #endif
479 return objectLocale.getDisplayName(displayLocale, name);
480 }
481
getDisplayName(const Locale & objectLocale,UnicodeString & name)482 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
483 UnicodeString& name)
484 {
485 return getDisplayName(objectLocale, Locale::getDefault(), name);
486 }
487
488 /* This is useless information */
489 /*void Collator::getVersion(UVersionInfo versionInfo) const
490 {
491 if (versionInfo!=NULL)
492 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
493 }
494 */
495
496 // UCollator protected constructor destructor ----------------------------
497
498 /**
499 * Default constructor.
500 * Constructor is different from the old default Collator constructor.
501 * The task for determing the default collation strength and normalization mode
502 * is left to the child class.
503 */
Collator()504 Collator::Collator()
505 : UObject()
506 {
507 }
508
509 /**
510 * Constructor.
511 * Empty constructor, does not handle the arguments.
512 * This constructor is done for backward compatibility with 1.7 and 1.8.
513 * The task for handling the argument collation strength and normalization
514 * mode is left to the child class.
515 * @param collationStrength collation strength
516 * @param decompositionMode
517 * @deprecated 2.4 use the default constructor instead
518 */
Collator(UCollationStrength,UNormalizationMode)519 Collator::Collator(UCollationStrength, UNormalizationMode )
520 : UObject()
521 {
522 }
523
~Collator()524 Collator::~Collator()
525 {
526 }
527
Collator(const Collator & other)528 Collator::Collator(const Collator &other)
529 : UObject(other)
530 {
531 }
532
operator ==(const Collator & other) const533 UBool Collator::operator==(const Collator& other) const
534 {
535 return (UBool)(this == &other);
536 }
537
operator !=(const Collator & other) const538 UBool Collator::operator!=(const Collator& other) const
539 {
540 return (UBool)!(*this == other);
541 }
542
getBound(const uint8_t * source,int32_t sourceLength,UColBoundMode boundType,uint32_t noOfLevels,uint8_t * result,int32_t resultLength,UErrorCode & status)543 int32_t U_EXPORT2 Collator::getBound(const uint8_t *source,
544 int32_t sourceLength,
545 UColBoundMode boundType,
546 uint32_t noOfLevels,
547 uint8_t *result,
548 int32_t resultLength,
549 UErrorCode &status)
550 {
551 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
552 }
553
554 void
setLocales(const Locale &,const Locale &)555 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */) {
556 }
557
getTailoredSet(UErrorCode & status) const558 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
559 {
560 if(U_FAILURE(status)) {
561 return NULL;
562 }
563 // everything can be changed
564 return new UnicodeSet(0, 0x10FFFF);
565 }
566
567 // -------------------------------------
568
569 #if !UCONFIG_NO_SERVICE
570 URegistryKey U_EXPORT2
registerInstance(Collator * toAdopt,const Locale & locale,UErrorCode & status)571 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
572 {
573 if (U_SUCCESS(status)) {
574 return getService()->registerInstance(toAdopt, locale, status);
575 }
576 return NULL;
577 }
578
579 // -------------------------------------
580
581 class CFactory : public LocaleKeyFactory {
582 private:
583 CollatorFactory* _delegate;
584 Hashtable* _ids;
585
586 public:
CFactory(CollatorFactory * delegate,UErrorCode & status)587 CFactory(CollatorFactory* delegate, UErrorCode& status)
588 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
589 , _delegate(delegate)
590 , _ids(NULL)
591 {
592 if (U_SUCCESS(status)) {
593 int32_t count = 0;
594 _ids = new Hashtable(status);
595 if (_ids) {
596 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
597 for (int i = 0; i < count; ++i) {
598 _ids->put(idlist[i], (void*)this, status);
599 if (U_FAILURE(status)) {
600 delete _ids;
601 _ids = NULL;
602 return;
603 }
604 }
605 } else {
606 status = U_MEMORY_ALLOCATION_ERROR;
607 }
608 }
609 }
610
~CFactory()611 virtual ~CFactory()
612 {
613 delete _delegate;
614 delete _ids;
615 }
616
617 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
618
619 protected:
getSupportedIDs(UErrorCode & status) const620 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
621 {
622 if (U_SUCCESS(status)) {
623 return _ids;
624 }
625 return NULL;
626 }
627
628 virtual UnicodeString&
629 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
630 };
631
632 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const633 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
634 {
635 if (handlesKey(key, status)) {
636 const LocaleKey& lkey = (const LocaleKey&)key;
637 Locale validLoc;
638 lkey.currentLocale(validLoc);
639 return _delegate->createCollator(validLoc);
640 }
641 return NULL;
642 }
643
644 UnicodeString&
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const645 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
646 {
647 if ((_coverage & 0x1) == 0) {
648 UErrorCode status = U_ZERO_ERROR;
649 const Hashtable* ids = getSupportedIDs(status);
650 if (ids && (ids->get(id) != NULL)) {
651 Locale loc;
652 LocaleUtility::initLocaleFromName(id, loc);
653 return _delegate->getDisplayName(loc, locale, result);
654 }
655 }
656 result.setToBogus();
657 return result;
658 }
659
660 URegistryKey U_EXPORT2
registerFactory(CollatorFactory * toAdopt,UErrorCode & status)661 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
662 {
663 if (U_SUCCESS(status)) {
664 CFactory* f = new CFactory(toAdopt, status);
665 if (f) {
666 return getService()->registerFactory(f, status);
667 }
668 status = U_MEMORY_ALLOCATION_ERROR;
669 }
670 return NULL;
671 }
672
673 // -------------------------------------
674
675 UBool U_EXPORT2
unregister(URegistryKey key,UErrorCode & status)676 Collator::unregister(URegistryKey key, UErrorCode& status)
677 {
678 if (U_SUCCESS(status)) {
679 if (hasService()) {
680 return gService->unregister(key, status);
681 }
682 status = U_ILLEGAL_ARGUMENT_ERROR;
683 }
684 return FALSE;
685 }
686 #endif /* UCONFIG_NO_SERVICE */
687
688 class CollationLocaleListEnumeration : public StringEnumeration {
689 private:
690 int32_t index;
691 public:
692 static UClassID U_EXPORT2 getStaticClassID(void);
693 virtual UClassID getDynamicClassID(void) const;
694 public:
CollationLocaleListEnumeration()695 CollationLocaleListEnumeration()
696 : index(0)
697 {
698 // The global variables should already be initialized.
699 //isAvailableLocaleListInitialized(status);
700 }
701
~CollationLocaleListEnumeration()702 virtual ~CollationLocaleListEnumeration() {
703 }
704
clone() const705 virtual StringEnumeration * clone() const
706 {
707 CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
708 result->index = index;
709 return result;
710 }
711
count(UErrorCode &) const712 virtual int32_t count(UErrorCode &/*status*/) const {
713 return availableLocaleListCount;
714 }
715
next(int32_t * resultLength,UErrorCode &)716 virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
717 const char* result;
718 if(index < availableLocaleListCount) {
719 result = availableLocaleList[index++].getName();
720 if(resultLength != NULL) {
721 *resultLength = uprv_strlen(result);
722 }
723 } else {
724 if(resultLength != NULL) {
725 *resultLength = 0;
726 }
727 result = NULL;
728 }
729 return result;
730 }
731
snext(UErrorCode & status)732 virtual const UnicodeString* snext(UErrorCode& status) {
733 int32_t resultLength = 0;
734 const char *s = next(&resultLength, status);
735 return setChars(s, resultLength, status);
736 }
737
reset(UErrorCode &)738 virtual void reset(UErrorCode& /*status*/) {
739 index = 0;
740 }
741 };
742
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)743 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
744
745
746 // -------------------------------------
747
748 StringEnumeration* U_EXPORT2
749 Collator::getAvailableLocales(void)
750 {
751 #if !UCONFIG_NO_SERVICE
752 if (hasService()) {
753 return getService()->getAvailableLocales();
754 }
755 #endif /* UCONFIG_NO_SERVICE */
756 UErrorCode status = U_ZERO_ERROR;
757 if (isAvailableLocaleListInitialized(status)) {
758 return new CollationLocaleListEnumeration();
759 }
760 return NULL;
761 }
762
763 StringEnumeration* U_EXPORT2
getKeywords(UErrorCode & status)764 Collator::getKeywords(UErrorCode& status) {
765 // This is a wrapper over ucol_getKeywords
766 UEnumeration* uenum = ucol_getKeywords(&status);
767 if (U_FAILURE(status)) {
768 uenum_close(uenum);
769 return NULL;
770 }
771 return new UStringEnumeration(uenum);
772 }
773
774 StringEnumeration* U_EXPORT2
getKeywordValues(const char * keyword,UErrorCode & status)775 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
776 // This is a wrapper over ucol_getKeywordValues
777 UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
778 if (U_FAILURE(status)) {
779 uenum_close(uenum);
780 return NULL;
781 }
782 return new UStringEnumeration(uenum);
783 }
784
785 Locale U_EXPORT2
getFunctionalEquivalent(const char * keyword,const Locale & locale,UBool & isAvailable,UErrorCode & status)786 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
787 UBool& isAvailable, UErrorCode& status) {
788 // This is a wrapper over ucol_getFunctionalEquivalent
789 char loc[ULOC_FULLNAME_CAPACITY];
790 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
791 keyword, locale.getName(), &isAvailable, &status);
792 if (U_FAILURE(status)) {
793 *loc = 0; // root
794 }
795 return Locale::createFromName(loc);
796 }
797
798 // UCollator private data members ----------------------------------------
799
800 /* This is useless information */
801 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
802
803 // -------------------------------------
804
805 U_NAMESPACE_END
806
807 #endif /* #if !UCONFIG_NO_COLLATION */
808
809 /* eof */
810