1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /**
4 *******************************************************************************
5 * Copyright (C) 2001-2014, International Business Machines Corporation and *
6 * others. All Rights Reserved. *
7 *******************************************************************************
8 *
9 *******************************************************************************
10 */
11 #include "unicode/utypes.h"
12
13 #if !UCONFIG_NO_SERVICE
14
15 #include "unicode/resbund.h"
16 #include "uresimp.h"
17 #include "cmemory.h"
18 #include "servloc.h"
19 #include "ustrfmt.h"
20 #include "charstr.h"
21 #include "uassert.h"
22
23 #define UNDERSCORE_CHAR ((UChar)0x005f)
24 #define AT_SIGN_CHAR ((UChar)64)
25 #define PERIOD_CHAR ((UChar)46)
26
27 U_NAMESPACE_BEGIN
28
ICULocaleService()29 ICULocaleService::ICULocaleService()
30 : fallbackLocale(Locale::getDefault())
31 {
32 }
33
ICULocaleService(const UnicodeString & dname)34 ICULocaleService::ICULocaleService(const UnicodeString& dname)
35 : ICUService(dname)
36 , fallbackLocale(Locale::getDefault())
37 {
38 }
39
~ICULocaleService()40 ICULocaleService::~ICULocaleService()
41 {
42 }
43
44 UObject*
get(const Locale & locale,UErrorCode & status) const45 ICULocaleService::get(const Locale& locale, UErrorCode& status) const
46 {
47 return get(locale, LocaleKey::KIND_ANY, NULL, status);
48 }
49
50 UObject*
get(const Locale & locale,int32_t kind,UErrorCode & status) const51 ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
52 {
53 return get(locale, kind, NULL, status);
54 }
55
56 UObject*
get(const Locale & locale,Locale * actualReturn,UErrorCode & status) const57 ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
58 {
59 return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
60 }
61
62 UObject*
get(const Locale & locale,int32_t kind,Locale * actualReturn,UErrorCode & status) const63 ICULocaleService::get(const Locale& locale, int32_t kind, Locale* actualReturn, UErrorCode& status) const
64 {
65 UObject* result = NULL;
66 if (U_FAILURE(status)) {
67 return result;
68 }
69
70 UnicodeString locName(locale.getName(), -1, US_INV);
71 if (locName.isBogus()) {
72 status = U_MEMORY_ALLOCATION_ERROR;
73 } else {
74 ICUServiceKey* key = createKey(&locName, kind, status);
75 if (key) {
76 if (actualReturn == NULL) {
77 result = getKey(*key, status);
78 } else {
79 UnicodeString temp;
80 result = getKey(*key, &temp, status);
81
82 if (result != NULL) {
83 key->parseSuffix(temp);
84 LocaleUtility::initLocaleFromName(temp, *actualReturn);
85 }
86 }
87 delete key;
88 }
89 }
90 return result;
91 }
92
93
94 URegistryKey
registerInstance(UObject * objToAdopt,const UnicodeString & locale,UBool visible,UErrorCode & status)95 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale,
96 UBool visible, UErrorCode& status)
97 {
98 Locale loc;
99 LocaleUtility::initLocaleFromName(locale, loc);
100 return registerInstance(objToAdopt, loc, LocaleKey::KIND_ANY,
101 visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE, status);
102 }
103
104 URegistryKey
registerInstance(UObject * objToAdopt,const Locale & locale,UErrorCode & status)105 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
106 {
107 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
108 }
109
110 URegistryKey
registerInstance(UObject * objToAdopt,const Locale & locale,int32_t kind,UErrorCode & status)111 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
112 {
113 return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
114 }
115
116 URegistryKey
registerInstance(UObject * objToAdopt,const Locale & locale,int32_t kind,int32_t coverage,UErrorCode & status)117 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, int32_t coverage, UErrorCode& status)
118 {
119 ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
120 if (factory != NULL) {
121 return registerFactory(factory, status);
122 }
123 delete objToAdopt;
124 return NULL;
125 }
126
127 #if 0
128 URegistryKey
129 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
130 {
131 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
132 }
133
134 URegistryKey
135 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UBool visible, UErrorCode& status)
136 {
137 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY,
138 visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE,
139 status);
140 }
141
142 URegistryKey
143 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, int32_t kind, int32_t coverage, UErrorCode& status)
144 {
145 ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
146 if (factory != NULL) {
147 return registerFactory(factory, status);
148 }
149 delete objToAdopt;
150 return NULL;
151 }
152 #endif
153
154 class ServiceEnumeration : public StringEnumeration {
155 private:
156 const ICULocaleService* _service;
157 int32_t _timestamp;
158 UVector _ids;
159 int32_t _pos;
160
161 private:
ServiceEnumeration(const ICULocaleService * service,UErrorCode & status)162 ServiceEnumeration(const ICULocaleService* service, UErrorCode &status)
163 : _service(service)
164 , _timestamp(service->getTimestamp())
165 , _ids(uprv_deleteUObject, NULL, status)
166 , _pos(0)
167 {
168 _service->getVisibleIDs(_ids, status);
169 }
170
ServiceEnumeration(const ServiceEnumeration & other,UErrorCode & status)171 ServiceEnumeration(const ServiceEnumeration &other, UErrorCode &status)
172 : _service(other._service)
173 , _timestamp(other._timestamp)
174 , _ids(uprv_deleteUObject, NULL, status)
175 , _pos(0)
176 {
177 if(U_SUCCESS(status)) {
178 int32_t i, length;
179
180 length = other._ids.size();
181 for(i = 0; i < length; ++i) {
182 _ids.addElement(((UnicodeString *)other._ids.elementAt(i))->clone(), status);
183 }
184
185 if(U_SUCCESS(status)) {
186 _pos = other._pos;
187 }
188 }
189 }
190
191 public:
create(const ICULocaleService * service)192 static ServiceEnumeration* create(const ICULocaleService* service) {
193 UErrorCode status = U_ZERO_ERROR;
194 ServiceEnumeration* result = new ServiceEnumeration(service, status);
195 if (U_SUCCESS(status)) {
196 return result;
197 }
198 delete result;
199 return NULL;
200 }
201
202 virtual ~ServiceEnumeration();
203
clone() const204 virtual StringEnumeration *clone() const {
205 UErrorCode status = U_ZERO_ERROR;
206 ServiceEnumeration *cl = new ServiceEnumeration(*this, status);
207 if(U_FAILURE(status)) {
208 delete cl;
209 cl = NULL;
210 }
211 return cl;
212 }
213
upToDate(UErrorCode & status) const214 UBool upToDate(UErrorCode& status) const {
215 if (U_SUCCESS(status)) {
216 if (_timestamp == _service->getTimestamp()) {
217 return TRUE;
218 }
219 status = U_ENUM_OUT_OF_SYNC_ERROR;
220 }
221 return FALSE;
222 }
223
count(UErrorCode & status) const224 virtual int32_t count(UErrorCode& status) const {
225 return upToDate(status) ? _ids.size() : 0;
226 }
227
snext(UErrorCode & status)228 virtual const UnicodeString* snext(UErrorCode& status) {
229 if (upToDate(status) && (_pos < _ids.size())) {
230 return (const UnicodeString*)_ids[_pos++];
231 }
232 return NULL;
233 }
234
reset(UErrorCode & status)235 virtual void reset(UErrorCode& status) {
236 if (status == U_ENUM_OUT_OF_SYNC_ERROR) {
237 status = U_ZERO_ERROR;
238 }
239 if (U_SUCCESS(status)) {
240 _timestamp = _service->getTimestamp();
241 _pos = 0;
242 _service->getVisibleIDs(_ids, status);
243 }
244 }
245
246 public:
247 static UClassID U_EXPORT2 getStaticClassID(void);
248 virtual UClassID getDynamicClassID(void) const;
249 };
250
~ServiceEnumeration()251 ServiceEnumeration::~ServiceEnumeration() {}
252
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)253 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
254
255 StringEnumeration*
256 ICULocaleService::getAvailableLocales(void) const
257 {
258 return ServiceEnumeration::create(this);
259 }
260
261 const UnicodeString&
validateFallbackLocale() const262 ICULocaleService::validateFallbackLocale() const
263 {
264 const Locale& loc = Locale::getDefault();
265 ICULocaleService* ncThis = (ICULocaleService*)this;
266 static UMutex llock;
267 {
268 Mutex mutex(&llock);
269 if (loc != fallbackLocale) {
270 ncThis->fallbackLocale = loc;
271 LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
272 ncThis->clearServiceCache();
273 }
274 }
275 return fallbackLocaleName;
276 }
277
278 ICUServiceKey*
createKey(const UnicodeString * id,UErrorCode & status) const279 ICULocaleService::createKey(const UnicodeString* id, UErrorCode& status) const
280 {
281 return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), status);
282 }
283
284 ICUServiceKey*
createKey(const UnicodeString * id,int32_t kind,UErrorCode & status) const285 ICULocaleService::createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const
286 {
287 return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), kind, status);
288 }
289
290 U_NAMESPACE_END
291
292 /* !UCONFIG_NO_SERVICE */
293 #endif
294
295
296