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