]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/coll.cpp
ICU-62107.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / coll.cpp
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 * Copyright (C) 1996-2014, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ******************************************************************************
8 */
9
10 /**
11 * File coll.cpp
12 *
13 * Created by: Helena Shih
14 *
15 * Modification History:
16 *
17 * Date Name Description
18 * 2/5/97 aliu Modified createDefault to load collation data from
19 * binary files when possible. Added related methods
20 * createCollationFromFile, chopLocale, createPathName.
21 * 2/11/97 aliu Added methods addToCache, findInCache, which implement
22 * a Collation cache. Modified createDefault to look in
23 * cache first, and also to store newly created Collation
24 * objects in the cache. Modified to not use gLocPath.
25 * 2/12/97 aliu Modified to create objects from RuleBasedCollator cache.
26 * Moved cache out of Collation class.
27 * 2/13/97 aliu Moved several methods out of this class and into
28 * RuleBasedCollator, with modifications. Modified
29 * createDefault() to call new RuleBasedCollator(Locale&)
30 * constructor. General clean up and documentation.
31 * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy
32 * constructor.
33 * 05/06/97 helena Added memory allocation error detection.
34 * 05/08/97 helena Added createInstance().
35 * 6/20/97 helena Java class name change.
36 * 04/23/99 stephen Removed EDecompositionMode, merged with
37 * Normalizer::EMode
38 * 11/23/9 srl Inlining of some critical functions
39 * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h)
40 * 2012-2014 markus Rewritten in C++ again.
41 */
42
43 #include "utypeinfo.h" // for 'typeid' to work
44
45 #include "unicode/utypes.h"
46
47 #if !UCONFIG_NO_COLLATION
48
49 #include "unicode/coll.h"
50 #include "unicode/tblcoll.h"
51 #include "collationdata.h"
52 #include "collationroot.h"
53 #include "collationtailoring.h"
54 #include "ucol_imp.h"
55 #include "cstring.h"
56 #include "cmemory.h"
57 #include "umutex.h"
58 #include "servloc.h"
59 #include "uassert.h"
60 #include "ustrenum.h"
61 #include "uresimp.h"
62 #include "ucln_in.h"
63 #if U_PLATFORM_IS_DARWIN_BASED
64 #include <os/log.h>
65 #endif
66
67 static icu::Locale* availableLocaleList = NULL;
68 static int32_t availableLocaleListCount;
69 #if !UCONFIG_NO_SERVICE
70 static icu::ICULocaleService* gService = NULL;
71 static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
72 #endif
73 static icu::UInitOnce gAvailableLocaleListInitOnce;
74
75 /**
76 * Release all static memory held by collator.
77 */
78 U_CDECL_BEGIN
79 static UBool U_CALLCONV collator_cleanup(void) {
80 #if !UCONFIG_NO_SERVICE
81 if (gService) {
82 delete gService;
83 gService = NULL;
84 }
85 gServiceInitOnce.reset();
86 #endif
87 if (availableLocaleList) {
88 delete []availableLocaleList;
89 availableLocaleList = NULL;
90 }
91 availableLocaleListCount = 0;
92 gAvailableLocaleListInitOnce.reset();
93 return TRUE;
94 }
95
96 U_CDECL_END
97
98 U_NAMESPACE_BEGIN
99
100 #if !UCONFIG_NO_SERVICE
101
102 // ------------------------------------------
103 //
104 // Registration
105 //
106
107 //-------------------------------------------
108
109 CollatorFactory::~CollatorFactory() {}
110
111 //-------------------------------------------
112
113 UBool
114 CollatorFactory::visible(void) const {
115 return TRUE;
116 }
117
118 //-------------------------------------------
119
120 UnicodeString&
121 CollatorFactory::getDisplayName(const Locale& objectLocale,
122 const Locale& displayLocale,
123 UnicodeString& result)
124 {
125 return objectLocale.getDisplayName(displayLocale, result);
126 }
127
128 // -------------------------------------
129
130 class ICUCollatorFactory : public ICUResourceBundleFactory {
131 public:
132 ICUCollatorFactory() : ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
133 virtual ~ICUCollatorFactory();
134 protected:
135 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
136 };
137
138 ICUCollatorFactory::~ICUCollatorFactory() {}
139
140 UObject*
141 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
142 if (handlesKey(key, status)) {
143 const LocaleKey& lkey = (const LocaleKey&)key;
144 Locale loc;
145 // make sure the requested locale is correct
146 // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
147 // but for ICU rb resources we use the actual one since it will fallback again
148 lkey.canonicalLocale(loc);
149
150 return Collator::makeInstance(loc, status);
151 }
152 return NULL;
153 }
154
155 // -------------------------------------
156
157 class ICUCollatorService : public ICULocaleService {
158 public:
159 ICUCollatorService()
160 : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
161 {
162 UErrorCode status = U_ZERO_ERROR;
163 registerFactory(new ICUCollatorFactory(), status);
164 }
165
166 virtual ~ICUCollatorService();
167
168 virtual UObject* cloneInstance(UObject* instance) const {
169 return ((Collator*)instance)->clone();
170 }
171
172 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
173 LocaleKey& lkey = (LocaleKey&)key;
174 if (actualID) {
175 // Ugly Hack Alert! We return an empty actualID to signal
176 // to callers that this is a default object, not a "real"
177 // service-created object. (TODO remove in 3.0) [aliu]
178 actualID->truncate(0);
179 }
180 Locale loc("");
181 lkey.canonicalLocale(loc);
182 return Collator::makeInstance(loc, status);
183 }
184
185 virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
186 UnicodeString ar;
187 if (actualReturn == NULL) {
188 actualReturn = &ar;
189 }
190 return (Collator*)ICULocaleService::getKey(key, actualReturn, status);
191 }
192
193 virtual UBool isDefault() const {
194 return countFactories() == 1;
195 }
196 };
197
198 ICUCollatorService::~ICUCollatorService() {}
199
200 // -------------------------------------
201
202 static void U_CALLCONV initService() {
203 gService = new ICUCollatorService();
204 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
205 }
206
207
208 static ICULocaleService*
209 getService(void)
210 {
211 umtx_initOnce(gServiceInitOnce, &initService);
212 return gService;
213 }
214
215 // -------------------------------------
216
217 static inline UBool
218 hasService(void)
219 {
220 UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL);
221 return retVal;
222 }
223
224 #endif /* UCONFIG_NO_SERVICE */
225
226 static void U_CALLCONV
227 initAvailableLocaleList(UErrorCode &status) {
228 U_ASSERT(availableLocaleListCount == 0);
229 U_ASSERT(availableLocaleList == NULL);
230 // for now, there is a hardcoded list, so just walk through that list and set it up.
231 UResourceBundle *index = NULL;
232 UResourceBundle installed;
233 int32_t i = 0;
234
235 ures_initStackObject(&installed);
236 index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
237 ures_getByKey(index, "InstalledLocales", &installed, &status);
238
239 if(U_SUCCESS(status)) {
240 availableLocaleListCount = ures_getSize(&installed);
241 availableLocaleList = new Locale[availableLocaleListCount];
242
243 if (availableLocaleList != NULL) {
244 ures_resetIterator(&installed);
245 while(ures_hasNext(&installed)) {
246 const char *tempKey = NULL;
247 ures_getNextString(&installed, NULL, &tempKey, &status);
248 availableLocaleList[i++] = Locale(tempKey);
249 }
250 }
251 U_ASSERT(availableLocaleListCount == i);
252 ures_close(&installed);
253 }
254 ures_close(index);
255 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
256 }
257
258 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
259 umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status);
260 return U_SUCCESS(status);
261 }
262
263
264 // Collator public methods -----------------------------------------------
265
266 namespace {
267
268 static const struct {
269 const char *name;
270 UColAttribute attr;
271 } collAttributes[] = {
272 { "colStrength", UCOL_STRENGTH },
273 { "colBackwards", UCOL_FRENCH_COLLATION },
274 { "colCaseLevel", UCOL_CASE_LEVEL },
275 { "colCaseFirst", UCOL_CASE_FIRST },
276 { "colAlternate", UCOL_ALTERNATE_HANDLING },
277 { "colNormalization", UCOL_NORMALIZATION_MODE },
278 { "colNumeric", UCOL_NUMERIC_COLLATION }
279 };
280
281 static const struct {
282 const char *name;
283 UColAttributeValue value;
284 } collAttributeValues[] = {
285 { "primary", UCOL_PRIMARY },
286 { "secondary", UCOL_SECONDARY },
287 { "tertiary", UCOL_TERTIARY },
288 { "quaternary", UCOL_QUATERNARY },
289 // Note: Not supporting typo "quarternary" because it was never supported in locale IDs.
290 { "identical", UCOL_IDENTICAL },
291 { "no", UCOL_OFF },
292 { "yes", UCOL_ON },
293 { "shifted", UCOL_SHIFTED },
294 { "non-ignorable", UCOL_NON_IGNORABLE },
295 { "lower", UCOL_LOWER_FIRST },
296 { "upper", UCOL_UPPER_FIRST }
297 };
298
299 static const char *collReorderCodes[UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST] = {
300 "space", "punct", "symbol", "currency", "digit"
301 };
302
303 int32_t getReorderCode(const char *s) {
304 for (int32_t i = 0; i < UPRV_LENGTHOF(collReorderCodes); ++i) {
305 if (uprv_stricmp(s, collReorderCodes[i]) == 0) {
306 return UCOL_REORDER_CODE_FIRST + i;
307 }
308 }
309 // Not supporting "others" = UCOL_REORDER_CODE_OTHERS
310 // as a synonym for Zzzz = USCRIPT_UNKNOWN for now:
311 // Avoid introducing synonyms/aliases.
312 return -1;
313 }
314
315 /**
316 * Sets collation attributes according to locale keywords. See
317 * http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings
318 *
319 * Using "alias" keywords and values where defined:
320 * http://www.unicode.org/reports/tr35/tr35.html#Old_Locale_Extension_Syntax
321 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
322 */
323 void setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) {
324 if (U_FAILURE(errorCode)) {
325 return;
326 }
327 if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) {
328 // No keywords.
329 return;
330 }
331 char value[1024]; // The reordering value could be long.
332 // Check for collation keywords that were already deprecated
333 // before any were supported in createInstance() (except for "collation").
334 int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, UPRV_LENGTHOF(value), errorCode);
335 if (U_FAILURE(errorCode)) {
336 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
337 return;
338 }
339 if (length != 0) {
340 errorCode = U_UNSUPPORTED_ERROR;
341 return;
342 }
343 length = loc.getKeywordValue("variableTop", value, UPRV_LENGTHOF(value), errorCode);
344 if (U_FAILURE(errorCode)) {
345 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
346 return;
347 }
348 if (length != 0) {
349 errorCode = U_UNSUPPORTED_ERROR;
350 return;
351 }
352 // Parse known collation keywords, ignore others.
353 if (errorCode == U_STRING_NOT_TERMINATED_WARNING) {
354 errorCode = U_ZERO_ERROR;
355 }
356 for (int32_t i = 0; i < UPRV_LENGTHOF(collAttributes); ++i) {
357 length = loc.getKeywordValue(collAttributes[i].name, value, UPRV_LENGTHOF(value), errorCode);
358 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
359 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
360 return;
361 }
362 if (length == 0) { continue; }
363 for (int32_t j = 0;; ++j) {
364 if (j == UPRV_LENGTHOF(collAttributeValues)) {
365 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
366 return;
367 }
368 if (uprv_stricmp(value, collAttributeValues[j].name) == 0) {
369 coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode);
370 break;
371 }
372 }
373 }
374 length = loc.getKeywordValue("colReorder", value, UPRV_LENGTHOF(value), errorCode);
375 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
376 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
377 return;
378 }
379 if (length != 0) {
380 int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST];
381 int32_t codesLength = 0;
382 char *scriptName = value;
383 for (;;) {
384 if (codesLength == UPRV_LENGTHOF(codes)) {
385 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
386 return;
387 }
388 char *limit = scriptName;
389 char c;
390 while ((c = *limit) != 0 && c != '-') { ++limit; }
391 *limit = 0;
392 int32_t code;
393 if ((limit - scriptName) == 4) {
394 // Strict parsing, accept only 4-letter script codes, not long names.
395 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName);
396 } else {
397 code = getReorderCode(scriptName);
398 }
399 if (code < 0) {
400 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
401 return;
402 }
403 codes[codesLength++] = code;
404 if (c == 0) { break; }
405 scriptName = limit + 1;
406 }
407 coll.setReorderCodes(codes, codesLength, errorCode);
408 }
409 length = loc.getKeywordValue("kv", value, UPRV_LENGTHOF(value), errorCode);
410 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
411 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
412 return;
413 }
414 if (length != 0) {
415 int32_t code = getReorderCode(value);
416 if (code < 0) {
417 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
418 return;
419 }
420 coll.setMaxVariable((UColReorderCode)code, errorCode);
421 }
422 if (U_FAILURE(errorCode)) {
423 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
424 }
425 }
426
427 } // namespace
428
429 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
430 {
431 return createInstance(Locale::getDefault(), success);
432 }
433
434 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
435 UErrorCode& status)
436 {
437 if (U_FAILURE(status))
438 return 0;
439 if (desiredLocale.isBogus()) {
440 // Locale constructed from malformed locale ID or language tag.
441 status = U_ILLEGAL_ARGUMENT_ERROR;
442 return NULL;
443 }
444
445 Collator* coll;
446 #if !UCONFIG_NO_SERVICE
447 if (hasService()) {
448 Locale actualLoc;
449 coll = (Collator*)gService->get(desiredLocale, &actualLoc, status);
450 } else
451 #endif
452 {
453 coll = makeInstance(desiredLocale, status);
454 }
455 // makeInstance either returns NULL with U_FAILURE(status), or non-NULL with U_SUCCESS(status).
456 // The *coll in setAttributesFromKeywords causes the NULL check to be optimized out of the delete
457 // even though setAttributesFromKeywords returns immediately if U_FAILURE(status), so we add a
458 // check here and also log the locale name for failures. <rdar://problem/40930320>
459 if (U_FAILURE(status)) {
460 #if U_PLATFORM_IS_DARWIN_BASED
461 #if 0
462 // logging disabled for shipping system, can enable for internal debugging
463 const char* locname = desiredLocale.getName();
464 os_log(OS_LOG_DEFAULT, "Collator::createInstance fails with locale: %{public}s", locname? locname: "(NULL)");
465 #endif
466 #endif
467 return NULL;
468 }
469 setAttributesFromKeywords(desiredLocale, *coll, status);
470 if (U_FAILURE(status)) {
471 delete coll;
472 return NULL;
473 }
474 return coll;
475 }
476
477
478 Collator* Collator::makeInstance(const Locale& desiredLocale, UErrorCode& status) {
479 const CollationCacheEntry *entry = CollationLoader::loadTailoring(desiredLocale, status);
480 if (U_SUCCESS(status)) {
481 Collator *result = new RuleBasedCollator(entry);
482 if (result != NULL) {
483 // Both the unified cache's get() and the RBC constructor
484 // did addRef(). Undo one of them.
485 entry->removeRef();
486 return result;
487 }
488 status = U_MEMORY_ALLOCATION_ERROR;
489 }
490 if (entry != NULL) {
491 // Undo the addRef() from the cache.get().
492 entry->removeRef();
493 }
494 return NULL;
495 }
496
497 Collator *
498 Collator::safeClone() const {
499 return clone();
500 }
501
502 // implement deprecated, previously abstract method
503 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
504 const UnicodeString& target) const
505 {
506 UErrorCode ec = U_ZERO_ERROR;
507 return (EComparisonResult)compare(source, target, ec);
508 }
509
510 // implement deprecated, previously abstract method
511 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
512 const UnicodeString& target,
513 int32_t length) const
514 {
515 UErrorCode ec = U_ZERO_ERROR;
516 return (EComparisonResult)compare(source, target, length, ec);
517 }
518
519 // implement deprecated, previously abstract method
520 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
521 const UChar* target, int32_t targetLength)
522 const
523 {
524 UErrorCode ec = U_ZERO_ERROR;
525 return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
526 }
527
528 UCollationResult Collator::compare(UCharIterator &/*sIter*/,
529 UCharIterator &/*tIter*/,
530 UErrorCode &status) const {
531 if(U_SUCCESS(status)) {
532 // Not implemented in the base class.
533 status = U_UNSUPPORTED_ERROR;
534 }
535 return UCOL_EQUAL;
536 }
537
538 UCollationResult Collator::compareUTF8(const StringPiece &source,
539 const StringPiece &target,
540 UErrorCode &status) const {
541 if(U_FAILURE(status)) {
542 return UCOL_EQUAL;
543 }
544 UCharIterator sIter, tIter;
545 uiter_setUTF8(&sIter, source.data(), source.length());
546 uiter_setUTF8(&tIter, target.data(), target.length());
547 return compare(sIter, tIter, status);
548 }
549
550 UBool Collator::equals(const UnicodeString& source,
551 const UnicodeString& target) const
552 {
553 UErrorCode ec = U_ZERO_ERROR;
554 return (compare(source, target, ec) == UCOL_EQUAL);
555 }
556
557 UBool Collator::greaterOrEqual(const UnicodeString& source,
558 const UnicodeString& target) const
559 {
560 UErrorCode ec = U_ZERO_ERROR;
561 return (compare(source, target, ec) != UCOL_LESS);
562 }
563
564 UBool Collator::greater(const UnicodeString& source,
565 const UnicodeString& target) const
566 {
567 UErrorCode ec = U_ZERO_ERROR;
568 return (compare(source, target, ec) == UCOL_GREATER);
569 }
570
571 // this API ignores registered collators, since it returns an
572 // array of indefinite lifetime
573 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
574 {
575 UErrorCode status = U_ZERO_ERROR;
576 Locale *result = NULL;
577 count = 0;
578 if (isAvailableLocaleListInitialized(status))
579 {
580 result = availableLocaleList;
581 count = availableLocaleListCount;
582 }
583 return result;
584 }
585
586 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
587 const Locale& displayLocale,
588 UnicodeString& name)
589 {
590 #if !UCONFIG_NO_SERVICE
591 if (hasService()) {
592 UnicodeString locNameStr;
593 LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
594 return gService->getDisplayName(locNameStr, name, displayLocale);
595 }
596 #endif
597 return objectLocale.getDisplayName(displayLocale, name);
598 }
599
600 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
601 UnicodeString& name)
602 {
603 return getDisplayName(objectLocale, Locale::getDefault(), name);
604 }
605
606 /* This is useless information */
607 /*void Collator::getVersion(UVersionInfo versionInfo) const
608 {
609 if (versionInfo!=NULL)
610 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
611 }
612 */
613
614 // UCollator protected constructor destructor ----------------------------
615
616 /**
617 * Default constructor.
618 * Constructor is different from the old default Collator constructor.
619 * The task for determing the default collation strength and normalization mode
620 * is left to the child class.
621 */
622 Collator::Collator()
623 : UObject()
624 {
625 }
626
627 /**
628 * Constructor.
629 * Empty constructor, does not handle the arguments.
630 * This constructor is done for backward compatibility with 1.7 and 1.8.
631 * The task for handling the argument collation strength and normalization
632 * mode is left to the child class.
633 * @param collationStrength collation strength
634 * @param decompositionMode
635 * @deprecated 2.4 use the default constructor instead
636 */
637 Collator::Collator(UCollationStrength, UNormalizationMode )
638 : UObject()
639 {
640 }
641
642 Collator::~Collator()
643 {
644 }
645
646 Collator::Collator(const Collator &other)
647 : UObject(other)
648 {
649 }
650
651 UBool Collator::operator==(const Collator& other) const
652 {
653 // Subclasses: Call this method and then add more specific checks.
654 return typeid(*this) == typeid(other);
655 }
656
657 UBool Collator::operator!=(const Collator& other) const
658 {
659 return (UBool)!(*this == other);
660 }
661
662 int32_t U_EXPORT2 Collator::getBound(const uint8_t *source,
663 int32_t sourceLength,
664 UColBoundMode boundType,
665 uint32_t noOfLevels,
666 uint8_t *result,
667 int32_t resultLength,
668 UErrorCode &status)
669 {
670 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
671 }
672
673 void
674 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
675 }
676
677 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
678 {
679 if(U_FAILURE(status)) {
680 return NULL;
681 }
682 // everything can be changed
683 return new UnicodeSet(0, 0x10FFFF);
684 }
685
686 // -------------------------------------
687
688 #if !UCONFIG_NO_SERVICE
689 URegistryKey U_EXPORT2
690 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
691 {
692 if (U_SUCCESS(status)) {
693 // Set the collator locales while registering so that createInstance()
694 // need not guess whether the collator's locales are already set properly
695 // (as they are by the data loader).
696 toAdopt->setLocales(locale, locale, locale);
697 return getService()->registerInstance(toAdopt, locale, status);
698 }
699 return NULL;
700 }
701
702 // -------------------------------------
703
704 class CFactory : public LocaleKeyFactory {
705 private:
706 CollatorFactory* _delegate;
707 Hashtable* _ids;
708
709 public:
710 CFactory(CollatorFactory* delegate, UErrorCode& status)
711 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
712 , _delegate(delegate)
713 , _ids(NULL)
714 {
715 if (U_SUCCESS(status)) {
716 int32_t count = 0;
717 _ids = new Hashtable(status);
718 if (_ids) {
719 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
720 for (int i = 0; i < count; ++i) {
721 _ids->put(idlist[i], (void*)this, status);
722 if (U_FAILURE(status)) {
723 delete _ids;
724 _ids = NULL;
725 return;
726 }
727 }
728 } else {
729 status = U_MEMORY_ALLOCATION_ERROR;
730 }
731 }
732 }
733
734 virtual ~CFactory();
735
736 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
737
738 protected:
739 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
740 {
741 if (U_SUCCESS(status)) {
742 return _ids;
743 }
744 return NULL;
745 }
746
747 virtual UnicodeString&
748 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
749 };
750
751 CFactory::~CFactory()
752 {
753 delete _delegate;
754 delete _ids;
755 }
756
757 UObject*
758 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
759 {
760 if (handlesKey(key, status)) {
761 const LocaleKey& lkey = (const LocaleKey&)key;
762 Locale validLoc;
763 lkey.currentLocale(validLoc);
764 return _delegate->createCollator(validLoc);
765 }
766 return NULL;
767 }
768
769 UnicodeString&
770 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
771 {
772 if ((_coverage & 0x1) == 0) {
773 UErrorCode status = U_ZERO_ERROR;
774 const Hashtable* ids = getSupportedIDs(status);
775 if (ids && (ids->get(id) != NULL)) {
776 Locale loc;
777 LocaleUtility::initLocaleFromName(id, loc);
778 return _delegate->getDisplayName(loc, locale, result);
779 }
780 }
781 result.setToBogus();
782 return result;
783 }
784
785 URegistryKey U_EXPORT2
786 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
787 {
788 if (U_SUCCESS(status)) {
789 CFactory* f = new CFactory(toAdopt, status);
790 if (f) {
791 return getService()->registerFactory(f, status);
792 }
793 status = U_MEMORY_ALLOCATION_ERROR;
794 }
795 return NULL;
796 }
797
798 // -------------------------------------
799
800 UBool U_EXPORT2
801 Collator::unregister(URegistryKey key, UErrorCode& status)
802 {
803 if (U_SUCCESS(status)) {
804 if (hasService()) {
805 return gService->unregister(key, status);
806 }
807 status = U_ILLEGAL_ARGUMENT_ERROR;
808 }
809 return FALSE;
810 }
811 #endif /* UCONFIG_NO_SERVICE */
812
813 class CollationLocaleListEnumeration : public StringEnumeration {
814 private:
815 int32_t index;
816 public:
817 static UClassID U_EXPORT2 getStaticClassID(void);
818 virtual UClassID getDynamicClassID(void) const;
819 public:
820 CollationLocaleListEnumeration()
821 : index(0)
822 {
823 // The global variables should already be initialized.
824 //isAvailableLocaleListInitialized(status);
825 }
826
827 virtual ~CollationLocaleListEnumeration();
828
829 virtual StringEnumeration * clone() const
830 {
831 CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
832 if (result) {
833 result->index = index;
834 }
835 return result;
836 }
837
838 virtual int32_t count(UErrorCode &/*status*/) const {
839 return availableLocaleListCount;
840 }
841
842 virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
843 const char* result;
844 if(index < availableLocaleListCount) {
845 result = availableLocaleList[index++].getName();
846 if(resultLength != NULL) {
847 *resultLength = (int32_t)uprv_strlen(result);
848 }
849 } else {
850 if(resultLength != NULL) {
851 *resultLength = 0;
852 }
853 result = NULL;
854 }
855 return result;
856 }
857
858 virtual const UnicodeString* snext(UErrorCode& status) {
859 int32_t resultLength = 0;
860 const char *s = next(&resultLength, status);
861 return setChars(s, resultLength, status);
862 }
863
864 virtual void reset(UErrorCode& /*status*/) {
865 index = 0;
866 }
867 };
868
869 CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {}
870
871 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
872
873
874 // -------------------------------------
875
876 StringEnumeration* U_EXPORT2
877 Collator::getAvailableLocales(void)
878 {
879 #if !UCONFIG_NO_SERVICE
880 if (hasService()) {
881 return getService()->getAvailableLocales();
882 }
883 #endif /* UCONFIG_NO_SERVICE */
884 UErrorCode status = U_ZERO_ERROR;
885 if (isAvailableLocaleListInitialized(status)) {
886 return new CollationLocaleListEnumeration();
887 }
888 return NULL;
889 }
890
891 StringEnumeration* U_EXPORT2
892 Collator::getKeywords(UErrorCode& status) {
893 return UStringEnumeration::fromUEnumeration(
894 ucol_getKeywords(&status), status);
895 }
896
897 StringEnumeration* U_EXPORT2
898 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
899 return UStringEnumeration::fromUEnumeration(
900 ucol_getKeywordValues(keyword, &status), status);
901 }
902
903 StringEnumeration* U_EXPORT2
904 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
905 UBool commonlyUsed, UErrorCode& status) {
906 return UStringEnumeration::fromUEnumeration(
907 ucol_getKeywordValuesForLocale(
908 key, locale.getName(), commonlyUsed, &status),
909 status);
910 }
911
912 Locale U_EXPORT2
913 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
914 UBool& isAvailable, UErrorCode& status) {
915 // This is a wrapper over ucol_getFunctionalEquivalent
916 char loc[ULOC_FULLNAME_CAPACITY];
917 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
918 keyword, locale.getName(), &isAvailable, &status);
919 if (U_FAILURE(status)) {
920 *loc = 0; // root
921 }
922 return Locale::createFromName(loc);
923 }
924
925 Collator::ECollationStrength
926 Collator::getStrength(void) const {
927 UErrorCode intStatus = U_ZERO_ERROR;
928 return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus);
929 }
930
931 void
932 Collator::setStrength(ECollationStrength newStrength) {
933 UErrorCode intStatus = U_ZERO_ERROR;
934 setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus);
935 }
936
937 Collator &
938 Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) {
939 if (U_SUCCESS(errorCode)) {
940 errorCode = U_UNSUPPORTED_ERROR;
941 }
942 return *this;
943 }
944
945 UColReorderCode
946 Collator::getMaxVariable() const {
947 return UCOL_REORDER_CODE_PUNCTUATION;
948 }
949
950 int32_t
951 Collator::getReorderCodes(int32_t* /* dest*/,
952 int32_t /* destCapacity*/,
953 UErrorCode& status) const
954 {
955 if (U_SUCCESS(status)) {
956 status = U_UNSUPPORTED_ERROR;
957 }
958 return 0;
959 }
960
961 void
962 Collator::setReorderCodes(const int32_t* /* reorderCodes */,
963 int32_t /* reorderCodesLength */,
964 UErrorCode& status)
965 {
966 if (U_SUCCESS(status)) {
967 status = U_UNSUPPORTED_ERROR;
968 }
969 }
970
971 int32_t
972 Collator::getEquivalentReorderCodes(int32_t reorderCode,
973 int32_t *dest, int32_t capacity,
974 UErrorCode &errorCode) {
975 if(U_FAILURE(errorCode)) { return 0; }
976 if(capacity < 0 || (dest == NULL && capacity > 0)) {
977 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
978 return 0;
979 }
980 const CollationData *baseData = CollationRoot::getData(errorCode);
981 if(U_FAILURE(errorCode)) { return 0; }
982 return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode);
983 }
984
985 int32_t
986 Collator::internalGetShortDefinitionString(const char * /*locale*/,
987 char * /*buffer*/,
988 int32_t /*capacity*/,
989 UErrorCode &status) const {
990 if(U_SUCCESS(status)) {
991 status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */
992 }
993 return 0;
994 }
995
996 UCollationResult
997 Collator::internalCompareUTF8(const char *left, int32_t leftLength,
998 const char *right, int32_t rightLength,
999 UErrorCode &errorCode) const {
1000 if(U_FAILURE(errorCode)) { return UCOL_EQUAL; }
1001 if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) {
1002 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
1003 return UCOL_EQUAL;
1004 }
1005 return compareUTF8(
1006 StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength),
1007 StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength),
1008 errorCode);
1009 }
1010
1011 int32_t
1012 Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2],
1013 uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const {
1014 if (U_SUCCESS(errorCode)) {
1015 errorCode = U_UNSUPPORTED_ERROR;
1016 }
1017 return 0;
1018 }
1019
1020 // UCollator private data members ----------------------------------------
1021
1022 /* This is useless information */
1023 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
1024
1025 // -------------------------------------
1026
1027 U_NAMESPACE_END
1028
1029 #endif /* #if !UCONFIG_NO_COLLATION */
1030
1031 /* eof */