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