]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/coll.cpp
ICU-66108.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 = U_INITONCE_INITIALIZER;
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 StackUResourceBundle installed;
233 int32_t i = 0;
234
235 index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
236 ures_getByKey(index, "InstalledLocales", installed.getAlias(), &status);
237
238 if(U_SUCCESS(status)) {
239 availableLocaleListCount = ures_getSize(installed.getAlias());
240 availableLocaleList = new Locale[availableLocaleListCount];
241
242 if (availableLocaleList != NULL) {
243 ures_resetIterator(installed.getAlias());
244 while(ures_hasNext(installed.getAlias())) {
245 const char *tempKey = NULL;
246 ures_getNextString(installed.getAlias(), NULL, &tempKey, &status);
247 availableLocaleList[i++] = Locale(tempKey);
248 }
249 }
250 U_ASSERT(availableLocaleListCount == i);
251 }
252 ures_close(index);
253 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
254 }
255
256 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
257 umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status);
258 return U_SUCCESS(status);
259 }
260
261
262 // Collator public methods -----------------------------------------------
263
264 namespace {
265
266 static const struct {
267 const char *name;
268 UColAttribute attr;
269 } collAttributes[] = {
270 { "colStrength", UCOL_STRENGTH },
271 { "colBackwards", UCOL_FRENCH_COLLATION },
272 { "colCaseLevel", UCOL_CASE_LEVEL },
273 { "colCaseFirst", UCOL_CASE_FIRST },
274 { "colAlternate", UCOL_ALTERNATE_HANDLING },
275 { "colNormalization", UCOL_NORMALIZATION_MODE },
276 { "colNumeric", UCOL_NUMERIC_COLLATION }
277 };
278
279 static const struct {
280 const char *name;
281 UColAttributeValue value;
282 } collAttributeValues[] = {
283 { "primary", UCOL_PRIMARY },
284 { "secondary", UCOL_SECONDARY },
285 { "tertiary", UCOL_TERTIARY },
286 { "quaternary", UCOL_QUATERNARY },
287 // Note: Not supporting typo "quarternary" because it was never supported in locale IDs.
288 { "identical", UCOL_IDENTICAL },
289 { "no", UCOL_OFF },
290 { "yes", UCOL_ON },
291 { "shifted", UCOL_SHIFTED },
292 { "non-ignorable", UCOL_NON_IGNORABLE },
293 { "lower", UCOL_LOWER_FIRST },
294 { "upper", UCOL_UPPER_FIRST }
295 };
296
297 static const char *collReorderCodes[UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST] = {
298 "space", "punct", "symbol", "currency", "digit"
299 };
300
301 int32_t getReorderCode(const char *s) {
302 for (int32_t i = 0; i < UPRV_LENGTHOF(collReorderCodes); ++i) {
303 if (uprv_stricmp(s, collReorderCodes[i]) == 0) {
304 return UCOL_REORDER_CODE_FIRST + i;
305 }
306 }
307 // Not supporting "others" = UCOL_REORDER_CODE_OTHERS
308 // as a synonym for Zzzz = USCRIPT_UNKNOWN for now:
309 // Avoid introducing synonyms/aliases.
310 return -1;
311 }
312
313 /**
314 * Sets collation attributes according to locale keywords. See
315 * http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings
316 *
317 * Using "alias" keywords and values where defined:
318 * http://www.unicode.org/reports/tr35/tr35.html#Old_Locale_Extension_Syntax
319 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
320 */
321 void setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) {
322 if (U_FAILURE(errorCode)) {
323 return;
324 }
325 if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) {
326 // No keywords.
327 return;
328 }
329 char value[1024]; // The reordering value could be long.
330 // Check for collation keywords that were already deprecated
331 // before any were supported in createInstance() (except for "collation").
332 int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, UPRV_LENGTHOF(value), errorCode);
333 if (U_FAILURE(errorCode)) {
334 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
335 return;
336 }
337 if (length != 0) {
338 errorCode = U_UNSUPPORTED_ERROR;
339 return;
340 }
341 length = loc.getKeywordValue("variableTop", value, UPRV_LENGTHOF(value), errorCode);
342 if (U_FAILURE(errorCode)) {
343 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
344 return;
345 }
346 if (length != 0) {
347 errorCode = U_UNSUPPORTED_ERROR;
348 return;
349 }
350 // Parse known collation keywords, ignore others.
351 if (errorCode == U_STRING_NOT_TERMINATED_WARNING) {
352 errorCode = U_ZERO_ERROR;
353 }
354 for (int32_t i = 0; i < UPRV_LENGTHOF(collAttributes); ++i) {
355 length = loc.getKeywordValue(collAttributes[i].name, value, UPRV_LENGTHOF(value), errorCode);
356 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
357 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
358 return;
359 }
360 if (length == 0) { continue; }
361 for (int32_t j = 0;; ++j) {
362 if (j == UPRV_LENGTHOF(collAttributeValues)) {
363 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
364 return;
365 }
366 if (uprv_stricmp(value, collAttributeValues[j].name) == 0) {
367 coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode);
368 break;
369 }
370 }
371 }
372 length = loc.getKeywordValue("colReorder", value, UPRV_LENGTHOF(value), errorCode);
373 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
374 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
375 return;
376 }
377 if (length != 0) {
378 int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST];
379 int32_t codesLength = 0;
380 char *scriptName = value;
381 for (;;) {
382 if (codesLength == UPRV_LENGTHOF(codes)) {
383 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
384 return;
385 }
386 char *limit = scriptName;
387 char c;
388 while ((c = *limit) != 0 && c != '-') { ++limit; }
389 *limit = 0;
390 int32_t code;
391 if ((limit - scriptName) == 4) {
392 // Strict parsing, accept only 4-letter script codes, not long names.
393 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName);
394 } else {
395 code = getReorderCode(scriptName);
396 }
397 if (code < 0) {
398 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
399 return;
400 }
401 codes[codesLength++] = code;
402 if (c == 0) { break; }
403 scriptName = limit + 1;
404 }
405 coll.setReorderCodes(codes, codesLength, errorCode);
406 }
407 length = loc.getKeywordValue("kv", value, UPRV_LENGTHOF(value), errorCode);
408 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
409 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
410 return;
411 }
412 if (length != 0) {
413 int32_t code = getReorderCode(value);
414 if (code < 0) {
415 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
416 return;
417 }
418 coll.setMaxVariable((UColReorderCode)code, errorCode);
419 }
420 if (U_FAILURE(errorCode)) {
421 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
422 }
423 }
424
425 } // namespace
426
427 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
428 {
429 return createInstance(Locale::getDefault(), success);
430 }
431
432 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
433 UErrorCode& status)
434 {
435 if (U_FAILURE(status))
436 return 0;
437 if (desiredLocale.isBogus()) {
438 // Locale constructed from malformed locale ID or language tag.
439 status = U_ILLEGAL_ARGUMENT_ERROR;
440 return NULL;
441 }
442
443 Collator* coll;
444 #if !UCONFIG_NO_SERVICE
445 if (hasService()) {
446 Locale actualLoc;
447 coll = (Collator*)gService->get(desiredLocale, &actualLoc, status);
448 } else
449 #endif
450 {
451 coll = makeInstance(desiredLocale, status);
452 // Either returns NULL with U_FAILURE(status), or non-NULL with U_SUCCESS(status)
453 }
454 // The use of *coll in setAttributesFromKeywords can cause the NULL check to be
455 // optimized out of the delete even though setAttributesFromKeywords returns
456 // immediately if U_FAILURE(status), so we add a check here.
457 if (U_FAILURE(status)) {
458 return NULL;
459 }
460 // makeInstance either returns NULL with U_FAILURE(status), or non-NULL with U_SUCCESS(status).
461 // The *coll in setAttributesFromKeywords causes the NULL check to be optimized out of the delete
462 // even though setAttributesFromKeywords returns immediately if U_FAILURE(status), so we add a
463 // check here and also log the locale name for failures. <rdar://problem/40930320>
464 if (U_FAILURE(status)) {
465 #if U_PLATFORM_IS_DARWIN_BASED
466 #if 0
467 // logging disabled for shipping system, can enable for internal debugging
468 const char* locname = desiredLocale.getName();
469 os_log(OS_LOG_DEFAULT, "Collator::createInstance fails with locale: %{public}s", locname? locname: "(NULL)");
470 #endif
471 #endif
472 return NULL;
473 }
474 setAttributesFromKeywords(desiredLocale, *coll, status);
475 if (U_FAILURE(status)) {
476 delete coll;
477 return NULL;
478 }
479 return coll;
480 }
481
482
483 Collator* Collator::makeInstance(const Locale& desiredLocale, UErrorCode& status) {
484 const CollationCacheEntry *entry = CollationLoader::loadTailoring(desiredLocale, status);
485 if (U_SUCCESS(status)) {
486 Collator *result = new RuleBasedCollator(entry);
487 if (result != NULL) {
488 // Both the unified cache's get() and the RBC constructor
489 // did addRef(). Undo one of them.
490 entry->removeRef();
491 return result;
492 }
493 status = U_MEMORY_ALLOCATION_ERROR;
494 }
495 if (entry != NULL) {
496 // Undo the addRef() from the cache.get().
497 entry->removeRef();
498 }
499 return NULL;
500 }
501
502 Collator *
503 Collator::safeClone() const {
504 return clone();
505 }
506
507 // implement deprecated, previously abstract method
508 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
509 const UnicodeString& target) const
510 {
511 UErrorCode ec = U_ZERO_ERROR;
512 return (EComparisonResult)compare(source, target, ec);
513 }
514
515 // implement deprecated, previously abstract method
516 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
517 const UnicodeString& target,
518 int32_t length) const
519 {
520 UErrorCode ec = U_ZERO_ERROR;
521 return (EComparisonResult)compare(source, target, length, ec);
522 }
523
524 // implement deprecated, previously abstract method
525 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
526 const UChar* target, int32_t targetLength)
527 const
528 {
529 UErrorCode ec = U_ZERO_ERROR;
530 return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
531 }
532
533 UCollationResult Collator::compare(UCharIterator &/*sIter*/,
534 UCharIterator &/*tIter*/,
535 UErrorCode &status) const {
536 if(U_SUCCESS(status)) {
537 // Not implemented in the base class.
538 status = U_UNSUPPORTED_ERROR;
539 }
540 return UCOL_EQUAL;
541 }
542
543 UCollationResult Collator::compareUTF8(const StringPiece &source,
544 const StringPiece &target,
545 UErrorCode &status) const {
546 if(U_FAILURE(status)) {
547 return UCOL_EQUAL;
548 }
549 UCharIterator sIter, tIter;
550 uiter_setUTF8(&sIter, source.data(), source.length());
551 uiter_setUTF8(&tIter, target.data(), target.length());
552 return compare(sIter, tIter, status);
553 }
554
555 UBool Collator::equals(const UnicodeString& source,
556 const UnicodeString& target) const
557 {
558 UErrorCode ec = U_ZERO_ERROR;
559 return (compare(source, target, ec) == UCOL_EQUAL);
560 }
561
562 UBool Collator::greaterOrEqual(const UnicodeString& source,
563 const UnicodeString& target) const
564 {
565 UErrorCode ec = U_ZERO_ERROR;
566 return (compare(source, target, ec) != UCOL_LESS);
567 }
568
569 UBool Collator::greater(const UnicodeString& source,
570 const UnicodeString& target) const
571 {
572 UErrorCode ec = U_ZERO_ERROR;
573 return (compare(source, target, ec) == UCOL_GREATER);
574 }
575
576 // this API ignores registered collators, since it returns an
577 // array of indefinite lifetime
578 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
579 {
580 UErrorCode status = U_ZERO_ERROR;
581 Locale *result = NULL;
582 count = 0;
583 if (isAvailableLocaleListInitialized(status))
584 {
585 result = availableLocaleList;
586 count = availableLocaleListCount;
587 }
588 return result;
589 }
590
591 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
592 const Locale& displayLocale,
593 UnicodeString& name)
594 {
595 #if !UCONFIG_NO_SERVICE
596 if (hasService()) {
597 UnicodeString locNameStr;
598 LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
599 return gService->getDisplayName(locNameStr, name, displayLocale);
600 }
601 #endif
602 return objectLocale.getDisplayName(displayLocale, name);
603 }
604
605 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
606 UnicodeString& name)
607 {
608 return getDisplayName(objectLocale, Locale::getDefault(), name);
609 }
610
611 /* This is useless information */
612 /*void Collator::getVersion(UVersionInfo versionInfo) const
613 {
614 if (versionInfo!=NULL)
615 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
616 }
617 */
618
619 // UCollator protected constructor destructor ----------------------------
620
621 /**
622 * Default constructor.
623 * Constructor is different from the old default Collator constructor.
624 * The task for determing the default collation strength and normalization mode
625 * is left to the child class.
626 */
627 Collator::Collator()
628 : UObject()
629 {
630 }
631
632 /**
633 * Constructor.
634 * Empty constructor, does not handle the arguments.
635 * This constructor is done for backward compatibility with 1.7 and 1.8.
636 * The task for handling the argument collation strength and normalization
637 * mode is left to the child class.
638 * @param collationStrength collation strength
639 * @param decompositionMode
640 * @deprecated 2.4 use the default constructor instead
641 */
642 Collator::Collator(UCollationStrength, UNormalizationMode )
643 : UObject()
644 {
645 }
646
647 Collator::~Collator()
648 {
649 }
650
651 Collator::Collator(const Collator &other)
652 : UObject(other)
653 {
654 }
655
656 UBool Collator::operator==(const Collator& other) const
657 {
658 // Subclasses: Call this method and then add more specific checks.
659 return typeid(*this) == typeid(other);
660 }
661
662 UBool Collator::operator!=(const Collator& other) const
663 {
664 return (UBool)!(*this == other);
665 }
666
667 int32_t U_EXPORT2 Collator::getBound(const uint8_t *source,
668 int32_t sourceLength,
669 UColBoundMode boundType,
670 uint32_t noOfLevels,
671 uint8_t *result,
672 int32_t resultLength,
673 UErrorCode &status)
674 {
675 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
676 }
677
678 void
679 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
680 }
681
682 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
683 {
684 if(U_FAILURE(status)) {
685 return NULL;
686 }
687 // everything can be changed
688 return new UnicodeSet(0, 0x10FFFF);
689 }
690
691 // -------------------------------------
692
693 #if !UCONFIG_NO_SERVICE
694 URegistryKey U_EXPORT2
695 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
696 {
697 if (U_SUCCESS(status)) {
698 // Set the collator locales while registering so that createInstance()
699 // need not guess whether the collator's locales are already set properly
700 // (as they are by the data loader).
701 toAdopt->setLocales(locale, locale, locale);
702 return getService()->registerInstance(toAdopt, locale, status);
703 }
704 return NULL;
705 }
706
707 // -------------------------------------
708
709 class CFactory : public LocaleKeyFactory {
710 private:
711 CollatorFactory* _delegate;
712 Hashtable* _ids;
713
714 public:
715 CFactory(CollatorFactory* delegate, UErrorCode& status)
716 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
717 , _delegate(delegate)
718 , _ids(NULL)
719 {
720 if (U_SUCCESS(status)) {
721 int32_t count = 0;
722 _ids = new Hashtable(status);
723 if (_ids) {
724 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
725 for (int i = 0; i < count; ++i) {
726 _ids->put(idlist[i], (void*)this, status);
727 if (U_FAILURE(status)) {
728 delete _ids;
729 _ids = NULL;
730 return;
731 }
732 }
733 } else {
734 status = U_MEMORY_ALLOCATION_ERROR;
735 }
736 }
737 }
738
739 virtual ~CFactory();
740
741 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
742
743 protected:
744 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
745 {
746 if (U_SUCCESS(status)) {
747 return _ids;
748 }
749 return NULL;
750 }
751
752 virtual UnicodeString&
753 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
754 };
755
756 CFactory::~CFactory()
757 {
758 delete _delegate;
759 delete _ids;
760 }
761
762 UObject*
763 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
764 {
765 if (handlesKey(key, status)) {
766 const LocaleKey& lkey = (const LocaleKey&)key;
767 Locale validLoc;
768 lkey.currentLocale(validLoc);
769 return _delegate->createCollator(validLoc);
770 }
771 return NULL;
772 }
773
774 UnicodeString&
775 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
776 {
777 if ((_coverage & 0x1) == 0) {
778 UErrorCode status = U_ZERO_ERROR;
779 const Hashtable* ids = getSupportedIDs(status);
780 if (ids && (ids->get(id) != NULL)) {
781 Locale loc;
782 LocaleUtility::initLocaleFromName(id, loc);
783 return _delegate->getDisplayName(loc, locale, result);
784 }
785 }
786 result.setToBogus();
787 return result;
788 }
789
790 URegistryKey U_EXPORT2
791 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
792 {
793 if (U_SUCCESS(status)) {
794 CFactory* f = new CFactory(toAdopt, status);
795 if (f) {
796 return getService()->registerFactory(f, status);
797 }
798 status = U_MEMORY_ALLOCATION_ERROR;
799 }
800 return NULL;
801 }
802
803 // -------------------------------------
804
805 UBool U_EXPORT2
806 Collator::unregister(URegistryKey key, UErrorCode& status)
807 {
808 if (U_SUCCESS(status)) {
809 if (hasService()) {
810 return gService->unregister(key, status);
811 }
812 status = U_ILLEGAL_ARGUMENT_ERROR;
813 }
814 return FALSE;
815 }
816 #endif /* UCONFIG_NO_SERVICE */
817
818 class CollationLocaleListEnumeration : public StringEnumeration {
819 private:
820 int32_t index;
821 public:
822 static UClassID U_EXPORT2 getStaticClassID(void);
823 virtual UClassID getDynamicClassID(void) const;
824 public:
825 CollationLocaleListEnumeration()
826 : index(0)
827 {
828 // The global variables should already be initialized.
829 //isAvailableLocaleListInitialized(status);
830 }
831
832 virtual ~CollationLocaleListEnumeration();
833
834 virtual StringEnumeration * clone() const
835 {
836 CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
837 if (result) {
838 result->index = index;
839 }
840 return result;
841 }
842
843 virtual int32_t count(UErrorCode &/*status*/) const {
844 return availableLocaleListCount;
845 }
846
847 virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
848 const char* result;
849 if(index < availableLocaleListCount) {
850 result = availableLocaleList[index++].getName();
851 if(resultLength != NULL) {
852 *resultLength = (int32_t)uprv_strlen(result);
853 }
854 } else {
855 if(resultLength != NULL) {
856 *resultLength = 0;
857 }
858 result = NULL;
859 }
860 return result;
861 }
862
863 virtual const UnicodeString* snext(UErrorCode& status) {
864 int32_t resultLength = 0;
865 const char *s = next(&resultLength, status);
866 return setChars(s, resultLength, status);
867 }
868
869 virtual void reset(UErrorCode& /*status*/) {
870 index = 0;
871 }
872 };
873
874 CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {}
875
876 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
877
878
879 // -------------------------------------
880
881 StringEnumeration* U_EXPORT2
882 Collator::getAvailableLocales(void)
883 {
884 #if !UCONFIG_NO_SERVICE
885 if (hasService()) {
886 return getService()->getAvailableLocales();
887 }
888 #endif /* UCONFIG_NO_SERVICE */
889 UErrorCode status = U_ZERO_ERROR;
890 if (isAvailableLocaleListInitialized(status)) {
891 return new CollationLocaleListEnumeration();
892 }
893 return NULL;
894 }
895
896 StringEnumeration* U_EXPORT2
897 Collator::getKeywords(UErrorCode& status) {
898 return UStringEnumeration::fromUEnumeration(
899 ucol_getKeywords(&status), status);
900 }
901
902 StringEnumeration* U_EXPORT2
903 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
904 return UStringEnumeration::fromUEnumeration(
905 ucol_getKeywordValues(keyword, &status), status);
906 }
907
908 StringEnumeration* U_EXPORT2
909 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
910 UBool commonlyUsed, UErrorCode& status) {
911 return UStringEnumeration::fromUEnumeration(
912 ucol_getKeywordValuesForLocale(
913 key, locale.getName(), commonlyUsed, &status),
914 status);
915 }
916
917 Locale U_EXPORT2
918 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
919 UBool& isAvailable, UErrorCode& status) {
920 // This is a wrapper over ucol_getFunctionalEquivalent
921 char loc[ULOC_FULLNAME_CAPACITY];
922 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
923 keyword, locale.getName(), &isAvailable, &status);
924 if (U_FAILURE(status)) {
925 *loc = 0; // root
926 }
927 return Locale::createFromName(loc);
928 }
929
930 Collator::ECollationStrength
931 Collator::getStrength(void) const {
932 UErrorCode intStatus = U_ZERO_ERROR;
933 return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus);
934 }
935
936 void
937 Collator::setStrength(ECollationStrength newStrength) {
938 UErrorCode intStatus = U_ZERO_ERROR;
939 setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus);
940 }
941
942 Collator &
943 Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) {
944 if (U_SUCCESS(errorCode)) {
945 errorCode = U_UNSUPPORTED_ERROR;
946 }
947 return *this;
948 }
949
950 UColReorderCode
951 Collator::getMaxVariable() const {
952 return UCOL_REORDER_CODE_PUNCTUATION;
953 }
954
955 int32_t
956 Collator::getReorderCodes(int32_t* /* dest*/,
957 int32_t /* destCapacity*/,
958 UErrorCode& status) const
959 {
960 if (U_SUCCESS(status)) {
961 status = U_UNSUPPORTED_ERROR;
962 }
963 return 0;
964 }
965
966 void
967 Collator::setReorderCodes(const int32_t* /* reorderCodes */,
968 int32_t /* reorderCodesLength */,
969 UErrorCode& status)
970 {
971 if (U_SUCCESS(status)) {
972 status = U_UNSUPPORTED_ERROR;
973 }
974 }
975
976 int32_t
977 Collator::getEquivalentReorderCodes(int32_t reorderCode,
978 int32_t *dest, int32_t capacity,
979 UErrorCode &errorCode) {
980 if(U_FAILURE(errorCode)) { return 0; }
981 if(capacity < 0 || (dest == NULL && capacity > 0)) {
982 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
983 return 0;
984 }
985 const CollationData *baseData = CollationRoot::getData(errorCode);
986 if(U_FAILURE(errorCode)) { return 0; }
987 return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode);
988 }
989
990 int32_t
991 Collator::internalGetShortDefinitionString(const char * /*locale*/,
992 char * /*buffer*/,
993 int32_t /*capacity*/,
994 UErrorCode &status) const {
995 if(U_SUCCESS(status)) {
996 status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */
997 }
998 return 0;
999 }
1000
1001 UCollationResult
1002 Collator::internalCompareUTF8(const char *left, int32_t leftLength,
1003 const char *right, int32_t rightLength,
1004 UErrorCode &errorCode) const {
1005 if(U_FAILURE(errorCode)) { return UCOL_EQUAL; }
1006 if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) {
1007 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
1008 return UCOL_EQUAL;
1009 }
1010 return compareUTF8(
1011 StringPiece(left, (leftLength < 0) ? static_cast<int32_t>(uprv_strlen(left)) : leftLength),
1012 StringPiece(right, (rightLength < 0) ? static_cast<int32_t>(uprv_strlen(right)) : rightLength),
1013 errorCode);
1014 }
1015
1016 int32_t
1017 Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2],
1018 uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const {
1019 if (U_SUCCESS(errorCode)) {
1020 errorCode = U_UNSUPPORTED_ERROR;
1021 }
1022 return 0;
1023 }
1024
1025 // UCollator private data members ----------------------------------------
1026
1027 /* This is useless information */
1028 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
1029
1030 // -------------------------------------
1031
1032 U_NAMESPACE_END
1033
1034 #endif /* #if !UCONFIG_NO_COLLATION */
1035
1036 /* eof */