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