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