OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ****************************************************************************** |
| 3 * Copyright (C) 1996-2010, 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 impleme
nt |
| 20 * a Collation cache. Modified createDefault to look i
n |
| 21 * cache first, and also to store newly created Collati
on |
| 22 * objects in the cache. Modified to not use gLocPath. |
| 23 * 2/12/97 aliu Modified to create objects from RuleBasedCollator ca
che. |
| 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 */ |
| 39 |
| 40 #include "unicode/utypes.h" |
| 41 |
| 42 #if !UCONFIG_NO_COLLATION |
| 43 |
| 44 #include "unicode/coll.h" |
| 45 #include "unicode/tblcoll.h" |
| 46 #include "ucol_imp.h" |
| 47 #include "cstring.h" |
| 48 #include "cmemory.h" |
| 49 #include "umutex.h" |
| 50 #include "servloc.h" |
| 51 #include "ustrenum.h" |
| 52 #include "uresimp.h" |
| 53 #include "ucln_in.h" |
| 54 |
| 55 static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL; |
| 56 static int32_t availableLocaleListCount; |
| 57 static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL; |
| 58 |
| 59 /** |
| 60 * Release all static memory held by collator. |
| 61 */ |
| 62 U_CDECL_BEGIN |
| 63 static UBool U_CALLCONV collator_cleanup(void) { |
| 64 #if !UCONFIG_NO_SERVICE |
| 65 if (gService) { |
| 66 delete gService; |
| 67 gService = NULL; |
| 68 } |
| 69 #endif |
| 70 if (availableLocaleList) { |
| 71 delete []availableLocaleList; |
| 72 availableLocaleList = NULL; |
| 73 } |
| 74 availableLocaleListCount = 0; |
| 75 |
| 76 return TRUE; |
| 77 } |
| 78 |
| 79 U_CDECL_END |
| 80 |
| 81 U_NAMESPACE_BEGIN |
| 82 |
| 83 #if !UCONFIG_NO_SERVICE |
| 84 |
| 85 // ------------------------------------------ |
| 86 // |
| 87 // Registration |
| 88 // |
| 89 |
| 90 //------------------------------------------- |
| 91 |
| 92 CollatorFactory::~CollatorFactory() {} |
| 93 |
| 94 //------------------------------------------- |
| 95 |
| 96 UBool |
| 97 CollatorFactory::visible(void) const { |
| 98 return TRUE; |
| 99 } |
| 100 |
| 101 //------------------------------------------- |
| 102 |
| 103 UnicodeString& |
| 104 CollatorFactory::getDisplayName(const Locale& objectLocale, |
| 105 const Locale& displayLocale, |
| 106 UnicodeString& result) |
| 107 { |
| 108 return objectLocale.getDisplayName(displayLocale, result); |
| 109 } |
| 110 |
| 111 // ------------------------------------- |
| 112 |
| 113 class ICUCollatorFactory : public ICUResourceBundleFactory { |
| 114 public: |
| 115 ICUCollatorFactory(): ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL
, -1, US_INV)) { } |
| 116 protected: |
| 117 virtual UObject* create(const ICUServiceKey& key, const ICUService* service,
UErrorCode& status) const; |
| 118 }; |
| 119 |
| 120 UObject* |
| 121 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* servic
e */, UErrorCode& status) const { |
| 122 if (handlesKey(key, status)) { |
| 123 const LocaleKey& lkey = (const LocaleKey&)key; |
| 124 Locale loc; |
| 125 // make sure the requested locale is correct |
| 126 // default LocaleFactory uses currentLocale since that's the one vetted
by handlesKey |
| 127 // but for ICU rb resources we use the actual one since it will fallback
again |
| 128 lkey.canonicalLocale(loc); |
| 129 |
| 130 return Collator::makeInstance(loc, status); |
| 131 } |
| 132 return NULL; |
| 133 } |
| 134 |
| 135 // ------------------------------------- |
| 136 |
| 137 class ICUCollatorService : public ICULocaleService { |
| 138 public: |
| 139 ICUCollatorService() |
| 140 : ICULocaleService(UNICODE_STRING_SIMPLE("Collator")) |
| 141 { |
| 142 UErrorCode status = U_ZERO_ERROR; |
| 143 registerFactory(new ICUCollatorFactory(), status); |
| 144 } |
| 145 |
| 146 virtual UObject* cloneInstance(UObject* instance) const { |
| 147 return ((Collator*)instance)->clone(); |
| 148 } |
| 149 |
| 150 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actu
alID, UErrorCode& status) const { |
| 151 LocaleKey& lkey = (LocaleKey&)key; |
| 152 if (actualID) { |
| 153 // Ugly Hack Alert! We return an empty actualID to signal |
| 154 // to callers that this is a default object, not a "real" |
| 155 // service-created object. (TODO remove in 3.0) [aliu] |
| 156 actualID->truncate(0); |
| 157 } |
| 158 Locale loc(""); |
| 159 lkey.canonicalLocale(loc); |
| 160 return Collator::makeInstance(loc, status); |
| 161 } |
| 162 |
| 163 virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UEr
rorCode& status) const { |
| 164 UnicodeString ar; |
| 165 if (actualReturn == NULL) { |
| 166 actualReturn = &ar; |
| 167 } |
| 168 Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn
, status); |
| 169 // Ugly Hack Alert! If the actualReturn length is zero, this |
| 170 // means we got a default object, not a "real" service-created |
| 171 // object. We don't call setLocales() on a default object, |
| 172 // because that will overwrite its correct built-in locale |
| 173 // metadata (valid & actual) with our incorrect data (all we |
| 174 // have is the requested locale). (TODO remove in 3.0) [aliu] |
| 175 if (result && actualReturn->length() > 0) { |
| 176 const LocaleKey& lkey = (const LocaleKey&)key; |
| 177 Locale canonicalLocale(""); |
| 178 Locale currentLocale(""); |
| 179 |
| 180 LocaleUtility::initLocaleFromName(*actualReturn, currentLocale); |
| 181 result->setLocales(lkey.canonicalLocale(canonicalLocale), currentLoc
ale, currentLocale); |
| 182 } |
| 183 return result; |
| 184 } |
| 185 |
| 186 virtual UBool isDefault() const { |
| 187 return countFactories() == 1; |
| 188 } |
| 189 }; |
| 190 |
| 191 // ------------------------------------- |
| 192 |
| 193 static ICULocaleService* |
| 194 getService(void) |
| 195 { |
| 196 UBool needInit; |
| 197 UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit); |
| 198 if(needInit) { |
| 199 ICULocaleService *newservice = new ICUCollatorService(); |
| 200 if(newservice) { |
| 201 umtx_lock(NULL); |
| 202 if(gService == NULL) { |
| 203 gService = newservice; |
| 204 newservice = NULL; |
| 205 } |
| 206 umtx_unlock(NULL); |
| 207 } |
| 208 if(newservice) { |
| 209 delete newservice; |
| 210 } |
| 211 else { |
| 212 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); |
| 213 } |
| 214 } |
| 215 return gService; |
| 216 } |
| 217 |
| 218 // ------------------------------------- |
| 219 |
| 220 static inline UBool |
| 221 hasService(void) |
| 222 { |
| 223 UBool retVal; |
| 224 UMTX_CHECK(NULL, gService != NULL, retVal); |
| 225 return retVal; |
| 226 } |
| 227 |
| 228 // ------------------------------------- |
| 229 |
| 230 UCollator* |
| 231 Collator::createUCollator(const char *loc, |
| 232 UErrorCode *status) |
| 233 { |
| 234 UCollator *result = 0; |
| 235 if (status && U_SUCCESS(*status) && hasService()) { |
| 236 Locale desiredLocale(loc); |
| 237 Collator *col = (Collator*)gService->get(desiredLocale, *status); |
| 238 RuleBasedCollator *rbc; |
| 239 if (col && (rbc = dynamic_cast<RuleBasedCollator *>(col))) { |
| 240 if (!rbc->dataIsOwned) { |
| 241 result = ucol_safeClone(rbc->ucollator, NULL, NULL, status); |
| 242 } else { |
| 243 result = rbc->ucollator; |
| 244 rbc->ucollator = NULL; // to prevent free on delete |
| 245 } |
| 246 } |
| 247 delete col; |
| 248 } |
| 249 return result; |
| 250 } |
| 251 #endif /* UCONFIG_NO_SERVICE */ |
| 252 |
| 253 static UBool isAvailableLocaleListInitialized(UErrorCode &status) { |
| 254 // for now, there is a hardcoded list, so just walk through that list and se
t it up. |
| 255 UBool needInit; |
| 256 UMTX_CHECK(NULL, availableLocaleList == NULL, needInit); |
| 257 |
| 258 if (needInit) { |
| 259 UResourceBundle *index = NULL; |
| 260 UResourceBundle installed; |
| 261 Locale * temp; |
| 262 int32_t i = 0; |
| 263 int32_t localeCount; |
| 264 |
| 265 ures_initStackObject(&installed); |
| 266 index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status); |
| 267 ures_getByKey(index, "InstalledLocales", &installed, &status); |
| 268 |
| 269 if(U_SUCCESS(status)) { |
| 270 localeCount = ures_getSize(&installed); |
| 271 temp = new Locale[localeCount]; |
| 272 |
| 273 if (temp != NULL) { |
| 274 ures_resetIterator(&installed); |
| 275 while(ures_hasNext(&installed)) { |
| 276 const char *tempKey = NULL; |
| 277 ures_getNextString(&installed, NULL, &tempKey, &status); |
| 278 temp[i++] = Locale(tempKey); |
| 279 } |
| 280 |
| 281 umtx_lock(NULL); |
| 282 if (availableLocaleList == NULL) |
| 283 { |
| 284 availableLocaleListCount = localeCount; |
| 285 availableLocaleList = temp; |
| 286 temp = NULL; |
| 287 ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_clean
up); |
| 288 } |
| 289 umtx_unlock(NULL); |
| 290 |
| 291 needInit = FALSE; |
| 292 if (temp) { |
| 293 delete []temp; |
| 294 } |
| 295 } |
| 296 |
| 297 ures_close(&installed); |
| 298 } |
| 299 ures_close(index); |
| 300 } |
| 301 return !needInit; |
| 302 } |
| 303 |
| 304 // Collator public methods ----------------------------------------------- |
| 305 |
| 306 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success) |
| 307 { |
| 308 return createInstance(Locale::getDefault(), success); |
| 309 } |
| 310 |
| 311 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale, |
| 312 UErrorCode& status) |
| 313 { |
| 314 if (U_FAILURE(status)) |
| 315 return 0; |
| 316 |
| 317 #if !UCONFIG_NO_SERVICE |
| 318 if (hasService()) { |
| 319 Locale actualLoc; |
| 320 Collator *result = |
| 321 (Collator*)gService->get(desiredLocale, &actualLoc, status); |
| 322 // Ugly Hack Alert! If the returned locale is empty (not root, |
| 323 // but empty -- getName() == "") then that means the service |
| 324 // returned a default object, not a "real" service object. In |
| 325 // that case, the locale metadata (valid & actual) is setup |
| 326 // correctly already, and we don't want to overwrite it. (TODO |
| 327 // remove in 3.0) [aliu] |
| 328 if (*actualLoc.getName() != 0) { |
| 329 result->setLocales(desiredLocale, actualLoc, actualLoc); |
| 330 } |
| 331 return result; |
| 332 } |
| 333 #endif |
| 334 return makeInstance(desiredLocale, status); |
| 335 } |
| 336 |
| 337 |
| 338 Collator* Collator::makeInstance(const Locale& desiredLocale, |
| 339 UErrorCode& status) |
| 340 { |
| 341 // A bit of explanation is required here. Although in the current |
| 342 // implementation |
| 343 // Collator::createInstance() is just turning around and calling |
| 344 // RuleBasedCollator(Locale&), this will not necessarily always be the |
| 345 // case. For example, suppose we modify this code to handle a |
| 346 // non-table-based Collator, such as that for Thai. In this case, |
| 347 // createInstance() will have to be modified to somehow determine this fact |
| 348 // (perhaps a field in the resource bundle). Then it can construct the |
| 349 // non-table-based Collator in some other way, when it sees that it needs |
| 350 // to. |
| 351 // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS |
| 352 // return a valid collation object, if the system is functioning properly. |
| 353 // The reason is that it will fall back, use the default locale, and even |
| 354 // use the built-in default collation rules. THEREFORE, createInstance() |
| 355 // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN |
| 356 // ADVANCE that the given locale's collation is properly implemented as a |
| 357 // RuleBasedCollator. |
| 358 // Currently, we don't do this...we always return a RuleBasedCollator, |
| 359 // whether it is strictly correct to do so or not, without checking, because
|
| 360 // we currently have no way of checking. |
| 361 |
| 362 RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale, |
| 363 status); |
| 364 /* test for NULL */ |
| 365 if (collation == 0) { |
| 366 status = U_MEMORY_ALLOCATION_ERROR; |
| 367 return 0; |
| 368 } |
| 369 if (U_FAILURE(status)) |
| 370 { |
| 371 delete collation; |
| 372 collation = 0; |
| 373 } |
| 374 return collation; |
| 375 } |
| 376 |
| 377 #ifdef U_USE_COLLATION_OBSOLETE_2_6 |
| 378 // !!! dlf the following is obsolete, ignore registration for this |
| 379 |
| 380 Collator * |
| 381 Collator::createInstance(const Locale &loc, |
| 382 UVersionInfo version, |
| 383 UErrorCode &status) |
| 384 { |
| 385 Collator *collator; |
| 386 UVersionInfo info; |
| 387 |
| 388 collator=new RuleBasedCollator(loc, status); |
| 389 /* test for NULL */ |
| 390 if (collator == 0) { |
| 391 status = U_MEMORY_ALLOCATION_ERROR; |
| 392 return 0; |
| 393 } |
| 394 |
| 395 if(U_SUCCESS(status)) { |
| 396 collator->getVersion(info); |
| 397 if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) { |
| 398 delete collator; |
| 399 status=U_MISSING_RESOURCE_ERROR; |
| 400 return 0; |
| 401 } |
| 402 } |
| 403 return collator; |
| 404 } |
| 405 #endif |
| 406 |
| 407 // implement deprecated, previously abstract method |
| 408 Collator::EComparisonResult Collator::compare(const UnicodeString& source, |
| 409 const UnicodeString& target) const |
| 410 { |
| 411 UErrorCode ec = U_ZERO_ERROR; |
| 412 return (Collator::EComparisonResult)compare(source, target, ec); |
| 413 } |
| 414 |
| 415 // implement deprecated, previously abstract method |
| 416 Collator::EComparisonResult Collator::compare(const UnicodeString& source, |
| 417 const UnicodeString& target, |
| 418 int32_t length) const |
| 419 { |
| 420 UErrorCode ec = U_ZERO_ERROR; |
| 421 return (Collator::EComparisonResult)compare(source, target, length, ec); |
| 422 } |
| 423 |
| 424 // implement deprecated, previously abstract method |
| 425 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourc
eLength, |
| 426 const UChar* target, int32_t targetLength) |
| 427 const |
| 428 { |
| 429 UErrorCode ec = U_ZERO_ERROR; |
| 430 return (Collator::EComparisonResult)compare(source, sourceLength, target, ta
rgetLength, ec); |
| 431 } |
| 432 |
| 433 UCollationResult Collator::compare(UCharIterator &/*sIter*/, |
| 434 UCharIterator &/*tIter*/, |
| 435 UErrorCode &status) const { |
| 436 if(U_SUCCESS(status)) { |
| 437 // Not implemented in the base class. |
| 438 status = U_UNSUPPORTED_ERROR; |
| 439 } |
| 440 return UCOL_EQUAL; |
| 441 } |
| 442 |
| 443 UCollationResult Collator::compareUTF8(const StringPiece &source, |
| 444 const StringPiece &target, |
| 445 UErrorCode &status) const { |
| 446 if(U_FAILURE(status)) { |
| 447 return UCOL_EQUAL; |
| 448 } |
| 449 UCharIterator sIter, tIter; |
| 450 uiter_setUTF8(&sIter, source.data(), source.length()); |
| 451 uiter_setUTF8(&tIter, target.data(), target.length()); |
| 452 return compare(sIter, tIter, status); |
| 453 } |
| 454 |
| 455 UBool Collator::equals(const UnicodeString& source, |
| 456 const UnicodeString& target) const |
| 457 { |
| 458 UErrorCode ec = U_ZERO_ERROR; |
| 459 return (compare(source, target, ec) == UCOL_EQUAL); |
| 460 } |
| 461 |
| 462 UBool Collator::greaterOrEqual(const UnicodeString& source, |
| 463 const UnicodeString& target) const |
| 464 { |
| 465 UErrorCode ec = U_ZERO_ERROR; |
| 466 return (compare(source, target, ec) != UCOL_LESS); |
| 467 } |
| 468 |
| 469 UBool Collator::greater(const UnicodeString& source, |
| 470 const UnicodeString& target) const |
| 471 { |
| 472 UErrorCode ec = U_ZERO_ERROR; |
| 473 return (compare(source, target, ec) == UCOL_GREATER); |
| 474 } |
| 475 |
| 476 // this API ignores registered collators, since it returns an |
| 477 // array of indefinite lifetime |
| 478 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count) |
| 479 { |
| 480 UErrorCode status = U_ZERO_ERROR; |
| 481 Locale *result = NULL; |
| 482 count = 0; |
| 483 if (isAvailableLocaleListInitialized(status)) |
| 484 { |
| 485 result = availableLocaleList; |
| 486 count = availableLocaleListCount; |
| 487 } |
| 488 return result; |
| 489 } |
| 490 |
| 491 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, |
| 492 const Locale& displayLocale, |
| 493 UnicodeString& name) |
| 494 { |
| 495 #if !UCONFIG_NO_SERVICE |
| 496 if (hasService()) { |
| 497 UnicodeString locNameStr; |
| 498 LocaleUtility::initNameFromLocale(objectLocale, locNameStr); |
| 499 return gService->getDisplayName(locNameStr, name, displayLocale); |
| 500 } |
| 501 #endif |
| 502 return objectLocale.getDisplayName(displayLocale, name); |
| 503 } |
| 504 |
| 505 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale, |
| 506 UnicodeString& name) |
| 507 { |
| 508 return getDisplayName(objectLocale, Locale::getDefault(), name); |
| 509 } |
| 510 |
| 511 /* This is useless information */ |
| 512 /*void Collator::getVersion(UVersionInfo versionInfo) const |
| 513 { |
| 514 if (versionInfo!=NULL) |
| 515 uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH); |
| 516 } |
| 517 */ |
| 518 |
| 519 // UCollator protected constructor destructor ---------------------------- |
| 520 |
| 521 /** |
| 522 * Default constructor. |
| 523 * Constructor is different from the old default Collator constructor. |
| 524 * The task for determing the default collation strength and normalization mode |
| 525 * is left to the child class. |
| 526 */ |
| 527 Collator::Collator() |
| 528 : UObject() |
| 529 { |
| 530 } |
| 531 |
| 532 /** |
| 533 * Constructor. |
| 534 * Empty constructor, does not handle the arguments. |
| 535 * This constructor is done for backward compatibility with 1.7 and 1.8. |
| 536 * The task for handling the argument collation strength and normalization |
| 537 * mode is left to the child class. |
| 538 * @param collationStrength collation strength |
| 539 * @param decompositionMode |
| 540 * @deprecated 2.4 use the default constructor instead |
| 541 */ |
| 542 Collator::Collator(UCollationStrength, UNormalizationMode ) |
| 543 : UObject() |
| 544 { |
| 545 } |
| 546 |
| 547 Collator::~Collator() |
| 548 { |
| 549 } |
| 550 |
| 551 Collator::Collator(const Collator &other) |
| 552 : UObject(other) |
| 553 { |
| 554 } |
| 555 |
| 556 UBool Collator::operator==(const Collator& other) const |
| 557 { |
| 558 return (UBool)(this == &other); |
| 559 } |
| 560 |
| 561 UBool Collator::operator!=(const Collator& other) const |
| 562 { |
| 563 return (UBool)!(*this == other); |
| 564 } |
| 565 |
| 566 int32_t U_EXPORT2 Collator::getBound(const uint8_t *source, |
| 567 int32_t sourceLength, |
| 568 UColBoundMode boundType, |
| 569 uint32_t noOfLevels, |
| 570 uint8_t *result, |
| 571 int32_t resultLength, |
| 572 UErrorCode &status) |
| 573 { |
| 574 return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, re
sultLength, &status); |
| 575 } |
| 576 |
| 577 void |
| 578 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* valid
Locale */, const Locale& /*actualLocale*/) { |
| 579 } |
| 580 |
| 581 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const |
| 582 { |
| 583 if(U_FAILURE(status)) { |
| 584 return NULL; |
| 585 } |
| 586 // everything can be changed |
| 587 return new UnicodeSet(0, 0x10FFFF); |
| 588 } |
| 589 |
| 590 // ------------------------------------- |
| 591 |
| 592 #if !UCONFIG_NO_SERVICE |
| 593 URegistryKey U_EXPORT2 |
| 594 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode&
status) |
| 595 { |
| 596 if (U_SUCCESS(status)) { |
| 597 return getService()->registerInstance(toAdopt, locale, status); |
| 598 } |
| 599 return NULL; |
| 600 } |
| 601 |
| 602 // ------------------------------------- |
| 603 |
| 604 class CFactory : public LocaleKeyFactory { |
| 605 private: |
| 606 CollatorFactory* _delegate; |
| 607 Hashtable* _ids; |
| 608 |
| 609 public: |
| 610 CFactory(CollatorFactory* delegate, UErrorCode& status) |
| 611 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE) |
| 612 , _delegate(delegate) |
| 613 , _ids(NULL) |
| 614 { |
| 615 if (U_SUCCESS(status)) { |
| 616 int32_t count = 0; |
| 617 _ids = new Hashtable(status); |
| 618 if (_ids) { |
| 619 const UnicodeString * idlist = _delegate->getSupportedIDs(count,
status); |
| 620 for (int i = 0; i < count; ++i) { |
| 621 _ids->put(idlist[i], (void*)this, status); |
| 622 if (U_FAILURE(status)) { |
| 623 delete _ids; |
| 624 _ids = NULL; |
| 625 return; |
| 626 } |
| 627 } |
| 628 } else { |
| 629 status = U_MEMORY_ALLOCATION_ERROR; |
| 630 } |
| 631 } |
| 632 } |
| 633 |
| 634 virtual ~CFactory() |
| 635 { |
| 636 delete _delegate; |
| 637 delete _ids; |
| 638 } |
| 639 |
| 640 virtual UObject* create(const ICUServiceKey& key, const ICUService* service,
UErrorCode& status) const; |
| 641 |
| 642 protected: |
| 643 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const |
| 644 { |
| 645 if (U_SUCCESS(status)) { |
| 646 return _ids; |
| 647 } |
| 648 return NULL; |
| 649 } |
| 650 |
| 651 virtual UnicodeString& |
| 652 getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeStr
ing& result) const; |
| 653 }; |
| 654 |
| 655 UObject* |
| 656 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErr
orCode& status) const |
| 657 { |
| 658 if (handlesKey(key, status)) { |
| 659 const LocaleKey& lkey = (const LocaleKey&)key; |
| 660 Locale validLoc; |
| 661 lkey.currentLocale(validLoc); |
| 662 return _delegate->createCollator(validLoc); |
| 663 } |
| 664 return NULL; |
| 665 } |
| 666 |
| 667 UnicodeString& |
| 668 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeS
tring& result) const |
| 669 { |
| 670 if ((_coverage & 0x1) == 0) { |
| 671 UErrorCode status = U_ZERO_ERROR; |
| 672 const Hashtable* ids = getSupportedIDs(status); |
| 673 if (ids && (ids->get(id) != NULL)) { |
| 674 Locale loc; |
| 675 LocaleUtility::initLocaleFromName(id, loc); |
| 676 return _delegate->getDisplayName(loc, locale, result); |
| 677 } |
| 678 } |
| 679 result.setToBogus(); |
| 680 return result; |
| 681 } |
| 682 |
| 683 URegistryKey U_EXPORT2 |
| 684 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status) |
| 685 { |
| 686 if (U_SUCCESS(status)) { |
| 687 CFactory* f = new CFactory(toAdopt, status); |
| 688 if (f) { |
| 689 return getService()->registerFactory(f, status); |
| 690 } |
| 691 status = U_MEMORY_ALLOCATION_ERROR; |
| 692 } |
| 693 return NULL; |
| 694 } |
| 695 |
| 696 // ------------------------------------- |
| 697 |
| 698 UBool U_EXPORT2 |
| 699 Collator::unregister(URegistryKey key, UErrorCode& status) |
| 700 { |
| 701 if (U_SUCCESS(status)) { |
| 702 if (hasService()) { |
| 703 return gService->unregister(key, status); |
| 704 } |
| 705 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 706 } |
| 707 return FALSE; |
| 708 } |
| 709 #endif /* UCONFIG_NO_SERVICE */ |
| 710 |
| 711 class CollationLocaleListEnumeration : public StringEnumeration { |
| 712 private: |
| 713 int32_t index; |
| 714 public: |
| 715 static UClassID U_EXPORT2 getStaticClassID(void); |
| 716 virtual UClassID getDynamicClassID(void) const; |
| 717 public: |
| 718 CollationLocaleListEnumeration() |
| 719 : index(0) |
| 720 { |
| 721 // The global variables should already be initialized. |
| 722 //isAvailableLocaleListInitialized(status); |
| 723 } |
| 724 |
| 725 virtual ~CollationLocaleListEnumeration() { |
| 726 } |
| 727 |
| 728 virtual StringEnumeration * clone() const |
| 729 { |
| 730 CollationLocaleListEnumeration *result = new CollationLocaleListEnumerat
ion(); |
| 731 if (result) { |
| 732 result->index = index; |
| 733 } |
| 734 return result; |
| 735 } |
| 736 |
| 737 virtual int32_t count(UErrorCode &/*status*/) const { |
| 738 return availableLocaleListCount; |
| 739 } |
| 740 |
| 741 virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) { |
| 742 const char* result; |
| 743 if(index < availableLocaleListCount) { |
| 744 result = availableLocaleList[index++].getName(); |
| 745 if(resultLength != NULL) { |
| 746 *resultLength = (int32_t)uprv_strlen(result); |
| 747 } |
| 748 } else { |
| 749 if(resultLength != NULL) { |
| 750 *resultLength = 0; |
| 751 } |
| 752 result = NULL; |
| 753 } |
| 754 return result; |
| 755 } |
| 756 |
| 757 virtual const UnicodeString* snext(UErrorCode& status) { |
| 758 int32_t resultLength = 0; |
| 759 const char *s = next(&resultLength, status); |
| 760 return setChars(s, resultLength, status); |
| 761 } |
| 762 |
| 763 virtual void reset(UErrorCode& /*status*/) { |
| 764 index = 0; |
| 765 } |
| 766 }; |
| 767 |
| 768 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration) |
| 769 |
| 770 |
| 771 // ------------------------------------- |
| 772 |
| 773 StringEnumeration* U_EXPORT2 |
| 774 Collator::getAvailableLocales(void) |
| 775 { |
| 776 #if !UCONFIG_NO_SERVICE |
| 777 if (hasService()) { |
| 778 return getService()->getAvailableLocales(); |
| 779 } |
| 780 #endif /* UCONFIG_NO_SERVICE */ |
| 781 UErrorCode status = U_ZERO_ERROR; |
| 782 if (isAvailableLocaleListInitialized(status)) { |
| 783 return new CollationLocaleListEnumeration(); |
| 784 } |
| 785 return NULL; |
| 786 } |
| 787 |
| 788 StringEnumeration* U_EXPORT2 |
| 789 Collator::getKeywords(UErrorCode& status) { |
| 790 // This is a wrapper over ucol_getKeywords |
| 791 UEnumeration* uenum = ucol_getKeywords(&status); |
| 792 if (U_FAILURE(status)) { |
| 793 uenum_close(uenum); |
| 794 return NULL; |
| 795 } |
| 796 return new UStringEnumeration(uenum); |
| 797 } |
| 798 |
| 799 StringEnumeration* U_EXPORT2 |
| 800 Collator::getKeywordValues(const char *keyword, UErrorCode& status) { |
| 801 // This is a wrapper over ucol_getKeywordValues |
| 802 UEnumeration* uenum = ucol_getKeywordValues(keyword, &status); |
| 803 if (U_FAILURE(status)) { |
| 804 uenum_close(uenum); |
| 805 return NULL; |
| 806 } |
| 807 return new UStringEnumeration(uenum); |
| 808 } |
| 809 |
| 810 StringEnumeration* U_EXPORT2 |
| 811 Collator::getKeywordValuesForLocale(const char* key, const Locale& locale, |
| 812 UBool commonlyUsed, UErrorCode& status) { |
| 813 // This is a wrapper over ucol_getKeywordValuesForLocale |
| 814 UEnumeration *uenum = ucol_getKeywordValuesForLocale(key, locale.getName(), |
| 815 commonlyUsed, &status); |
| 816 if (U_FAILURE(status)) { |
| 817 uenum_close(uenum); |
| 818 return NULL; |
| 819 } |
| 820 return new UStringEnumeration(uenum); |
| 821 } |
| 822 |
| 823 Locale U_EXPORT2 |
| 824 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale, |
| 825 UBool& isAvailable, UErrorCode& status) { |
| 826 // This is a wrapper over ucol_getFunctionalEquivalent |
| 827 char loc[ULOC_FULLNAME_CAPACITY]; |
| 828 /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc), |
| 829 keyword, locale.getName(), &isAvailable, &status); |
| 830 if (U_FAILURE(status)) { |
| 831 *loc = 0; // root |
| 832 } |
| 833 return Locale::createFromName(loc); |
| 834 } |
| 835 |
| 836 int32_t Collator::getReorderCodes(int32_t *dest, |
| 837 int32_t destCapacity, |
| 838 UErrorCode& status) const |
| 839 { |
| 840 if (U_SUCCESS(status)) { |
| 841 status = U_UNSUPPORTED_ERROR; |
| 842 } |
| 843 return 0; |
| 844 } |
| 845 |
| 846 void Collator::setReorderCodes(const int32_t *reorderCodes, |
| 847 int32_t reorderCodesLength, |
| 848 UErrorCode& status) |
| 849 { |
| 850 if (U_SUCCESS(status)) { |
| 851 status = U_UNSUPPORTED_ERROR; |
| 852 } |
| 853 } |
| 854 |
| 855 // UCollator private data members ---------------------------------------- |
| 856 |
| 857 /* This is useless information */ |
| 858 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/ |
| 859 |
| 860 // ------------------------------------- |
| 861 |
| 862 U_NAMESPACE_END |
| 863 |
| 864 #endif /* #if !UCONFIG_NO_COLLATION */ |
| 865 |
| 866 /* eof */ |
OLD | NEW |