]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/coll.cpp
ICU-64260.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / coll.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f 3/*
46f4442e 4 ******************************************************************************
57a6839d 5 * Copyright (C) 1996-2014, International Business Machines Corporation and
729e4ab9 6 * others. All Rights Reserved.
46f4442e
A
7 ******************************************************************************
8 */
b75a7d8f
A
9
10/**
46f4442e
A
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)
57a6839d 40 * 2012-2014 markus Rewritten in C++ again.
46f4442e 41 */
b75a7d8f 42
57a6839d 43#include "utypeinfo.h" // for 'typeid' to work
51004dcb 44
b75a7d8f
A
45#include "unicode/utypes.h"
46
47#if !UCONFIG_NO_COLLATION
48
49#include "unicode/coll.h"
50#include "unicode/tblcoll.h"
57a6839d
A
51#include "collationdata.h"
52#include "collationroot.h"
53#include "collationtailoring.h"
374ca955 54#include "ucol_imp.h"
46f4442e 55#include "cstring.h"
b75a7d8f 56#include "cmemory.h"
46f4442e 57#include "umutex.h"
73c04bcf 58#include "servloc.h"
57a6839d 59#include "uassert.h"
374ca955 60#include "ustrenum.h"
46f4442e 61#include "uresimp.h"
b75a7d8f 62#include "ucln_in.h"
0f5d89e8
A
63#if U_PLATFORM_IS_DARWIN_BASED
64#include <os/log.h>
65#endif
b75a7d8f 66
4388f060 67static icu::Locale* availableLocaleList = NULL;
46f4442e 68static int32_t availableLocaleListCount;
3bb97ae2 69#if !UCONFIG_NO_SERVICE
4388f060 70static icu::ICULocaleService* gService = NULL;
57a6839d 71static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
3bb97ae2 72#endif
3d1f044b 73static icu::UInitOnce gAvailableLocaleListInitOnce = U_INITONCE_INITIALIZER;
374ca955 74
374ca955
A
75/**
76 * Release all static memory held by collator.
77 */
78U_CDECL_BEGIN
79static UBool U_CALLCONV collator_cleanup(void) {
46f4442e 80#if !UCONFIG_NO_SERVICE
374ca955
A
81 if (gService) {
82 delete gService;
83 gService = NULL;
84 }
57a6839d 85 gServiceInitOnce.reset();
46f4442e
A
86#endif
87 if (availableLocaleList) {
88 delete []availableLocaleList;
89 availableLocaleList = NULL;
90 }
91 availableLocaleListCount = 0;
57a6839d 92 gAvailableLocaleListInitOnce.reset();
374ca955
A
93 return TRUE;
94}
46f4442e 95
374ca955
A
96U_CDECL_END
97
b75a7d8f
A
98U_NAMESPACE_BEGIN
99
46f4442e
A
100#if !UCONFIG_NO_SERVICE
101
b75a7d8f
A
102// ------------------------------------------
103//
104// Registration
105//
106
107//-------------------------------------------
108
374ca955
A
109CollatorFactory::~CollatorFactory() {}
110
111//-------------------------------------------
112
b75a7d8f
A
113UBool
114CollatorFactory::visible(void) const {
374ca955 115 return TRUE;
b75a7d8f
A
116}
117
118//-------------------------------------------
119
120UnicodeString&
121CollatorFactory::getDisplayName(const Locale& objectLocale,
122 const Locale& displayLocale,
123 UnicodeString& result)
124{
125 return objectLocale.getDisplayName(displayLocale, result);
126}
127
128// -------------------------------------
129
130class ICUCollatorFactory : public ICUResourceBundleFactory {
374ca955 131 public:
4388f060
A
132 ICUCollatorFactory() : ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
133 virtual ~ICUCollatorFactory();
374ca955
A
134 protected:
135 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
b75a7d8f
A
136};
137
4388f060
A
138ICUCollatorFactory::~ICUCollatorFactory() {}
139
b75a7d8f
A
140UObject*
141ICUCollatorFactory::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);
374ca955 149
b75a7d8f
A
150 return Collator::makeInstance(loc, status);
151 }
152 return NULL;
153}
154
155// -------------------------------------
156
157class ICUCollatorService : public ICULocaleService {
374ca955 158public:
b75a7d8f 159 ICUCollatorService()
73c04bcf 160 : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
b75a7d8f
A
161 {
162 UErrorCode status = U_ZERO_ERROR;
163 registerFactory(new ICUCollatorFactory(), status);
164 }
4388f060
A
165
166 virtual ~ICUCollatorService();
167
b75a7d8f
A
168 virtual UObject* cloneInstance(UObject* instance) const {
169 return ((Collator*)instance)->clone();
170 }
374ca955 171
b75a7d8f
A
172 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
173 LocaleKey& lkey = (LocaleKey&)key;
374ca955
A
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("");
b75a7d8f
A
181 lkey.canonicalLocale(loc);
182 return Collator::makeInstance(loc, status);
183 }
374ca955
A
184
185 virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
186 UnicodeString ar;
187 if (actualReturn == NULL) {
188 actualReturn = &ar;
189 }
57a6839d 190 return (Collator*)ICULocaleService::getKey(key, actualReturn, status);
374ca955 191 }
b75a7d8f
A
192
193 virtual UBool isDefault() const {
194 return countFactories() == 1;
195 }
196};
197
4388f060
A
198ICUCollatorService::~ICUCollatorService() {}
199
b75a7d8f
A
200// -------------------------------------
201
57a6839d
A
202static void U_CALLCONV initService() {
203 gService = new ICUCollatorService();
204 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
205}
206
207
b75a7d8f
A
208static ICULocaleService*
209getService(void)
210{
57a6839d 211 umtx_initOnce(gServiceInitOnce, &initService);
374ca955 212 return gService;
b75a7d8f
A
213}
214
215// -------------------------------------
216
46f4442e 217static inline UBool
b75a7d8f
A
218hasService(void)
219{
57a6839d 220 UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL);
46f4442e 221 return retVal;
b75a7d8f
A
222}
223
374ca955 224#endif /* UCONFIG_NO_SERVICE */
b75a7d8f 225
57a6839d
A
226static void U_CALLCONV
227initAvailableLocaleList(UErrorCode &status) {
228 U_ASSERT(availableLocaleListCount == 0);
229 U_ASSERT(availableLocaleList == NULL);
46f4442e 230 // for now, there is a hardcoded list, so just walk through that list and set it up.
57a6839d 231 UResourceBundle *index = NULL;
3d1f044b 232 StackUResourceBundle installed;
57a6839d
A
233 int32_t i = 0;
234
57a6839d 235 index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
3d1f044b
A
236 ures_getByKey(index, "InstalledLocales", installed.getAlias(), &status);
237
57a6839d 238 if(U_SUCCESS(status)) {
3d1f044b 239 availableLocaleListCount = ures_getSize(installed.getAlias());
57a6839d 240 availableLocaleList = new Locale[availableLocaleListCount];
46f4442e 241
57a6839d 242 if (availableLocaleList != NULL) {
3d1f044b
A
243 ures_resetIterator(installed.getAlias());
244 while(ures_hasNext(installed.getAlias())) {
57a6839d 245 const char *tempKey = NULL;
3d1f044b 246 ures_getNextString(installed.getAlias(), NULL, &tempKey, &status);
57a6839d 247 availableLocaleList[i++] = Locale(tempKey);
46f4442e 248 }
46f4442e 249 }
57a6839d 250 U_ASSERT(availableLocaleListCount == i);
46f4442e 251 }
57a6839d
A
252 ures_close(index);
253 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
46f4442e
A
254}
255
57a6839d
A
256static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
257 umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status);
258 return U_SUCCESS(status);
259}
260
261
b75a7d8f
A
262// Collator public methods -----------------------------------------------
263
b331163b
A
264namespace {
265
266static 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
279static 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
297static const char *collReorderCodes[UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST] = {
298 "space", "punct", "symbol", "currency", "digit"
299};
300
301int32_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 */
321void 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
374ca955 427Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
b75a7d8f 428{
374ca955 429 return createInstance(Locale::getDefault(), success);
b75a7d8f
A
430}
431
374ca955 432Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
b75a7d8f
A
433 UErrorCode& status)
434{
374ca955
A
435 if (U_FAILURE(status))
436 return 0;
b331163b
A
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;
374ca955
A
444#if !UCONFIG_NO_SERVICE
445 if (hasService()) {
446 Locale actualLoc;
b331163b
A
447 coll = (Collator*)gService->get(desiredLocale, &actualLoc, status);
448 } else
374ca955 449#endif
b331163b
A
450 {
451 coll = makeInstance(desiredLocale, status);
3d1f044b
A
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;
b331163b 459 }
0f5d89e8
A
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 }
b331163b
A
474 setAttributesFromKeywords(desiredLocale, *coll, status);
475 if (U_FAILURE(status)) {
476 delete coll;
477 return NULL;
478 }
479 return coll;
b75a7d8f
A
480}
481
482
b331163b
A
483Collator* Collator::makeInstance(const Locale& desiredLocale, UErrorCode& status) {
484 const CollationCacheEntry *entry = CollationLoader::loadTailoring(desiredLocale, status);
57a6839d 485 if (U_SUCCESS(status)) {
b331163b 486 Collator *result = new RuleBasedCollator(entry);
57a6839d 487 if (result != NULL) {
b331163b
A
488 // Both the unified cache's get() and the RBC constructor
489 // did addRef(). Undo one of them.
490 entry->removeRef();
57a6839d
A
491 return result;
492 }
374ca955 493 status = U_MEMORY_ALLOCATION_ERROR;
b75a7d8f 494 }
b331163b
A
495 if (entry != NULL) {
496 // Undo the addRef() from the cache.get().
497 entry->removeRef();
374ca955 498 }
57a6839d 499 return NULL;
b75a7d8f
A
500}
501
51004dcb
A
502Collator *
503Collator::safeClone() const {
504 return clone();
505}
506
b75a7d8f
A
507// implement deprecated, previously abstract method
508Collator::EComparisonResult Collator::compare(const UnicodeString& source,
509 const UnicodeString& target) const
510{
374ca955 511 UErrorCode ec = U_ZERO_ERROR;
51004dcb 512 return (EComparisonResult)compare(source, target, ec);
b75a7d8f
A
513}
514
515// implement deprecated, previously abstract method
516Collator::EComparisonResult Collator::compare(const UnicodeString& source,
517 const UnicodeString& target,
518 int32_t length) const
519{
374ca955 520 UErrorCode ec = U_ZERO_ERROR;
51004dcb 521 return (EComparisonResult)compare(source, target, length, ec);
b75a7d8f
A
522}
523
524// implement deprecated, previously abstract method
525Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
526 const UChar* target, int32_t targetLength)
527 const
528{
374ca955 529 UErrorCode ec = U_ZERO_ERROR;
51004dcb 530 return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
b75a7d8f
A
531}
532
729e4ab9
A
533UCollationResult 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
543UCollationResult 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
b75a7d8f 555UBool Collator::equals(const UnicodeString& source,
374ca955 556 const UnicodeString& target) const
b75a7d8f 557{
374ca955
A
558 UErrorCode ec = U_ZERO_ERROR;
559 return (compare(source, target, ec) == UCOL_EQUAL);
b75a7d8f
A
560}
561
562UBool Collator::greaterOrEqual(const UnicodeString& source,
374ca955 563 const UnicodeString& target) const
b75a7d8f 564{
374ca955
A
565 UErrorCode ec = U_ZERO_ERROR;
566 return (compare(source, target, ec) != UCOL_LESS);
b75a7d8f
A
567}
568
569UBool Collator::greater(const UnicodeString& source,
374ca955 570 const UnicodeString& target) const
b75a7d8f 571{
374ca955
A
572 UErrorCode ec = U_ZERO_ERROR;
573 return (compare(source, target, ec) == UCOL_GREATER);
b75a7d8f
A
574}
575
576// this API ignores registered collators, since it returns an
577// array of indefinite lifetime
374ca955 578const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
b75a7d8f 579{
46f4442e
A
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;
b75a7d8f
A
589}
590
374ca955
A
591UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
592 const Locale& displayLocale,
593 UnicodeString& name)
b75a7d8f 594{
374ca955
A
595#if !UCONFIG_NO_SERVICE
596 if (hasService()) {
73c04bcf
A
597 UnicodeString locNameStr;
598 LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
599 return gService->getDisplayName(locNameStr, name, displayLocale);
374ca955
A
600 }
601#endif
602 return objectLocale.getDisplayName(displayLocale, name);
b75a7d8f
A
603}
604
374ca955
A
605UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
606 UnicodeString& name)
b75a7d8f 607{
374ca955 608 return getDisplayName(objectLocale, Locale::getDefault(), name);
b75a7d8f
A
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*/
627Collator::Collator()
374ca955 628: UObject()
b75a7d8f
A
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*/
642Collator::Collator(UCollationStrength, UNormalizationMode )
374ca955 643: UObject()
b75a7d8f
A
644{
645}
646
647Collator::~Collator()
648{
649}
650
651Collator::Collator(const Collator &other)
652 : UObject(other)
653{
654}
655
374ca955
A
656UBool Collator::operator==(const Collator& other) const
657{
51004dcb
A
658 // Subclasses: Call this method and then add more specific checks.
659 return typeid(*this) == typeid(other);
374ca955
A
660}
661
662UBool Collator::operator!=(const Collator& other) const
663{
664 return (UBool)!(*this == other);
665}
666
667int32_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);
b75a7d8f
A
676}
677
678void
46f4442e 679Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) {
b75a7d8f
A
680}
681
374ca955
A
682UnicodeSet *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
b75a7d8f
A
691// -------------------------------------
692
374ca955
A
693#if !UCONFIG_NO_SERVICE
694URegistryKey U_EXPORT2
b75a7d8f
A
695Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
696{
697 if (U_SUCCESS(status)) {
57a6839d
A
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);
b75a7d8f
A
702 return getService()->registerInstance(toAdopt, locale, status);
703 }
704 return NULL;
705}
706
707// -------------------------------------
708
709class CFactory : public LocaleKeyFactory {
710private:
711 CollatorFactory* _delegate;
712 Hashtable* _ids;
374ca955 713
b75a7d8f
A
714public:
715 CFactory(CollatorFactory* delegate, UErrorCode& status)
716 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
717 , _delegate(delegate)
718 , _ids(NULL)
719 {
374ca955
A
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 }
b75a7d8f
A
736 }
737 }
4388f060
A
738
739 virtual ~CFactory();
740
b75a7d8f 741 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
374ca955
A
742
743protected:
b75a7d8f
A
744 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
745 {
746 if (U_SUCCESS(status)) {
747 return _ids;
748 }
749 return NULL;
750 }
374ca955 751
b75a7d8f
A
752 virtual UnicodeString&
753 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
754};
755
4388f060
A
756CFactory::~CFactory()
757{
758 delete _delegate;
759 delete _ids;
760}
761
b75a7d8f
A
762UObject*
763CFactory::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);
374ca955 769 return _delegate->createCollator(validLoc);
b75a7d8f
A
770 }
771 return NULL;
772}
773
774UnicodeString&
775CFactory::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
374ca955 790URegistryKey U_EXPORT2
b75a7d8f
A
791Collator::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
374ca955 805UBool U_EXPORT2
b75a7d8f
A
806Collator::unregister(URegistryKey key, UErrorCode& status)
807{
374ca955
A
808 if (U_SUCCESS(status)) {
809 if (hasService()) {
810 return gService->unregister(key, status);
811 }
812 status = U_ILLEGAL_ARGUMENT_ERROR;
b75a7d8f 813 }
374ca955 814 return FALSE;
b75a7d8f 815}
46f4442e
A
816#endif /* UCONFIG_NO_SERVICE */
817
818class CollationLocaleListEnumeration : public StringEnumeration {
819private:
820 int32_t index;
821public:
822 static UClassID U_EXPORT2 getStaticClassID(void);
823 virtual UClassID getDynamicClassID(void) const;
824public:
825 CollationLocaleListEnumeration()
826 : index(0)
827 {
828 // The global variables should already be initialized.
829 //isAvailableLocaleListInitialized(status);
830 }
831
4388f060 832 virtual ~CollationLocaleListEnumeration();
46f4442e
A
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) {
729e4ab9 852 *resultLength = (int32_t)uprv_strlen(result);
46f4442e
A
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
4388f060
A
874CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {}
875
46f4442e
A
876UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
877
b75a7d8f
A
878
879// -------------------------------------
880
374ca955 881StringEnumeration* U_EXPORT2
b75a7d8f
A
882Collator::getAvailableLocales(void)
883{
46f4442e
A
884#if !UCONFIG_NO_SERVICE
885 if (hasService()) {
886 return getService()->getAvailableLocales();
887 }
374ca955 888#endif /* UCONFIG_NO_SERVICE */
46f4442e
A
889 UErrorCode status = U_ZERO_ERROR;
890 if (isAvailableLocaleListInitialized(status)) {
891 return new CollationLocaleListEnumeration();
892 }
893 return NULL;
894}
374ca955
A
895
896StringEnumeration* U_EXPORT2
897Collator::getKeywords(UErrorCode& status) {
b331163b
A
898 return UStringEnumeration::fromUEnumeration(
899 ucol_getKeywords(&status), status);
374ca955
A
900}
901
902StringEnumeration* U_EXPORT2
903Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
b331163b
A
904 return UStringEnumeration::fromUEnumeration(
905 ucol_getKeywordValues(keyword, &status), status);
374ca955
A
906}
907
729e4ab9
A
908StringEnumeration* U_EXPORT2
909Collator::getKeywordValuesForLocale(const char* key, const Locale& locale,
910 UBool commonlyUsed, UErrorCode& status) {
b331163b
A
911 return UStringEnumeration::fromUEnumeration(
912 ucol_getKeywordValuesForLocale(
913 key, locale.getName(), commonlyUsed, &status),
914 status);
729e4ab9
A
915}
916
374ca955
A
917Locale U_EXPORT2
918Collator::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);
b75a7d8f
A
928}
929
51004dcb
A
930Collator::ECollationStrength
931Collator::getStrength(void) const {
932 UErrorCode intStatus = U_ZERO_ERROR;
933 return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus);
934}
935
936void
937Collator::setStrength(ECollationStrength newStrength) {
938 UErrorCode intStatus = U_ZERO_ERROR;
939 setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus);
940}
941
57a6839d
A
942Collator &
943Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) {
944 if (U_SUCCESS(errorCode)) {
945 errorCode = U_UNSUPPORTED_ERROR;
946 }
947 return *this;
948}
949
950UColReorderCode
951Collator::getMaxVariable() const {
952 return UCOL_REORDER_CODE_PUNCTUATION;
953}
954
51004dcb 955int32_t
4388f060
A
956Collator::getReorderCodes(int32_t* /* dest*/,
957 int32_t /* destCapacity*/,
958 UErrorCode& status) const
729e4ab9
A
959{
960 if (U_SUCCESS(status)) {
961 status = U_UNSUPPORTED_ERROR;
962 }
963 return 0;
964}
965
51004dcb 966void
4388f060
A
967Collator::setReorderCodes(const int32_t* /* reorderCodes */,
968 int32_t /* reorderCodesLength */,
969 UErrorCode& status)
729e4ab9
A
970{
971 if (U_SUCCESS(status)) {
972 status = U_UNSUPPORTED_ERROR;
973 }
974}
975
57a6839d
A
976int32_t
977Collator::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;
4388f060 984 }
57a6839d
A
985 const CollationData *baseData = CollationRoot::getData(errorCode);
986 if(U_FAILURE(errorCode)) { return 0; }
987 return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode);
4388f060
A
988}
989
990int32_t
991Collator::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
57a6839d
A
1001UCollationResult
1002Collator::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(
3d1f044b
A
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),
57a6839d
A
1013 errorCode);
1014}
1015
1016int32_t
1017Collator::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
b75a7d8f
A
1025// UCollator private data members ----------------------------------------
1026
1027/* This is useless information */
1028/*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
1029
1030// -------------------------------------
1031
1032U_NAMESPACE_END
1033
b75a7d8f
A
1034#endif /* #if !UCONFIG_NO_COLLATION */
1035
1036/* eof */