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 62static icu::Locale* availableLocaleList = NULL; 63static int32_t availableLocaleListCount; 64static icu::ICULocaleService* gService = NULL; 65static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER; 66static icu::UInitOnce gAvailableLocaleListInitOnce; 67 68/** 69 * Release all static memory held by collator. 70 */ 71U_CDECL_BEGIN 72static 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 89U_CDECL_END 90 91U_NAMESPACE_BEGIN 92 93#if !UCONFIG_NO_SERVICE 94 95// ------------------------------------------ 96// 97// Registration 98// 99 100//------------------------------------------- 101 102CollatorFactory::~CollatorFactory() {} 103 104//------------------------------------------- 105 106UBool 107CollatorFactory::visible(void) const { 108 return TRUE; 109} 110 111//------------------------------------------- 112 113UnicodeString& 114CollatorFactory::getDisplayName(const Locale& objectLocale, 115 const Locale& displayLocale, 116 UnicodeString& result) 117{ 118 return objectLocale.getDisplayName(displayLocale, result); 119} 120 121// ------------------------------------- 122 123class ICUCollatorFactory : public ICUResourceBundleFactory { 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 131ICUCollatorFactory::~ICUCollatorFactory() {} 132 133UObject* 134ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const { 135 if (handlesKey(key, status)) { 136 const LocaleKey& lkey = (const LocaleKey&)key; 137 Locale loc; 138 // make sure the requested locale is correct 139 // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey 140 // but for ICU rb resources we use the actual one since it will fallback again 141 lkey.canonicalLocale(loc); 142 143 return Collator::makeInstance(loc, status); 144 } 145 return NULL; 146} 147 148// ------------------------------------- 149 150class ICUCollatorService : public ICULocaleService { 151public: 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 191ICUCollatorService::~ICUCollatorService() {} 192 193// ------------------------------------- 194 195static void U_CALLCONV initService() { 196 gService = new ICUCollatorService(); 197 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); 198} 199 200 201static ICULocaleService* 202getService(void) 203{ 204 umtx_initOnce(gServiceInitOnce, &initService); 205 return gService; 206} 207 208// ------------------------------------- 209 210static inline UBool 211hasService(void) 212{ 213 UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL); 214 return retVal; 215} 216 217#endif /* UCONFIG_NO_SERVICE */ 218 219static void U_CALLCONV 220initAvailableLocaleList(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 251static UBool isAvailableLocaleListInitialized(UErrorCode &status) { 252 umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status); 253 return U_SUCCESS(status); 254} 255 256 257// Collator public methods ----------------------------------------------- 258 259namespace { 260 261static const struct { 262 const char *name; 263 UColAttribute attr; 264} collAttributes[] = { 265 { "colStrength", UCOL_STRENGTH }, 266 { "colBackwards", UCOL_FRENCH_COLLATION }, 267 { "colCaseLevel", UCOL_CASE_LEVEL }, 268 { "colCaseFirst", UCOL_CASE_FIRST }, 269 { "colAlternate", UCOL_ALTERNATE_HANDLING }, 270 { "colNormalization", UCOL_NORMALIZATION_MODE }, 271 { "colNumeric", UCOL_NUMERIC_COLLATION } 272}; 273 274static const struct { 275 const char *name; 276 UColAttributeValue value; 277} collAttributeValues[] = { 278 { "primary", UCOL_PRIMARY }, 279 { "secondary", UCOL_SECONDARY }, 280 { "tertiary", UCOL_TERTIARY }, 281 { "quaternary", UCOL_QUATERNARY }, 282 // Note: Not supporting typo "quarternary" because it was never supported in locale IDs. 283 { "identical", UCOL_IDENTICAL }, 284 { "no", UCOL_OFF }, 285 { "yes", UCOL_ON }, 286 { "shifted", UCOL_SHIFTED }, 287 { "non-ignorable", UCOL_NON_IGNORABLE }, 288 { "lower", UCOL_LOWER_FIRST }, 289 { "upper", UCOL_UPPER_FIRST } 290}; 291 292static const char *collReorderCodes[UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST] = { 293 "space", "punct", "symbol", "currency", "digit" 294}; 295 296int32_t getReorderCode(const char *s) { 297 for (int32_t i = 0; i < UPRV_LENGTHOF(collReorderCodes); ++i) { 298 if (uprv_stricmp(s, collReorderCodes[i]) == 0) { 299 return UCOL_REORDER_CODE_FIRST + i; 300 } 301 } 302 // Not supporting "others" = UCOL_REORDER_CODE_OTHERS 303 // as a synonym for Zzzz = USCRIPT_UNKNOWN for now: 304 // Avoid introducing synonyms/aliases. 305 return -1; 306} 307 308/** 309 * Sets collation attributes according to locale keywords. See 310 * http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings 311 * 312 * Using "alias" keywords and values where defined: 313 * http://www.unicode.org/reports/tr35/tr35.html#Old_Locale_Extension_Syntax 314 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml 315 */ 316void setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) { 317 if (U_FAILURE(errorCode)) { 318 return; 319 } 320 if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) { 321 // No keywords. 322 return; 323 } 324 char value[1024]; // The reordering value could be long. 325 // Check for collation keywords that were already deprecated 326 // before any were supported in createInstance() (except for "collation"). 327 int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, UPRV_LENGTHOF(value), errorCode); 328 if (U_FAILURE(errorCode)) { 329 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 330 return; 331 } 332 if (length != 0) { 333 errorCode = U_UNSUPPORTED_ERROR; 334 return; 335 } 336 length = loc.getKeywordValue("variableTop", value, UPRV_LENGTHOF(value), errorCode); 337 if (U_FAILURE(errorCode)) { 338 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 339 return; 340 } 341 if (length != 0) { 342 errorCode = U_UNSUPPORTED_ERROR; 343 return; 344 } 345 // Parse known collation keywords, ignore others. 346 if (errorCode == U_STRING_NOT_TERMINATED_WARNING) { 347 errorCode = U_ZERO_ERROR; 348 } 349 for (int32_t i = 0; i < UPRV_LENGTHOF(collAttributes); ++i) { 350 length = loc.getKeywordValue(collAttributes[i].name, value, UPRV_LENGTHOF(value), errorCode); 351 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 352 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 353 return; 354 } 355 if (length == 0) { continue; } 356 for (int32_t j = 0;; ++j) { 357 if (j == UPRV_LENGTHOF(collAttributeValues)) { 358 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 359 return; 360 } 361 if (uprv_stricmp(value, collAttributeValues[j].name) == 0) { 362 coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode); 363 break; 364 } 365 } 366 } 367 length = loc.getKeywordValue("colReorder", value, UPRV_LENGTHOF(value), errorCode); 368 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 369 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 370 return; 371 } 372 if (length != 0) { 373 int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST]; 374 int32_t codesLength = 0; 375 char *scriptName = value; 376 for (;;) { 377 if (codesLength == UPRV_LENGTHOF(codes)) { 378 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 379 return; 380 } 381 char *limit = scriptName; 382 char c; 383 while ((c = *limit) != 0 && c != '-') { ++limit; } 384 *limit = 0; 385 int32_t code; 386 if ((limit - scriptName) == 4) { 387 // Strict parsing, accept only 4-letter script codes, not long names. 388 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName); 389 } else { 390 code = getReorderCode(scriptName); 391 } 392 if (code < 0) { 393 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 394 return; 395 } 396 codes[codesLength++] = code; 397 if (c == 0) { break; } 398 scriptName = limit + 1; 399 } 400 coll.setReorderCodes(codes, codesLength, errorCode); 401 } 402 length = loc.getKeywordValue("kv", value, UPRV_LENGTHOF(value), errorCode); 403 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 404 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 405 return; 406 } 407 if (length != 0) { 408 int32_t code = getReorderCode(value); 409 if (code < 0) { 410 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 411 return; 412 } 413 coll.setMaxVariable((UColReorderCode)code, errorCode); 414 } 415 if (U_FAILURE(errorCode)) { 416 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 417 } 418} 419 420} // namespace 421 422Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success) 423{ 424 return createInstance(Locale::getDefault(), success); 425} 426 427Collator* 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 457Collator* 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 476Collator * 477Collator::safeClone() const { 478 return clone(); 479} 480 481// implement deprecated, previously abstract method 482Collator::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 490Collator::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 499Collator::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 507UCollationResult Collator::compare(UCharIterator &/*sIter*/, 508 UCharIterator &/*tIter*/, 509 UErrorCode &status) const { 510 if(U_SUCCESS(status)) { 511 // Not implemented in the base class. 512 status = U_UNSUPPORTED_ERROR; 513 } 514 return UCOL_EQUAL; 515} 516 517UCollationResult Collator::compareUTF8(const StringPiece &source, 518 const StringPiece &target, 519 UErrorCode &status) const { 520 if(U_FAILURE(status)) { 521 return UCOL_EQUAL; 522 } 523 UCharIterator sIter, tIter; 524 uiter_setUTF8(&sIter, source.data(), source.length()); 525 uiter_setUTF8(&tIter, target.data(), target.length()); 526 return compare(sIter, tIter, status); 527} 528 529UBool 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 536UBool 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 543UBool 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 552const 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 565UnicodeString& 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 579UnicodeString& 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*/ 601Collator::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*/ 616Collator::Collator(UCollationStrength, UNormalizationMode ) 617: UObject() 618{ 619} 620 621Collator::~Collator() 622{ 623} 624 625Collator::Collator(const Collator &other) 626 : UObject(other) 627{ 628} 629 630UBool 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 636UBool Collator::operator!=(const Collator& other) const 637{ 638 return (UBool)!(*this == other); 639} 640 641int32_t U_EXPORT2 Collator::getBound(const uint8_t *source, 642 int32_t sourceLength, 643 UColBoundMode boundType, 644 uint32_t noOfLevels, 645 uint8_t *result, 646 int32_t resultLength, 647 UErrorCode &status) 648{ 649 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status); 650} 651 652void 653Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) { 654} 655 656UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const 657{ 658 if(U_FAILURE(status)) { 659 return NULL; 660 } 661 // everything can be changed 662 return new UnicodeSet(0, 0x10FFFF); 663} 664 665// ------------------------------------- 666 667#if !UCONFIG_NO_SERVICE 668URegistryKey U_EXPORT2 669Collator::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 683class CFactory : public LocaleKeyFactory { 684private: 685 CollatorFactory* _delegate; 686 Hashtable* _ids; 687 688public: 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 717protected: 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 730CFactory::~CFactory() 731{ 732 delete _delegate; 733 delete _ids; 734} 735 736UObject* 737CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const 738{ 739 if (handlesKey(key, status)) { 740 const LocaleKey& lkey = (const LocaleKey&)key; 741 Locale validLoc; 742 lkey.currentLocale(validLoc); 743 return _delegate->createCollator(validLoc); 744 } 745 return NULL; 746} 747 748UnicodeString& 749CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const 750{ 751 if ((_coverage & 0x1) == 0) { 752 UErrorCode status = U_ZERO_ERROR; 753 const Hashtable* ids = getSupportedIDs(status); 754 if (ids && (ids->get(id) != NULL)) { 755 Locale loc; 756 LocaleUtility::initLocaleFromName(id, loc); 757 return _delegate->getDisplayName(loc, locale, result); 758 } 759 } 760 result.setToBogus(); 761 return result; 762} 763 764URegistryKey U_EXPORT2 765Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status) 766{ 767 if (U_SUCCESS(status)) { 768 CFactory* f = new CFactory(toAdopt, status); 769 if (f) { 770 return getService()->registerFactory(f, status); 771 } 772 status = U_MEMORY_ALLOCATION_ERROR; 773 } 774 return NULL; 775} 776 777// ------------------------------------- 778 779UBool U_EXPORT2 780Collator::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 792class CollationLocaleListEnumeration : public StringEnumeration { 793private: 794 int32_t index; 795public: 796 static UClassID U_EXPORT2 getStaticClassID(void); 797 virtual UClassID getDynamicClassID(void) const; 798public: 799 CollationLocaleListEnumeration() 800 : index(0) 801 { 802 // The global variables should already be initialized. 803 //isAvailableLocaleListInitialized(status); 804 } 805 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 848CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {} 849 850UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration) 851 852 853// ------------------------------------- 854 855StringEnumeration* U_EXPORT2 856Collator::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 870StringEnumeration* U_EXPORT2 871Collator::getKeywords(UErrorCode& status) { 872 return UStringEnumeration::fromUEnumeration( 873 ucol_getKeywords(&status), status); 874} 875 876StringEnumeration* U_EXPORT2 877Collator::getKeywordValues(const char *keyword, UErrorCode& status) { 878 return UStringEnumeration::fromUEnumeration( 879 ucol_getKeywordValues(keyword, &status), status); 880} 881 882StringEnumeration* U_EXPORT2 883Collator::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 891Locale U_EXPORT2 892Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale, 893 UBool& isAvailable, UErrorCode& status) { 894 // This is a wrapper over ucol_getFunctionalEquivalent 895 char loc[ULOC_FULLNAME_CAPACITY]; 896 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc), 897 keyword, locale.getName(), &isAvailable, &status); 898 if (U_FAILURE(status)) { 899 *loc = 0; // root 900 } 901 return Locale::createFromName(loc); 902} 903 904Collator::ECollationStrength 905Collator::getStrength(void) const { 906 UErrorCode intStatus = U_ZERO_ERROR; 907 return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus); 908} 909 910void 911Collator::setStrength(ECollationStrength newStrength) { 912 UErrorCode intStatus = U_ZERO_ERROR; 913 setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus); 914} 915 916Collator & 917Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) { 918 if (U_SUCCESS(errorCode)) { 919 errorCode = U_UNSUPPORTED_ERROR; 920 } 921 return *this; 922} 923 924UColReorderCode 925Collator::getMaxVariable() const { 926 return UCOL_REORDER_CODE_PUNCTUATION; 927} 928 929int32_t 930Collator::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 940void 941Collator::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 950int32_t 951Collator::getEquivalentReorderCodes(int32_t reorderCode, 952 int32_t *dest, int32_t capacity, 953 UErrorCode &errorCode) { 954 if(U_FAILURE(errorCode)) { return 0; } 955 if(capacity < 0 || (dest == NULL && capacity > 0)) { 956 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 957 return 0; 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 964int32_t 965Collator::internalGetShortDefinitionString(const char * /*locale*/, 966 char * /*buffer*/, 967 int32_t /*capacity*/, 968 UErrorCode &status) const { 969 if(U_SUCCESS(status)) { 970 status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */ 971 } 972 return 0; 973} 974 975UCollationResult 976Collator::internalCompareUTF8(const char *left, int32_t leftLength, 977 const char *right, int32_t rightLength, 978 UErrorCode &errorCode) const { 979 if(U_FAILURE(errorCode)) { return UCOL_EQUAL; } 980 if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) { 981 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 982 return UCOL_EQUAL; 983 } 984 return compareUTF8( 985 StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength), 986 StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength), 987 errorCode); 988} 989 990int32_t 991Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2], 992 uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const { 993 if (U_SUCCESS(errorCode)) { 994 errorCode = U_UNSUPPORTED_ERROR; 995 } 996 return 0; 997} 998 999// UCollator private data members ---------------------------------------- 1000 1001/* This is useless information */ 1002/*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/ 1003 1004// ------------------------------------- 1005 1006U_NAMESPACE_END 1007 1008#endif /* #if !UCONFIG_NO_COLLATION */ 1009 1010/* eof */ 1011