1 // Copyright (C) 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 static UBool U_CALLCONV collator_cleanup(void) { 75 #if !UCONFIG_NO_SERVICE 76 if (gService) { 77 delete gService; 78 gService = NULL; 79 } 80 gServiceInitOnce.reset(); 81 #endif 82 if (availableLocaleList) { 83 delete []availableLocaleList; 84 availableLocaleList = NULL; 85 } 86 availableLocaleListCount = 0; 87 gAvailableLocaleListInitOnce.reset(); 88 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 CollatorFactory::~CollatorFactory() {} 105 106 //------------------------------------------- 107 108 UBool 109 CollatorFactory::visible(void) const { 110 return TRUE; 111 } 112 113 //------------------------------------------- 114 115 UnicodeString& 116 CollatorFactory::getDisplayName(const Locale& objectLocale, 117 const Locale& displayLocale, 118 UnicodeString& result) 119 { 120 return objectLocale.getDisplayName(displayLocale, result); 121 } 122 123 // ------------------------------------- 124 125 class ICUCollatorFactory : public ICUResourceBundleFactory { 126 public: 127 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 ICUCollatorFactory::~ICUCollatorFactory() {} 134 135 UObject* 136 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const { 137 if (handlesKey(key, status)) { 138 const LocaleKey& lkey = (const LocaleKey&)key; 139 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 lkey.canonicalLocale(loc); 144 145 return Collator::makeInstance(loc, status); 146 } 147 return NULL; 148 } 149 150 // ------------------------------------- 151 152 class ICUCollatorService : public ICULocaleService { 153 public: 154 ICUCollatorService() 155 : ICULocaleService(UNICODE_STRING_SIMPLE("Collator")) 156 { 157 UErrorCode status = U_ZERO_ERROR; 158 registerFactory(new ICUCollatorFactory(), status); 159 } 160 161 virtual ~ICUCollatorService(); 162 163 virtual UObject* cloneInstance(UObject* instance) const { 164 return ((Collator*)instance)->clone(); 165 } 166 167 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const { 168 LocaleKey& lkey = (LocaleKey&)key; 169 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 actualID->truncate(0); 174 } 175 Locale loc(""); 176 lkey.canonicalLocale(loc); 177 return Collator::makeInstance(loc, status); 178 } 179 180 virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const { 181 UnicodeString ar; 182 if (actualReturn == NULL) { 183 actualReturn = &ar; 184 } 185 return (Collator*)ICULocaleService::getKey(key, actualReturn, status); 186 } 187 188 virtual UBool isDefault() const { 189 return countFactories() == 1; 190 } 191 }; 192 193 ICUCollatorService::~ICUCollatorService() {} 194 195 // ------------------------------------- 196 197 static void U_CALLCONV initService() { 198 gService = new ICUCollatorService(); 199 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); 200 } 201 202 203 static ICULocaleService* 204 getService(void) 205 { 206 umtx_initOnce(gServiceInitOnce, &initService); 207 return gService; 208 } 209 210 // ------------------------------------- 211 212 static inline UBool 213 hasService(void) 214 { 215 UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL); 216 return retVal; 217 } 218 219 #endif /* UCONFIG_NO_SERVICE */ 220 221 static void U_CALLCONV 222 initAvailableLocaleList(UErrorCode &status) { 223 U_ASSERT(availableLocaleListCount == 0); 224 U_ASSERT(availableLocaleList == NULL); 225 // for now, there is a hardcoded list, so just walk through that list and set it up. 226 UResourceBundle *index = NULL; 227 UResourceBundle installed; 228 int32_t i = 0; 229 230 ures_initStackObject(&installed); 231 index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status); 232 ures_getByKey(index, "InstalledLocales", &installed, &status); 233 234 if(U_SUCCESS(status)) { 235 availableLocaleListCount = ures_getSize(&installed); 236 availableLocaleList = new Locale[availableLocaleListCount]; 237 238 if (availableLocaleList != NULL) { 239 ures_resetIterator(&installed); 240 while(ures_hasNext(&installed)) { 241 const char *tempKey = NULL; 242 ures_getNextString(&installed, NULL, &tempKey, &status); 243 availableLocaleList[i++] = Locale(tempKey); 244 } 245 } 246 U_ASSERT(availableLocaleListCount == i); 247 ures_close(&installed); 248 } 249 ures_close(index); 250 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); 251 } 252 253 static UBool isAvailableLocaleListInitialized(UErrorCode &status) { 254 umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status); 255 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 int32_t getReorderCode(const char *s) { 299 for (int32_t i = 0; i < UPRV_LENGTHOF(collReorderCodes); ++i) { 300 if (uprv_stricmp(s, collReorderCodes[i]) == 0) { 301 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 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 void setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) { 319 if (U_FAILURE(errorCode)) { 320 return; 321 } 322 if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) { 323 // No keywords. 324 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 int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, UPRV_LENGTHOF(value), errorCode); 330 if (U_FAILURE(errorCode)) { 331 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 332 return; 333 } 334 if (length != 0) { 335 errorCode = U_UNSUPPORTED_ERROR; 336 return; 337 } 338 length = loc.getKeywordValue("variableTop", value, UPRV_LENGTHOF(value), errorCode); 339 if (U_FAILURE(errorCode)) { 340 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 341 return; 342 } 343 if (length != 0) { 344 errorCode = U_UNSUPPORTED_ERROR; 345 return; 346 } 347 // Parse known collation keywords, ignore others. 348 if (errorCode == U_STRING_NOT_TERMINATED_WARNING) { 349 errorCode = U_ZERO_ERROR; 350 } 351 for (int32_t i = 0; i < UPRV_LENGTHOF(collAttributes); ++i) { 352 length = loc.getKeywordValue(collAttributes[i].name, value, UPRV_LENGTHOF(value), errorCode); 353 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 354 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 355 return; 356 } 357 if (length == 0) { continue; } 358 for (int32_t j = 0;; ++j) { 359 if (j == UPRV_LENGTHOF(collAttributeValues)) { 360 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 361 return; 362 } 363 if (uprv_stricmp(value, collAttributeValues[j].name) == 0) { 364 coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode); 365 break; 366 } 367 } 368 } 369 length = loc.getKeywordValue("colReorder", value, UPRV_LENGTHOF(value), errorCode); 370 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 371 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 372 return; 373 } 374 if (length != 0) { 375 int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST]; 376 int32_t codesLength = 0; 377 char *scriptName = value; 378 for (;;) { 379 if (codesLength == UPRV_LENGTHOF(codes)) { 380 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 381 return; 382 } 383 char *limit = scriptName; 384 char c; 385 while ((c = *limit) != 0 && c != '-') { ++limit; } 386 *limit = 0; 387 int32_t code; 388 if ((limit - scriptName) == 4) { 389 // Strict parsing, accept only 4-letter script codes, not long names. 390 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName); 391 } else { 392 code = getReorderCode(scriptName); 393 } 394 if (code < 0) { 395 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 396 return; 397 } 398 codes[codesLength++] = code; 399 if (c == 0) { break; } 400 scriptName = limit + 1; 401 } 402 coll.setReorderCodes(codes, codesLength, errorCode); 403 } 404 length = loc.getKeywordValue("kv", value, UPRV_LENGTHOF(value), errorCode); 405 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 406 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 407 return; 408 } 409 if (length != 0) { 410 int32_t code = getReorderCode(value); 411 if (code < 0) { 412 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 413 return; 414 } 415 coll.setMaxVariable((UColReorderCode)code, errorCode); 416 } 417 if (U_FAILURE(errorCode)) { 418 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 419 } 420 } 421 422 } // namespace 423 424 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success) 425 { 426 return createInstance(Locale::getDefault(), success); 427 } 428 429 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale, 430 UErrorCode& status) 431 { 432 if (U_FAILURE(status)) 433 return 0; 434 if (desiredLocale.isBogus()) { 435 // Locale constructed from malformed locale ID or language tag. 436 status = U_ILLEGAL_ARGUMENT_ERROR; 437 return NULL; 438 } 439 440 Collator* coll; 441 #if !UCONFIG_NO_SERVICE 442 if (hasService()) { 443 Locale actualLoc; 444 coll = (Collator*)gService->get(desiredLocale, &actualLoc, status); 445 } else 446 #endif 447 { 448 coll = makeInstance(desiredLocale, status); 449 } 450 setAttributesFromKeywords(desiredLocale, *coll, status); 451 if (U_FAILURE(status)) { 452 delete coll; 453 return NULL; 454 } 455 return coll; 456 } 457 458 459 Collator* Collator::makeInstance(const Locale& desiredLocale, UErrorCode& status) { 460 const CollationCacheEntry *entry = CollationLoader::loadTailoring(desiredLocale, status); 461 if (U_SUCCESS(status)) { 462 Collator *result = new RuleBasedCollator(entry); 463 if (result != NULL) { 464 // Both the unified cache's get() and the RBC constructor 465 // did addRef(). Undo one of them. 466 entry->removeRef(); 467 return result; 468 } 469 status = U_MEMORY_ALLOCATION_ERROR; 470 } 471 if (entry != NULL) { 472 // Undo the addRef() from the cache.get(). 473 entry->removeRef(); 474 } 475 return NULL; 476 } 477 478 Collator * 479 Collator::safeClone() const { 480 return clone(); 481 } 482 483 // implement deprecated, previously abstract method 484 Collator::EComparisonResult Collator::compare(const UnicodeString& source, 485 const UnicodeString& target) const 486 { 487 UErrorCode ec = U_ZERO_ERROR; 488 return (EComparisonResult)compare(source, target, ec); 489 } 490 491 // implement deprecated, previously abstract method 492 Collator::EComparisonResult Collator::compare(const UnicodeString& source, 493 const UnicodeString& target, 494 int32_t length) const 495 { 496 UErrorCode ec = U_ZERO_ERROR; 497 return (EComparisonResult)compare(source, target, length, ec); 498 } 499 500 // implement deprecated, previously abstract method 501 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength, 502 const UChar* target, int32_t targetLength) 503 const 504 { 505 UErrorCode ec = U_ZERO_ERROR; 506 return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec); 507 } 508 509 UCollationResult Collator::compare(UCharIterator &/*sIter*/, 510 UCharIterator &/*tIter*/, 511 UErrorCode &status) const { 512 if(U_SUCCESS(status)) { 513 // Not implemented in the base class. 514 status = U_UNSUPPORTED_ERROR; 515 } 516 return UCOL_EQUAL; 517 } 518 519 UCollationResult Collator::compareUTF8(const StringPiece &source, 520 const StringPiece &target, 521 UErrorCode &status) const { 522 if(U_FAILURE(status)) { 523 return UCOL_EQUAL; 524 } 525 UCharIterator sIter, tIter; 526 uiter_setUTF8(&sIter, source.data(), source.length()); 527 uiter_setUTF8(&tIter, target.data(), target.length()); 528 return compare(sIter, tIter, status); 529 } 530 531 UBool Collator::equals(const UnicodeString& source, 532 const UnicodeString& target) const 533 { 534 UErrorCode ec = U_ZERO_ERROR; 535 return (compare(source, target, ec) == UCOL_EQUAL); 536 } 537 538 UBool Collator::greaterOrEqual(const UnicodeString& source, 539 const UnicodeString& target) const 540 { 541 UErrorCode ec = U_ZERO_ERROR; 542 return (compare(source, target, ec) != UCOL_LESS); 543 } 544 545 UBool Collator::greater(const UnicodeString& source, 546 const UnicodeString& target) const 547 { 548 UErrorCode ec = U_ZERO_ERROR; 549 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 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count) 555 { 556 UErrorCode status = U_ZERO_ERROR; 557 Locale *result = NULL; 558 count = 0; 559 if (isAvailableLocaleListInitialized(status)) 560 { 561 result = availableLocaleList; 562 count = availableLocaleListCount; 563 } 564 return result; 565 } 566 567 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, 568 const Locale& displayLocale, 569 UnicodeString& name) 570 { 571 #if !UCONFIG_NO_SERVICE 572 if (hasService()) { 573 UnicodeString locNameStr; 574 LocaleUtility::initNameFromLocale(objectLocale, locNameStr); 575 return gService->getDisplayName(locNameStr, name, displayLocale); 576 } 577 #endif 578 return objectLocale.getDisplayName(displayLocale, name); 579 } 580 581 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, 582 UnicodeString& name) 583 { 584 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 Collator::Collator() 604 : UObject() 605 { 606 } 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 Collator::Collator(UCollationStrength, UNormalizationMode ) 619 : UObject() 620 { 621 } 622 623 Collator::~Collator() 624 { 625 } 626 627 Collator::Collator(const Collator &other) 628 : UObject(other) 629 { 630 } 631 632 UBool Collator::operator==(const Collator& other) const 633 { 634 // Subclasses: Call this method and then add more specific checks. 635 return typeid(*this) == typeid(other); 636 } 637 638 UBool Collator::operator!=(const Collator& other) const 639 { 640 return (UBool)!(*this == other); 641 } 642 643 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 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status); 652 } 653 654 void 655 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) { 656 } 657 658 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const 659 { 660 if(U_FAILURE(status)) { 661 return NULL; 662 } 663 // everything can be changed 664 return new UnicodeSet(0, 0x10FFFF); 665 } 666 667 // ------------------------------------- 668 669 #if !UCONFIG_NO_SERVICE 670 URegistryKey U_EXPORT2 671 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status) 672 { 673 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 toAdopt->setLocales(locale, locale, locale); 678 return getService()->registerInstance(toAdopt, locale, status); 679 } 680 return NULL; 681 } 682 683 // ------------------------------------- 684 685 class CFactory : public LocaleKeyFactory { 686 private: 687 CollatorFactory* _delegate; 688 Hashtable* _ids; 689 690 public: 691 CFactory(CollatorFactory* delegate, UErrorCode& status) 692 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE) 693 , _delegate(delegate) 694 , _ids(NULL) 695 { 696 if (U_SUCCESS(status)) { 697 int32_t count = 0; 698 _ids = new Hashtable(status); 699 if (_ids) { 700 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status); 701 for (int i = 0; i < count; ++i) { 702 _ids->put(idlist[i], (void*)this, status); 703 if (U_FAILURE(status)) { 704 delete _ids; 705 _ids = NULL; 706 return; 707 } 708 } 709 } else { 710 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 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const 721 { 722 if (U_SUCCESS(status)) { 723 return _ids; 724 } 725 return NULL; 726 } 727 728 virtual UnicodeString& 729 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const; 730 }; 731 732 CFactory::~CFactory() 733 { 734 delete _delegate; 735 delete _ids; 736 } 737 738 UObject* 739 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const 740 { 741 if (handlesKey(key, status)) { 742 const LocaleKey& lkey = (const LocaleKey&)key; 743 Locale validLoc; 744 lkey.currentLocale(validLoc); 745 return _delegate->createCollator(validLoc); 746 } 747 return NULL; 748 } 749 750 UnicodeString& 751 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const 752 { 753 if ((_coverage & 0x1) == 0) { 754 UErrorCode status = U_ZERO_ERROR; 755 const Hashtable* ids = getSupportedIDs(status); 756 if (ids && (ids->get(id) != NULL)) { 757 Locale loc; 758 LocaleUtility::initLocaleFromName(id, loc); 759 return _delegate->getDisplayName(loc, locale, result); 760 } 761 } 762 result.setToBogus(); 763 return result; 764 } 765 766 URegistryKey U_EXPORT2 767 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status) 768 { 769 if (U_SUCCESS(status)) { 770 CFactory* f = new CFactory(toAdopt, status); 771 if (f) { 772 return getService()->registerFactory(f, status); 773 } 774 status = U_MEMORY_ALLOCATION_ERROR; 775 } 776 return NULL; 777 } 778 779 // ------------------------------------- 780 781 UBool U_EXPORT2 782 Collator::unregister(URegistryKey key, UErrorCode& status) 783 { 784 if (U_SUCCESS(status)) { 785 if (hasService()) { 786 return gService->unregister(key, status); 787 } 788 status = U_ILLEGAL_ARGUMENT_ERROR; 789 } 790 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 CollationLocaleListEnumeration() 802 : index(0) 803 { 804 // The global variables should already be initialized. 805 //isAvailableLocaleListInitialized(status); 806 } 807 808 virtual ~CollationLocaleListEnumeration(); 809 810 virtual StringEnumeration * clone() const 811 { 812 CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration(); 813 if (result) { 814 result->index = index; 815 } 816 return result; 817 } 818 819 virtual int32_t count(UErrorCode &/*status*/) const { 820 return availableLocaleListCount; 821 } 822 823 virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) { 824 const char* result; 825 if(index < availableLocaleListCount) { 826 result = availableLocaleList[index++].getName(); 827 if(resultLength != NULL) { 828 *resultLength = (int32_t)uprv_strlen(result); 829 } 830 } else { 831 if(resultLength != NULL) { 832 *resultLength = 0; 833 } 834 result = NULL; 835 } 836 return result; 837 } 838 839 virtual const UnicodeString* snext(UErrorCode& status) { 840 int32_t resultLength = 0; 841 const char *s = next(&resultLength, status); 842 return setChars(s, resultLength, status); 843 } 844 845 virtual void reset(UErrorCode& /*status*/) { 846 index = 0; 847 } 848 }; 849 850 CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {} 851 852 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration) 853 854 855 // ------------------------------------- 856 857 StringEnumeration* U_EXPORT2 858 Collator::getAvailableLocales(void) 859 { 860 #if !UCONFIG_NO_SERVICE 861 if (hasService()) { 862 return getService()->getAvailableLocales(); 863 } 864 #endif /* UCONFIG_NO_SERVICE */ 865 UErrorCode status = U_ZERO_ERROR; 866 if (isAvailableLocaleListInitialized(status)) { 867 return new CollationLocaleListEnumeration(); 868 } 869 return NULL; 870 } 871 872 StringEnumeration* U_EXPORT2 873 Collator::getKeywords(UErrorCode& status) { 874 return UStringEnumeration::fromUEnumeration( 875 ucol_getKeywords(&status), status); 876 } 877 878 StringEnumeration* U_EXPORT2 879 Collator::getKeywordValues(const char *keyword, UErrorCode& status) { 880 return UStringEnumeration::fromUEnumeration( 881 ucol_getKeywordValues(keyword, &status), status); 882 } 883 884 StringEnumeration* U_EXPORT2 885 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale, 886 UBool commonlyUsed, UErrorCode& status) { 887 return UStringEnumeration::fromUEnumeration( 888 ucol_getKeywordValuesForLocale( 889 key, locale.getName(), commonlyUsed, &status), 890 status); 891 } 892 893 Locale U_EXPORT2 894 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 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc), 899 keyword, locale.getName(), &isAvailable, &status); 900 if (U_FAILURE(status)) { 901 *loc = 0; // root 902 } 903 return Locale::createFromName(loc); 904 } 905 906 Collator::ECollationStrength 907 Collator::getStrength(void) const { 908 UErrorCode intStatus = U_ZERO_ERROR; 909 return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus); 910 } 911 912 void 913 Collator::setStrength(ECollationStrength newStrength) { 914 UErrorCode intStatus = U_ZERO_ERROR; 915 setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus); 916 } 917 918 Collator & 919 Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) { 920 if (U_SUCCESS(errorCode)) { 921 errorCode = U_UNSUPPORTED_ERROR; 922 } 923 return *this; 924 } 925 926 UColReorderCode 927 Collator::getMaxVariable() const { 928 return UCOL_REORDER_CODE_PUNCTUATION; 929 } 930 931 int32_t 932 Collator::getReorderCodes(int32_t* /* dest*/, 933 int32_t /* destCapacity*/, 934 UErrorCode& status) const 935 { 936 if (U_SUCCESS(status)) { 937 status = U_UNSUPPORTED_ERROR; 938 } 939 return 0; 940 } 941 942 void 943 Collator::setReorderCodes(const int32_t* /* reorderCodes */, 944 int32_t /* reorderCodesLength */, 945 UErrorCode& status) 946 { 947 if (U_SUCCESS(status)) { 948 status = U_UNSUPPORTED_ERROR; 949 } 950 } 951 952 int32_t 953 Collator::getEquivalentReorderCodes(int32_t reorderCode, 954 int32_t *dest, int32_t capacity, 955 UErrorCode &errorCode) { 956 if(U_FAILURE(errorCode)) { return 0; } 957 if(capacity < 0 || (dest == NULL && capacity > 0)) { 958 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 959 return 0; 960 } 961 const CollationData *baseData = CollationRoot::getData(errorCode); 962 if(U_FAILURE(errorCode)) { return 0; } 963 return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode); 964 } 965 966 int32_t 967 Collator::internalGetShortDefinitionString(const char * /*locale*/, 968 char * /*buffer*/, 969 int32_t /*capacity*/, 970 UErrorCode &status) const { 971 if(U_SUCCESS(status)) { 972 status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */ 973 } 974 return 0; 975 } 976 977 UCollationResult 978 Collator::internalCompareUTF8(const char *left, int32_t leftLength, 979 const char *right, int32_t rightLength, 980 UErrorCode &errorCode) const { 981 if(U_FAILURE(errorCode)) { return UCOL_EQUAL; } 982 if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) { 983 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 984 return UCOL_EQUAL; 985 } 986 return compareUTF8( 987 StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength), 988 StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength), 989 errorCode); 990 } 991 992 int32_t 993 Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2], 994 uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const { 995 if (U_SUCCESS(errorCode)) { 996 errorCode = U_UNSUPPORTED_ERROR; 997 } 998 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 */ 1013