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 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 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 < LENGTHOF(collReorderCodes); ++i) { 300 if (uprv_stricmp(s, collReorderCodes[i]) == 0) { 301 return UCOL_REORDER_CODE_FIRST + i; 302 } 303 } 304 return -1; 305 } 306 307 /** 308 * Sets collation attributes according to locale keywords. See 309 * http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings 310 * 311 * Using "alias" keywords and values where defined: 312 * http://www.unicode.org/reports/tr35/tr35.html#Old_Locale_Extension_Syntax 313 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml 314 */ 315 void setAttributesFromKeywords(const Locale &loc, Collator &coll, UErrorCode &errorCode) { 316 if (U_FAILURE(errorCode)) { 317 return; 318 } 319 if (uprv_strcmp(loc.getName(), loc.getBaseName()) == 0) { 320 // No keywords. 321 return; 322 } 323 char value[1024]; // The reordering value could be long. 324 // Check for collation keywords that were already deprecated 325 // before any were supported in createInstance() (except for "collation"). 326 int32_t length = loc.getKeywordValue("colHiraganaQuaternary", value, LENGTHOF(value), errorCode); 327 if (U_FAILURE(errorCode)) { 328 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 329 return; 330 } 331 if (length != 0) { 332 errorCode = U_UNSUPPORTED_ERROR; 333 return; 334 } 335 length = loc.getKeywordValue("variableTop", value, LENGTHOF(value), errorCode); 336 if (U_FAILURE(errorCode)) { 337 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 338 return; 339 } 340 if (length != 0) { 341 errorCode = U_UNSUPPORTED_ERROR; 342 return; 343 } 344 // Parse known collation keywords, ignore others. 345 if (errorCode == U_STRING_NOT_TERMINATED_WARNING) { 346 errorCode = U_ZERO_ERROR; 347 } 348 for (int32_t i = 0; i < LENGTHOF(collAttributes); ++i) { 349 length = loc.getKeywordValue(collAttributes[i].name, value, LENGTHOF(value), errorCode); 350 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 351 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 352 return; 353 } 354 if (length == 0) { continue; } 355 for (int32_t j = 0;; ++j) { 356 if (j == LENGTHOF(collAttributeValues)) { 357 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 358 return; 359 } 360 if (uprv_stricmp(value, collAttributeValues[j].name) == 0) { 361 coll.setAttribute(collAttributes[i].attr, collAttributeValues[j].value, errorCode); 362 break; 363 } 364 } 365 } 366 length = loc.getKeywordValue("colReorder", value, LENGTHOF(value), errorCode); 367 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 368 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 369 return; 370 } 371 if (length != 0) { 372 int32_t codes[USCRIPT_CODE_LIMIT + UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST]; 373 int32_t codesLength = 0; 374 char *scriptName = value; 375 for (;;) { 376 if (codesLength == LENGTHOF(codes)) { 377 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 378 return; 379 } 380 char *limit = scriptName; 381 char c; 382 while ((c = *limit) != 0 && c != '-') { ++limit; } 383 *limit = 0; 384 int32_t code; 385 if ((limit - scriptName) == 4) { 386 // Strict parsing, accept only 4-letter script codes, not long names. 387 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName); 388 } else { 389 code = getReorderCode(scriptName); 390 } 391 if (code < 0) { 392 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 393 return; 394 } 395 codes[codesLength++] = code; 396 if (c == 0) { break; } 397 scriptName = limit + 1; 398 } 399 coll.setReorderCodes(codes, codesLength, errorCode); 400 } 401 length = loc.getKeywordValue("kv", value, LENGTHOF(value), errorCode); 402 if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) { 403 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 404 return; 405 } 406 if (length != 0) { 407 int32_t code = getReorderCode(value); 408 if (code < 0) { 409 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 410 return; 411 } 412 coll.setMaxVariable((UColReorderCode)code, errorCode); 413 } 414 if (U_FAILURE(errorCode)) { 415 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 416 } 417 } 418 419 } // namespace 420 421 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success) 422 { 423 return createInstance(Locale::getDefault(), success); 424 } 425 426 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale, 427 UErrorCode& status) 428 { 429 if (U_FAILURE(status)) 430 return 0; 431 if (desiredLocale.isBogus()) { 432 // Locale constructed from malformed locale ID or language tag. 433 status = U_ILLEGAL_ARGUMENT_ERROR; 434 return NULL; 435 } 436 437 Collator* coll; 438 #if !UCONFIG_NO_SERVICE 439 if (hasService()) { 440 Locale actualLoc; 441 coll = (Collator*)gService->get(desiredLocale, &actualLoc, status); 442 } else 443 #endif 444 { 445 coll = makeInstance(desiredLocale, status); 446 } 447 setAttributesFromKeywords(desiredLocale, *coll, status); 448 if (U_FAILURE(status)) { 449 delete coll; 450 return NULL; 451 } 452 return coll; 453 } 454 455 456 Collator* Collator::makeInstance(const Locale& desiredLocale, 457 UErrorCode& status) 458 { 459 Locale validLocale(""); 460 const CollationTailoring *t = 461 CollationLoader::loadTailoring(desiredLocale, validLocale, status); 462 if (U_SUCCESS(status)) { 463 Collator *result = new RuleBasedCollator(t, validLocale); 464 if (result != NULL) { 465 return result; 466 } 467 status = U_MEMORY_ALLOCATION_ERROR; 468 } 469 if (t != NULL) { 470 t->deleteIfZeroRefCount(); 471 } 472 return NULL; 473 } 474 475 Collator * 476 Collator::safeClone() const { 477 return clone(); 478 } 479 480 // implement deprecated, previously abstract method 481 Collator::EComparisonResult Collator::compare(const UnicodeString& source, 482 const UnicodeString& target) const 483 { 484 UErrorCode ec = U_ZERO_ERROR; 485 return (EComparisonResult)compare(source, target, ec); 486 } 487 488 // implement deprecated, previously abstract method 489 Collator::EComparisonResult Collator::compare(const UnicodeString& source, 490 const UnicodeString& target, 491 int32_t length) const 492 { 493 UErrorCode ec = U_ZERO_ERROR; 494 return (EComparisonResult)compare(source, target, length, ec); 495 } 496 497 // implement deprecated, previously abstract method 498 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength, 499 const UChar* target, int32_t targetLength) 500 const 501 { 502 UErrorCode ec = U_ZERO_ERROR; 503 return (EComparisonResult)compare(source, sourceLength, target, targetLength, ec); 504 } 505 506 UCollationResult Collator::compare(UCharIterator &/*sIter*/, 507 UCharIterator &/*tIter*/, 508 UErrorCode &status) const { 509 if(U_SUCCESS(status)) { 510 // Not implemented in the base class. 511 status = U_UNSUPPORTED_ERROR; 512 } 513 return UCOL_EQUAL; 514 } 515 516 UCollationResult Collator::compareUTF8(const StringPiece &source, 517 const StringPiece &target, 518 UErrorCode &status) const { 519 if(U_FAILURE(status)) { 520 return UCOL_EQUAL; 521 } 522 UCharIterator sIter, tIter; 523 uiter_setUTF8(&sIter, source.data(), source.length()); 524 uiter_setUTF8(&tIter, target.data(), target.length()); 525 return compare(sIter, tIter, status); 526 } 527 528 UBool Collator::equals(const UnicodeString& source, 529 const UnicodeString& target) const 530 { 531 UErrorCode ec = U_ZERO_ERROR; 532 return (compare(source, target, ec) == UCOL_EQUAL); 533 } 534 535 UBool Collator::greaterOrEqual(const UnicodeString& source, 536 const UnicodeString& target) const 537 { 538 UErrorCode ec = U_ZERO_ERROR; 539 return (compare(source, target, ec) != UCOL_LESS); 540 } 541 542 UBool Collator::greater(const UnicodeString& source, 543 const UnicodeString& target) const 544 { 545 UErrorCode ec = U_ZERO_ERROR; 546 return (compare(source, target, ec) == UCOL_GREATER); 547 } 548 549 // this API ignores registered collators, since it returns an 550 // array of indefinite lifetime 551 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count) 552 { 553 UErrorCode status = U_ZERO_ERROR; 554 Locale *result = NULL; 555 count = 0; 556 if (isAvailableLocaleListInitialized(status)) 557 { 558 result = availableLocaleList; 559 count = availableLocaleListCount; 560 } 561 return result; 562 } 563 564 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, 565 const Locale& displayLocale, 566 UnicodeString& name) 567 { 568 #if !UCONFIG_NO_SERVICE 569 if (hasService()) { 570 UnicodeString locNameStr; 571 LocaleUtility::initNameFromLocale(objectLocale, locNameStr); 572 return gService->getDisplayName(locNameStr, name, displayLocale); 573 } 574 #endif 575 return objectLocale.getDisplayName(displayLocale, name); 576 } 577 578 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, 579 UnicodeString& name) 580 { 581 return getDisplayName(objectLocale, Locale::getDefault(), name); 582 } 583 584 /* This is useless information */ 585 /*void Collator::getVersion(UVersionInfo versionInfo) const 586 { 587 if (versionInfo!=NULL) 588 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH); 589 } 590 */ 591 592 // UCollator protected constructor destructor ---------------------------- 593 594 /** 595 * Default constructor. 596 * Constructor is different from the old default Collator constructor. 597 * The task for determing the default collation strength and normalization mode 598 * is left to the child class. 599 */ 600 Collator::Collator() 601 : UObject() 602 { 603 } 604 605 /** 606 * Constructor. 607 * Empty constructor, does not handle the arguments. 608 * This constructor is done for backward compatibility with 1.7 and 1.8. 609 * The task for handling the argument collation strength and normalization 610 * mode is left to the child class. 611 * @param collationStrength collation strength 612 * @param decompositionMode 613 * @deprecated 2.4 use the default constructor instead 614 */ 615 Collator::Collator(UCollationStrength, UNormalizationMode ) 616 : UObject() 617 { 618 } 619 620 Collator::~Collator() 621 { 622 } 623 624 Collator::Collator(const Collator &other) 625 : UObject(other) 626 { 627 } 628 629 UBool Collator::operator==(const Collator& other) const 630 { 631 // Subclasses: Call this method and then add more specific checks. 632 return typeid(*this) == typeid(other); 633 } 634 635 UBool Collator::operator!=(const Collator& other) const 636 { 637 return (UBool)!(*this == other); 638 } 639 640 int32_t U_EXPORT2 Collator::getBound(const uint8_t *source, 641 int32_t sourceLength, 642 UColBoundMode boundType, 643 uint32_t noOfLevels, 644 uint8_t *result, 645 int32_t resultLength, 646 UErrorCode &status) 647 { 648 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status); 649 } 650 651 void 652 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */, const Locale& /*actualLocale*/) { 653 } 654 655 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const 656 { 657 if(U_FAILURE(status)) { 658 return NULL; 659 } 660 // everything can be changed 661 return new UnicodeSet(0, 0x10FFFF); 662 } 663 664 // ------------------------------------- 665 666 #if !UCONFIG_NO_SERVICE 667 URegistryKey U_EXPORT2 668 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status) 669 { 670 if (U_SUCCESS(status)) { 671 // Set the collator locales while registering so that createInstance() 672 // need not guess whether the collator's locales are already set properly 673 // (as they are by the data loader). 674 toAdopt->setLocales(locale, locale, locale); 675 return getService()->registerInstance(toAdopt, locale, status); 676 } 677 return NULL; 678 } 679 680 // ------------------------------------- 681 682 class CFactory : public LocaleKeyFactory { 683 private: 684 CollatorFactory* _delegate; 685 Hashtable* _ids; 686 687 public: 688 CFactory(CollatorFactory* delegate, UErrorCode& status) 689 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE) 690 , _delegate(delegate) 691 , _ids(NULL) 692 { 693 if (U_SUCCESS(status)) { 694 int32_t count = 0; 695 _ids = new Hashtable(status); 696 if (_ids) { 697 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status); 698 for (int i = 0; i < count; ++i) { 699 _ids->put(idlist[i], (void*)this, status); 700 if (U_FAILURE(status)) { 701 delete _ids; 702 _ids = NULL; 703 return; 704 } 705 } 706 } else { 707 status = U_MEMORY_ALLOCATION_ERROR; 708 } 709 } 710 } 711 712 virtual ~CFactory(); 713 714 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const; 715 716 protected: 717 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const 718 { 719 if (U_SUCCESS(status)) { 720 return _ids; 721 } 722 return NULL; 723 } 724 725 virtual UnicodeString& 726 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const; 727 }; 728 729 CFactory::~CFactory() 730 { 731 delete _delegate; 732 delete _ids; 733 } 734 735 UObject* 736 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const 737 { 738 if (handlesKey(key, status)) { 739 const LocaleKey& lkey = (const LocaleKey&)key; 740 Locale validLoc; 741 lkey.currentLocale(validLoc); 742 return _delegate->createCollator(validLoc); 743 } 744 return NULL; 745 } 746 747 UnicodeString& 748 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const 749 { 750 if ((_coverage & 0x1) == 0) { 751 UErrorCode status = U_ZERO_ERROR; 752 const Hashtable* ids = getSupportedIDs(status); 753 if (ids && (ids->get(id) != NULL)) { 754 Locale loc; 755 LocaleUtility::initLocaleFromName(id, loc); 756 return _delegate->getDisplayName(loc, locale, result); 757 } 758 } 759 result.setToBogus(); 760 return result; 761 } 762 763 URegistryKey U_EXPORT2 764 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status) 765 { 766 if (U_SUCCESS(status)) { 767 CFactory* f = new CFactory(toAdopt, status); 768 if (f) { 769 return getService()->registerFactory(f, status); 770 } 771 status = U_MEMORY_ALLOCATION_ERROR; 772 } 773 return NULL; 774 } 775 776 // ------------------------------------- 777 778 UBool U_EXPORT2 779 Collator::unregister(URegistryKey key, UErrorCode& status) 780 { 781 if (U_SUCCESS(status)) { 782 if (hasService()) { 783 return gService->unregister(key, status); 784 } 785 status = U_ILLEGAL_ARGUMENT_ERROR; 786 } 787 return FALSE; 788 } 789 #endif /* UCONFIG_NO_SERVICE */ 790 791 class CollationLocaleListEnumeration : public StringEnumeration { 792 private: 793 int32_t index; 794 public: 795 static UClassID U_EXPORT2 getStaticClassID(void); 796 virtual UClassID getDynamicClassID(void) const; 797 public: 798 CollationLocaleListEnumeration() 799 : index(0) 800 { 801 // The global variables should already be initialized. 802 //isAvailableLocaleListInitialized(status); 803 } 804 805 virtual ~CollationLocaleListEnumeration(); 806 807 virtual StringEnumeration * clone() const 808 { 809 CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration(); 810 if (result) { 811 result->index = index; 812 } 813 return result; 814 } 815 816 virtual int32_t count(UErrorCode &/*status*/) const { 817 return availableLocaleListCount; 818 } 819 820 virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) { 821 const char* result; 822 if(index < availableLocaleListCount) { 823 result = availableLocaleList[index++].getName(); 824 if(resultLength != NULL) { 825 *resultLength = (int32_t)uprv_strlen(result); 826 } 827 } else { 828 if(resultLength != NULL) { 829 *resultLength = 0; 830 } 831 result = NULL; 832 } 833 return result; 834 } 835 836 virtual const UnicodeString* snext(UErrorCode& status) { 837 int32_t resultLength = 0; 838 const char *s = next(&resultLength, status); 839 return setChars(s, resultLength, status); 840 } 841 842 virtual void reset(UErrorCode& /*status*/) { 843 index = 0; 844 } 845 }; 846 847 CollationLocaleListEnumeration::~CollationLocaleListEnumeration() {} 848 849 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration) 850 851 852 // ------------------------------------- 853 854 StringEnumeration* U_EXPORT2 855 Collator::getAvailableLocales(void) 856 { 857 #if !UCONFIG_NO_SERVICE 858 if (hasService()) { 859 return getService()->getAvailableLocales(); 860 } 861 #endif /* UCONFIG_NO_SERVICE */ 862 UErrorCode status = U_ZERO_ERROR; 863 if (isAvailableLocaleListInitialized(status)) { 864 return new CollationLocaleListEnumeration(); 865 } 866 return NULL; 867 } 868 869 StringEnumeration* U_EXPORT2 870 Collator::getKeywords(UErrorCode& status) { 871 // This is a wrapper over ucol_getKeywords 872 UEnumeration* uenum = ucol_getKeywords(&status); 873 if (U_FAILURE(status)) { 874 uenum_close(uenum); 875 return NULL; 876 } 877 return new UStringEnumeration(uenum); 878 } 879 880 StringEnumeration* U_EXPORT2 881 Collator::getKeywordValues(const char *keyword, UErrorCode& status) { 882 // This is a wrapper over ucol_getKeywordValues 883 UEnumeration* uenum = ucol_getKeywordValues(keyword, &status); 884 if (U_FAILURE(status)) { 885 uenum_close(uenum); 886 return NULL; 887 } 888 return new UStringEnumeration(uenum); 889 } 890 891 StringEnumeration* U_EXPORT2 892 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale, 893 UBool commonlyUsed, UErrorCode& status) { 894 // This is a wrapper over ucol_getKeywordValuesForLocale 895 UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(), 896 commonlyUsed, &status); 897 if (U_FAILURE(status)) { 898 uenum_close(uenum); 899 return NULL; 900 } 901 return new UStringEnumeration(uenum); 902 } 903 904 Locale U_EXPORT2 905 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale, 906 UBool& isAvailable, UErrorCode& status) { 907 // This is a wrapper over ucol_getFunctionalEquivalent 908 char loc[ULOC_FULLNAME_CAPACITY]; 909 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc), 910 keyword, locale.getName(), &isAvailable, &status); 911 if (U_FAILURE(status)) { 912 *loc = 0; // root 913 } 914 return Locale::createFromName(loc); 915 } 916 917 Collator::ECollationStrength 918 Collator::getStrength(void) const { 919 UErrorCode intStatus = U_ZERO_ERROR; 920 return (ECollationStrength)getAttribute(UCOL_STRENGTH, intStatus); 921 } 922 923 void 924 Collator::setStrength(ECollationStrength newStrength) { 925 UErrorCode intStatus = U_ZERO_ERROR; 926 setAttribute(UCOL_STRENGTH, (UColAttributeValue)newStrength, intStatus); 927 } 928 929 Collator & 930 Collator::setMaxVariable(UColReorderCode /*group*/, UErrorCode &errorCode) { 931 if (U_SUCCESS(errorCode)) { 932 errorCode = U_UNSUPPORTED_ERROR; 933 } 934 return *this; 935 } 936 937 UColReorderCode 938 Collator::getMaxVariable() const { 939 return UCOL_REORDER_CODE_PUNCTUATION; 940 } 941 942 int32_t 943 Collator::getReorderCodes(int32_t* /* dest*/, 944 int32_t /* destCapacity*/, 945 UErrorCode& status) const 946 { 947 if (U_SUCCESS(status)) { 948 status = U_UNSUPPORTED_ERROR; 949 } 950 return 0; 951 } 952 953 void 954 Collator::setReorderCodes(const int32_t* /* reorderCodes */, 955 int32_t /* reorderCodesLength */, 956 UErrorCode& status) 957 { 958 if (U_SUCCESS(status)) { 959 status = U_UNSUPPORTED_ERROR; 960 } 961 } 962 963 int32_t 964 Collator::getEquivalentReorderCodes(int32_t reorderCode, 965 int32_t *dest, int32_t capacity, 966 UErrorCode &errorCode) { 967 if(U_FAILURE(errorCode)) { return 0; } 968 if(capacity < 0 || (dest == NULL && capacity > 0)) { 969 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 970 return 0; 971 } 972 const CollationData *baseData = CollationRoot::getData(errorCode); 973 if(U_FAILURE(errorCode)) { return 0; } 974 return baseData->getEquivalentScripts(reorderCode, dest, capacity, errorCode); 975 } 976 977 int32_t 978 Collator::internalGetShortDefinitionString(const char * /*locale*/, 979 char * /*buffer*/, 980 int32_t /*capacity*/, 981 UErrorCode &status) const { 982 if(U_SUCCESS(status)) { 983 status = U_UNSUPPORTED_ERROR; /* Shouldn't happen, internal function */ 984 } 985 return 0; 986 } 987 988 UCollationResult 989 Collator::internalCompareUTF8(const char *left, int32_t leftLength, 990 const char *right, int32_t rightLength, 991 UErrorCode &errorCode) const { 992 if(U_FAILURE(errorCode)) { return UCOL_EQUAL; } 993 if((left == NULL && leftLength != 0) || (right == NULL && rightLength != 0)) { 994 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 995 return UCOL_EQUAL; 996 } 997 return compareUTF8( 998 StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength), 999 StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength), 1000 errorCode); 1001 } 1002 1003 int32_t 1004 Collator::internalNextSortKeyPart(UCharIterator * /*iter*/, uint32_t /*state*/[2], 1005 uint8_t * /*dest*/, int32_t /*count*/, UErrorCode &errorCode) const { 1006 if (U_SUCCESS(errorCode)) { 1007 errorCode = U_UNSUPPORTED_ERROR; 1008 } 1009 return 0; 1010 } 1011 1012 // UCollator private data members ---------------------------------------- 1013 1014 /* This is useless information */ 1015 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/ 1016 1017 // ------------------------------------- 1018 1019 U_NAMESPACE_END 1020 1021 #endif /* #if !UCONFIG_NO_COLLATION */ 1022 1023 /* eof */ 1024