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