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