]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/iculserv.cpp
ICU-6.2.4.tar.gz
[apple/icu.git] / icuSources / common / iculserv.cpp
1 /**
2 *******************************************************************************
3 * Copyright (C) 2001-2004, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
6 *
7 *******************************************************************************
8 */
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_SERVICE
12
13 #include "unicode/resbund.h"
14 #include "uresimp.h"
15 #include "cmemory.h"
16 #include "iculserv.h"
17 #include "ustrfmt.h"
18 #include "uhash.h"
19 #include "charstr.h"
20 #include "ucln_cmn.h"
21 #include "uassert.h"
22
23 // see LocaleUtility::getAvailableLocaleNames
24 static Hashtable * LocaleUtility_cache = NULL;
25
26 #define UNDERSCORE_CHAR ((UChar)0x005f)
27 #define AT_SIGN_CHAR ((UChar)64)
28 #define PERIOD_CHAR ((UChar)46)
29
30 /*
31 ******************************************************************
32 */
33
34 /**
35 * Release all static memory held by Locale Utility.
36 */
37 U_CDECL_BEGIN
38 static UBool U_CALLCONV service_cleanup(void) {
39 if (LocaleUtility_cache) {
40 delete LocaleUtility_cache;
41 LocaleUtility_cache = NULL;
42 }
43 return TRUE;
44 }
45 U_CDECL_END
46
47 U_NAMESPACE_BEGIN
48
49 UnicodeString&
50 LocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& result)
51 {
52 if (id == NULL) {
53 result.setToBogus();
54 } else {
55 // Fix case only (no other changes) up to the first '@' or '.' or
56 // end of string, whichever comes first. In 3.0 I changed this to
57 // stop at first '@' or '.'. It used to run out to the end of
58 // string. My fix makes the tests pass but is probably
59 // structurally incorrect. See below. [alan 3.0]
60
61 // TODO: Doug, you might want to revise this...
62 result = *id;
63 int32_t i = 0;
64 int32_t end = result.indexOf(AT_SIGN_CHAR);
65 int32_t n = result.indexOf(PERIOD_CHAR);
66 if (n >= 0 && n < end) {
67 end = n;
68 }
69 if (end < 0) {
70 end = result.length();
71 }
72 n = result.indexOf(UNDERSCORE_CHAR);
73 if (n < 0) {
74 n = end;
75 }
76 for (; i < n; ++i) {
77 UChar c = result.charAt(i);
78 if (c >= 0x0041 && c <= 0x005a) {
79 c += 0x20;
80 result.setCharAt(i, c);
81 }
82 }
83 for (n = end; i < n; ++i) {
84 UChar c = result.charAt(i);
85 if (c >= 0x0061 && c <= 0x007a) {
86 c -= 0x20;
87 result.setCharAt(i, c);
88 }
89 }
90 }
91 return result;
92
93 #if 0
94 // This code does a proper full level 2 canonicalization of id.
95 // It's nasty to go from UChar to char to char to UChar -- but
96 // that's what you have to do to use the uloc_canonicalize
97 // function on UnicodeStrings.
98
99 // I ended up doing the alternate fix (see above) not for
100 // performance reasons, although performance will certainly be
101 // better, but because doing a full level 2 canonicalization
102 // causes some tests to fail. [alan 3.0]
103
104 // TODO: Doug, you might want to revisit this...
105 result.setToBogus();
106 if (id != 0) {
107 int32_t buflen = id->length() + 8; // space for NUL
108 char* buf = (char*) uprv_malloc(buflen);
109 char* canon = (buf == 0) ? 0 : (char*) uprv_malloc(buflen);
110 if (buf != 0 && canon != 0) {
111 U_ASSERT(id->extract(0, INT32_MAX, buf, buflen) < buflen);
112 UErrorCode ec = U_ZERO_ERROR;
113 uloc_canonicalize(buf, canon, buflen, &ec);
114 if (U_SUCCESS(ec)) {
115 result = UnicodeString(canon);
116 }
117 }
118 uprv_free(buf);
119 uprv_free(canon);
120 }
121 return result;
122 #endif
123 }
124
125 Locale&
126 LocaleUtility::initLocaleFromName(const UnicodeString& id, Locale& result)
127 {
128 enum { BUFLEN = 128 }; // larger than ever needed
129
130 if (id.isBogus() || id.length() >= BUFLEN) {
131 result.setToBogus();
132 } else {
133 /*
134 * We need to convert from a UnicodeString to char * in order to
135 * create a Locale.
136 *
137 * Problem: Locale ID strings may contain '@' which is a variant
138 * character and cannot be handled by invariant-character conversion.
139 *
140 * Hack: Since ICU code can handle locale IDs with multiple encodings
141 * of '@' (at least for EBCDIC; it's not known to be a problem for
142 * ASCII-based systems),
143 * we use regular invariant-character conversion for everything else
144 * and manually convert U+0040 into a compiler-char-constant '@'.
145 * While this compilation-time constant may not match the runtime
146 * encoding of '@', it should be one of the encodings which ICU
147 * recognizes.
148 *
149 * There should be only at most one '@' in a locale ID.
150 */
151 char buffer[BUFLEN];
152 int32_t prev, i;
153 prev = 0;
154 for(;;) {
155 i = id.indexOf((UChar)0x40, prev);
156 if(i < 0) {
157 // no @ between prev and the rest of the string
158 id.extract(prev, INT32_MAX, buffer + prev, BUFLEN - prev, US_INV);
159 break; // done
160 } else {
161 // normal invariant-character conversion for text between @s
162 id.extract(prev, i - prev, buffer + prev, BUFLEN - prev, US_INV);
163 // manually "convert" U+0040 at id[i] into '@' at buffer[i]
164 buffer[i] = '@';
165 prev = i + 1;
166 }
167 }
168 result = Locale::createFromName(buffer);
169 }
170 return result;
171 }
172
173 UnicodeString&
174 LocaleUtility::initNameFromLocale(const Locale& locale, UnicodeString& result)
175 {
176 if (locale.isBogus()) {
177 result.setToBogus();
178 } else {
179 result.append(UnicodeString(locale.getName(), -1, US_INV));
180 }
181 return result;
182 }
183
184 const Hashtable*
185 LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
186 {
187 // LocaleUtility_cache is a hash-of-hashes. The top-level keys
188 // are path strings ('bundleID') passed to
189 // ures_openAvailableLocales. The top-level values are
190 // second-level hashes. The second-level keys are result strings
191 // from ures_openAvailableLocales. The second-level values are
192 // garbage ((void*)1 or other random pointer).
193
194 UErrorCode status = U_ZERO_ERROR;
195 Hashtable* cache;
196 umtx_lock(NULL);
197 cache = LocaleUtility_cache;
198 umtx_unlock(NULL);
199
200 if (cache == NULL) {
201 cache = new Hashtable(status);
202 if (cache == NULL || U_FAILURE(status)) {
203 return NULL; // catastrophic failure; e.g. out of memory
204 }
205 cache->setValueDeleter(uhash_deleteHashtable);
206 Hashtable* h; // set this to final LocaleUtility_cache value
207 umtx_lock(NULL);
208 h = LocaleUtility_cache;
209 if (h == NULL) {
210 LocaleUtility_cache = h = cache;
211 cache = NULL;
212 ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup);
213 }
214 umtx_unlock(NULL);
215 delete cache;
216 cache = h;
217 }
218
219 U_ASSERT(cache != NULL);
220
221 Hashtable* htp;
222 umtx_lock(NULL);
223 htp = (Hashtable*) cache->get(bundleID);
224 umtx_unlock(NULL);
225
226 if (htp == NULL) {
227 htp = new Hashtable(status);
228 if (htp && U_SUCCESS(status)) {
229 CharString cbundleID(bundleID);
230 const char* path = (const char*) cbundleID;
231 if (*path == 0) path = NULL; // empty string => NULL
232 UEnumeration *uenum = ures_openAvailableLocales(path, &status);
233 for (;;) {
234 const UChar* id = uenum_unext(uenum, NULL, &status);
235 if (id == NULL) {
236 break;
237 }
238 htp->put(UnicodeString(id), (void*)htp, status);
239 }
240 uenum_close(uenum);
241 if (U_FAILURE(status)) {
242 delete htp;
243 return NULL;
244 }
245 umtx_lock(NULL);
246 cache->put(bundleID, (void*)htp, status);
247 umtx_unlock(NULL);
248 }
249 }
250 return htp;
251 }
252
253 UBool
254 LocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& child)
255 {
256 return child.indexOf(root) == 0 &&
257 (child.length() == root.length() ||
258 child.charAt(root.length()) == UNDERSCORE_CHAR);
259 }
260
261 /*
262 ******************************************************************
263 */
264
265 const int32_t LocaleKey::KIND_ANY = -1;
266
267 LocaleKey*
268 LocaleKey::createWithCanonicalFallback(const UnicodeString* primaryID,
269 const UnicodeString* canonicalFallbackID,
270 UErrorCode& status)
271 {
272 return LocaleKey::createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY, status);
273 }
274
275 LocaleKey*
276 LocaleKey::createWithCanonicalFallback(const UnicodeString* primaryID,
277 const UnicodeString* canonicalFallbackID,
278 int32_t kind,
279 UErrorCode& status)
280 {
281 if (primaryID == NULL || U_FAILURE(status)) {
282 return NULL;
283 }
284 UnicodeString canonicalPrimaryID;
285 LocaleUtility::canonicalLocaleString(primaryID, canonicalPrimaryID);
286 return new LocaleKey(*primaryID, canonicalPrimaryID, canonicalFallbackID, kind);
287 }
288
289 LocaleKey::LocaleKey(const UnicodeString& primaryID,
290 const UnicodeString& canonicalPrimaryID,
291 const UnicodeString* canonicalFallbackID,
292 int32_t kind)
293 : ICUServiceKey(primaryID)
294 , _kind(kind)
295 , _primaryID(canonicalPrimaryID)
296 , _fallbackID()
297 , _currentID()
298 {
299 _fallbackID.setToBogus();
300 if (_primaryID.length() != 0) {
301 if (canonicalFallbackID != NULL && _primaryID != *canonicalFallbackID) {
302 _fallbackID = *canonicalFallbackID;
303 }
304 }
305
306 _currentID = _primaryID;
307 }
308
309 LocaleKey::~LocaleKey() {}
310
311 UnicodeString&
312 LocaleKey::prefix(UnicodeString& result) const {
313 if (_kind != KIND_ANY) {
314 UChar buffer[64];
315 uprv_itou(buffer, 64, _kind, 10, 0);
316 UnicodeString temp(buffer);
317 result.append(temp);
318 }
319 return result;
320 }
321
322 int32_t
323 LocaleKey::kind() const {
324 return _kind;
325 }
326
327 UnicodeString&
328 LocaleKey::canonicalID(UnicodeString& result) const {
329 return result.append(_primaryID);
330 }
331
332 UnicodeString&
333 LocaleKey::currentID(UnicodeString& result) const {
334 if (!_currentID.isBogus()) {
335 result.append(_currentID);
336 }
337 return result;
338 }
339
340 UnicodeString&
341 LocaleKey::currentDescriptor(UnicodeString& result) const {
342 if (!_currentID.isBogus()) {
343 prefix(result).append(PREFIX_DELIMITER).append(_currentID);
344 } else {
345 result.setToBogus();
346 }
347 return result;
348 }
349
350 Locale&
351 LocaleKey::canonicalLocale(Locale& result) const {
352 return LocaleUtility::initLocaleFromName(_primaryID, result);
353 }
354
355 Locale&
356 LocaleKey::currentLocale(Locale& result) const {
357 return LocaleUtility::initLocaleFromName(_currentID, result);
358 }
359
360 UBool
361 LocaleKey::fallback() {
362 if (!_currentID.isBogus()) {
363 int x = _currentID.lastIndexOf(UNDERSCORE_CHAR);
364 if (x != -1) {
365 _currentID.remove(x); // truncate current or fallback, whichever we're pointing to
366 return TRUE;
367 }
368
369 if (!_fallbackID.isBogus()) {
370 _currentID = _fallbackID;
371 _fallbackID.setToBogus();
372 return TRUE;
373 }
374
375 if (_currentID.length() > 0) {
376 _currentID.remove(0); // completely truncate
377 return TRUE;
378 }
379
380 _currentID.setToBogus();
381 }
382
383 return FALSE;
384 }
385
386 UBool
387 LocaleKey::isFallbackOf(const UnicodeString& id) const {
388 UnicodeString temp(id);
389 parseSuffix(temp);
390 return temp.indexOf(_primaryID) == 0 &&
391 (temp.length() == _primaryID.length() ||
392 temp.charAt(_primaryID.length()) == UNDERSCORE_CHAR);
393 }
394
395 #ifdef SERVICE_DEBUG
396 UnicodeString&
397 LocaleKey::debug(UnicodeString& result) const
398 {
399 ICUServiceKey::debug(result);
400 result.append(" kind: ");
401 result.append(_kind);
402 result.append(" primaryID: ");
403 result.append(_primaryID);
404 result.append(" fallbackID: ");
405 result.append(_fallbackID);
406 result.append(" currentID: ");
407 result.append(_currentID);
408 return result;
409 }
410
411 UnicodeString&
412 LocaleKey::debugClass(UnicodeString& result) const
413 {
414 return result.append("LocaleKey ");
415 }
416 #endif
417
418 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocaleKey)
419
420 /*
421 ******************************************************************
422 */
423
424 LocaleKeyFactory::LocaleKeyFactory(int32_t coverage)
425 : _name()
426 , _coverage(coverage)
427 {
428 }
429
430 LocaleKeyFactory::LocaleKeyFactory(int32_t coverage, const UnicodeString& name)
431 : _name(name)
432 , _coverage(coverage)
433 {
434 }
435
436 LocaleKeyFactory::~LocaleKeyFactory() {
437 }
438
439 UObject*
440 LocaleKeyFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const {
441 if (handlesKey(key, status)) {
442 const LocaleKey& lkey = (const LocaleKey&)key;
443 int32_t kind = lkey.kind();
444 Locale loc;
445 lkey.currentLocale(loc);
446
447 return handleCreate(loc, kind, service, status);
448 }
449 return NULL;
450 }
451
452 UBool
453 LocaleKeyFactory::handlesKey(const ICUServiceKey& key, UErrorCode& status) const {
454 const Hashtable* supported = getSupportedIDs(status);
455 if (supported) {
456 UnicodeString id;
457 key.currentID(id);
458 return supported->get(id) != NULL;
459 }
460 return FALSE;
461 }
462
463 void
464 LocaleKeyFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
465 const Hashtable* supported = getSupportedIDs(status);
466 if (supported) {
467 UBool visible = (_coverage & 0x1) == 0;
468
469 const UHashElement* elem = NULL;
470 int32_t pos = 0;
471 while ((elem = supported->nextElement(pos)) != NULL) {
472 const UnicodeString& id = *((const UnicodeString*)elem->key.pointer);
473 if (!visible) {
474 result.remove(id);
475 } else {
476 result.put(id, (void*)this, status); // this is dummy non-void marker used for set semantics
477 if (U_FAILURE(status)) {
478 break;
479 }
480 }
481 }
482 }
483 }
484
485 UnicodeString&
486 LocaleKeyFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const {
487 if ((_coverage & 0x1) == 0) {
488 //UErrorCode status = U_ZERO_ERROR;
489 // assume if this is called on us, we support some fallback of this id
490 // if (isSupportedID(id, status)) {
491 Locale loc;
492 LocaleUtility::initLocaleFromName(id, loc);
493 return loc.getDisplayName(locale, result);
494 // }
495 }
496 result.setToBogus();
497 return result;
498 }
499
500 UObject*
501 LocaleKeyFactory::handleCreate(const Locale& /* loc */,
502 int32_t /* kind */,
503 const ICUService* /* service */,
504 UErrorCode& /* status */) const {
505 return NULL;
506 }
507
508 UBool
509 LocaleKeyFactory::isSupportedID(const UnicodeString& id, UErrorCode& status) const {
510 const Hashtable* ids = getSupportedIDs(status);
511 return ids && ids->get(id);
512 }
513
514 const Hashtable*
515 LocaleKeyFactory::getSupportedIDs(UErrorCode& /* status */) const {
516 return NULL;
517 }
518
519 #ifdef SERVICE_DEBUG
520 UnicodeString&
521 LocaleKeyFactory::debug(UnicodeString& result) const
522 {
523 debugClass(result);
524 result.append(", name: ");
525 result.append(_name);
526 result.append(", coverage: ");
527 result.append(_coverage);
528 return result;
529 }
530
531 UnicodeString&
532 LocaleKeyFactory::debugClass(UnicodeString& result) const
533 {
534 return result.append("LocaleKeyFactory");
535 }
536 #endif
537
538 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocaleKeyFactory)
539
540 /*
541 ******************************************************************
542 */
543
544 SimpleLocaleKeyFactory::SimpleLocaleKeyFactory(UObject* objToAdopt,
545 const UnicodeString& locale,
546 int32_t kind,
547 int32_t coverage)
548 : LocaleKeyFactory(coverage)
549 , _obj(objToAdopt)
550 , _id(locale)
551 , _kind(kind)
552 {
553 }
554
555 SimpleLocaleKeyFactory::SimpleLocaleKeyFactory(UObject* objToAdopt,
556 const Locale& locale,
557 int32_t kind,
558 int32_t coverage)
559 : LocaleKeyFactory(coverage)
560 , _obj(objToAdopt)
561 , _id()
562 , _kind(kind)
563 {
564 LocaleUtility::initNameFromLocale(locale, _id);
565 }
566
567 SimpleLocaleKeyFactory::~SimpleLocaleKeyFactory()
568 {
569 delete _obj;
570 _obj = NULL;
571 }
572
573 UObject*
574 SimpleLocaleKeyFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
575 {
576 if (U_SUCCESS(status)) {
577 const LocaleKey& lkey = (const LocaleKey&)key;
578 if (_kind == LocaleKey::KIND_ANY || _kind == lkey.kind()) {
579 UnicodeString keyID;
580 lkey.currentID(keyID);
581 if (_id == keyID) {
582 return service->cloneInstance(_obj);
583 }
584 }
585 }
586 return NULL;
587 }
588
589 UBool
590 SimpleLocaleKeyFactory::isSupportedID(const UnicodeString& id, UErrorCode& /* status */) const
591 {
592 return id == _id;
593 }
594
595 void
596 SimpleLocaleKeyFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const
597 {
598 if (U_SUCCESS(status)) {
599 if (_coverage & 0x1) {
600 result.remove(_id);
601 } else {
602 result.put(_id, (void*)this, status);
603 }
604 }
605 }
606
607 #ifdef SERVICE_DEBUG
608 UnicodeString&
609 SimpleLocaleKeyFactory::debug(UnicodeString& result) const
610 {
611 LocaleKeyFactory::debug(result);
612 result.append(", id: ");
613 result.append(_id);
614 result.append(", kind: ");
615 result.append(_kind);
616 return result;
617 }
618
619 UnicodeString&
620 SimpleLocaleKeyFactory::debugClass(UnicodeString& result) const
621 {
622 return result.append("SimpleLocaleKeyFactory");
623 }
624 #endif
625
626 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleLocaleKeyFactory)
627
628 /*
629 ******************************************************************
630 */
631
632 ICUResourceBundleFactory::ICUResourceBundleFactory()
633 : LocaleKeyFactory(VISIBLE)
634 , _bundleName()
635 {
636 }
637
638 ICUResourceBundleFactory::ICUResourceBundleFactory(const UnicodeString& bundleName)
639 : LocaleKeyFactory(VISIBLE)
640 , _bundleName(bundleName)
641 {
642 }
643
644 ICUResourceBundleFactory::~ICUResourceBundleFactory() {}
645
646 const Hashtable*
647 ICUResourceBundleFactory::getSupportedIDs(UErrorCode& status) const
648 {
649 if (U_SUCCESS(status)) {
650 return LocaleUtility::getAvailableLocaleNames(_bundleName);
651 }
652 return NULL;
653 }
654
655 UObject*
656 ICUResourceBundleFactory::handleCreate(const Locale& loc, int32_t /* kind */, const ICUService* /* service */, UErrorCode& status) const
657 {
658 if (U_SUCCESS(status)) {
659 // _bundleName is a package name
660 // and should only contain invariant characters
661 char pkg[20];
662 int32_t length;
663 length=_bundleName.extract(0, INT32_MAX, pkg, (int32_t)sizeof(pkg), US_INV);
664 if(length>=(int32_t)sizeof(pkg)) {
665 return NULL;
666 }
667 return new ResourceBundle(pkg, loc, status);
668 }
669 return NULL;
670 }
671
672 #ifdef SERVICE_DEBUG
673 UnicodeString&
674 ICUResourceBundleFactory::debug(UnicodeString& result) const
675 {
676 LocaleKeyFactory::debug(result);
677 result.append(", bundle: ");
678 return result.append(_bundleName);
679 }
680
681 UnicodeString&
682 ICUResourceBundleFactory::debugClass(UnicodeString& result) const
683 {
684 return result.append("ICUResourceBundleFactory");
685 }
686 #endif
687
688 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUResourceBundleFactory)
689
690 /*
691 ******************************************************************
692 */
693
694 ICULocaleService::ICULocaleService()
695 : fallbackLocale(Locale::getDefault())
696 , llock(0)
697 {
698 umtx_init(&llock);
699 }
700
701 ICULocaleService::ICULocaleService(const UnicodeString& dname)
702 : ICUService(dname)
703 , fallbackLocale(Locale::getDefault())
704 , llock(0)
705 {
706 umtx_init(&llock);
707 }
708
709 ICULocaleService::~ICULocaleService()
710 {
711 umtx_destroy(&llock);
712 }
713
714 UObject*
715 ICULocaleService::get(const Locale& locale, UErrorCode& status) const
716 {
717 return get(locale, LocaleKey::KIND_ANY, NULL, status);
718 }
719
720 UObject*
721 ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
722 {
723 return get(locale, kind, NULL, status);
724 }
725
726 UObject*
727 ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
728 {
729 return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
730 }
731
732 UObject*
733 ICULocaleService::get(const Locale& locale, int32_t kind, Locale* actualReturn, UErrorCode& status) const
734 {
735 UObject* result = NULL;
736 if (U_FAILURE(status)) {
737 return result;
738 }
739
740 UnicodeString locName(locale.getName(), -1, US_INV);
741 if (locName.isBogus()) {
742 status = U_MEMORY_ALLOCATION_ERROR;
743 } else {
744 ICUServiceKey* key = createKey(&locName, kind, status);
745 if (key) {
746 if (actualReturn == NULL) {
747 result = getKey(*key, status);
748 } else {
749 UnicodeString temp;
750 result = getKey(*key, &temp, status);
751
752 if (result != NULL) {
753 key->parseSuffix(temp);
754 LocaleUtility::initLocaleFromName(temp, *actualReturn);
755 }
756 }
757 delete key;
758 }
759 }
760 return result;
761 }
762
763
764 URegistryKey
765 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale,
766 UBool visible, UErrorCode& status)
767 {
768 Locale loc;
769 LocaleUtility::initLocaleFromName(locale, loc);
770 return registerInstance(objToAdopt, loc, LocaleKey::KIND_ANY,
771 visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE, status);
772 }
773
774 URegistryKey
775 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
776 {
777 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
778 }
779
780 URegistryKey
781 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
782 {
783 return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
784 }
785
786 URegistryKey
787 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, int32_t coverage, UErrorCode& status)
788 {
789 ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
790 if (factory != NULL) {
791 return registerFactory(factory, status);
792 }
793 delete objToAdopt;
794 return NULL;
795 }
796
797 #if 0
798 URegistryKey
799 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
800 {
801 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
802 }
803
804 URegistryKey
805 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UBool visible, UErrorCode& status)
806 {
807 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY,
808 visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE,
809 status);
810 }
811
812 URegistryKey
813 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, int32_t kind, int32_t coverage, UErrorCode& status)
814 {
815 ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
816 if (factory != NULL) {
817 return registerFactory(factory, status);
818 }
819 delete objToAdopt;
820 return NULL;
821 }
822 #endif
823
824 class ServiceEnumeration : public StringEnumeration {
825 private:
826 const ICULocaleService* _service;
827 int32_t _timestamp;
828 UVector _ids;
829 int32_t _pos;
830
831 private:
832 ServiceEnumeration(const ICULocaleService* service, UErrorCode &status)
833 : _service(service)
834 , _timestamp(service->getTimestamp())
835 , _ids(uhash_deleteUnicodeString, NULL, status)
836 , _pos(0)
837 {
838 _service->getVisibleIDs(_ids, status);
839 }
840
841 ServiceEnumeration(const ServiceEnumeration &other, UErrorCode &status)
842 : _service(other._service)
843 , _timestamp(other._timestamp)
844 , _ids(uhash_deleteUnicodeString, NULL, status)
845 , _pos(0)
846 {
847 if(U_SUCCESS(status)) {
848 int32_t i, length;
849
850 length = other._ids.size();
851 for(i = 0; i < length; ++i) {
852 _ids.addElement(((UnicodeString *)other._ids.elementAt(i))->clone(), status);
853 }
854
855 if(U_SUCCESS(status)) {
856 _pos = other._pos;
857 }
858 }
859 }
860
861 public:
862 static ServiceEnumeration* create(const ICULocaleService* service) {
863 UErrorCode status = U_ZERO_ERROR;
864 ServiceEnumeration* result = new ServiceEnumeration(service, status);
865 if (U_SUCCESS(status)) {
866 return result;
867 }
868 delete result;
869 return NULL;
870 }
871
872 virtual ~ServiceEnumeration() {}
873
874 virtual StringEnumeration *clone() const {
875 UErrorCode status = U_ZERO_ERROR;
876 ServiceEnumeration *cl = new ServiceEnumeration(*this, status);
877 if(U_FAILURE(status)) {
878 delete cl;
879 cl = NULL;
880 }
881 return cl;
882 }
883
884 UBool upToDate(UErrorCode& status) const {
885 if (U_SUCCESS(status)) {
886 if (_timestamp == _service->getTimestamp()) {
887 return TRUE;
888 }
889 status = U_ENUM_OUT_OF_SYNC_ERROR;
890 }
891 return FALSE;
892 }
893
894 virtual int32_t count(UErrorCode& status) const {
895 return upToDate(status) ? _ids.size() : 0;
896 }
897
898 virtual const UnicodeString* snext(UErrorCode& status) {
899 if (upToDate(status) && (_pos < _ids.size())) {
900 return (const UnicodeString*)_ids[_pos++];
901 }
902 return NULL;
903 }
904
905 virtual void reset(UErrorCode& status) {
906 if (status == U_ENUM_OUT_OF_SYNC_ERROR) {
907 status = U_ZERO_ERROR;
908 }
909 if (U_SUCCESS(status)) {
910 _timestamp = _service->getTimestamp();
911 _pos = 0;
912 _service->getVisibleIDs(_ids, status);
913 }
914 }
915
916 public:
917 static UClassID U_EXPORT2 getStaticClassID(void);
918 virtual UClassID getDynamicClassID(void) const;
919 };
920
921 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
922
923 StringEnumeration*
924 ICULocaleService::getAvailableLocales(void) const
925 {
926 return ServiceEnumeration::create(this);
927 }
928
929 const UnicodeString&
930 ICULocaleService::validateFallbackLocale() const
931 {
932 const Locale& loc = Locale::getDefault();
933 ICULocaleService* ncThis = (ICULocaleService*)this;
934 {
935 Mutex mutex(&ncThis->llock);
936 if (loc != fallbackLocale) {
937 ncThis->fallbackLocale = loc;
938 LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
939 ncThis->clearServiceCache();
940 }
941 }
942 return fallbackLocaleName;
943 }
944
945 ICUServiceKey*
946 ICULocaleService::createKey(const UnicodeString* id, UErrorCode& status) const
947 {
948 return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), status);
949 }
950
951 ICUServiceKey*
952 ICULocaleService::createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const
953 {
954 return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), kind, status);
955 }
956
957 U_NAMESPACE_END
958
959 /* !UCONFIG_NO_SERVICE */
960 #endif
961
962