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
29 static UMutex llock = U_MUTEX_INITIALIZER;
ICULocaleService()30 ICULocaleService::ICULocaleService()
31 : fallbackLocale(Locale::getDefault())
32 {
33 }
34
ICULocaleService(const UnicodeString & dname)35 ICULocaleService::ICULocaleService(const UnicodeString& dname)
36 : ICUService(dname)
37 , fallbackLocale(Locale::getDefault())
38 {
39 }
40
~ICULocaleService()41 ICULocaleService::~ICULocaleService()
42 {
43 }
44
45 UObject*
get(const Locale & locale,UErrorCode & status) const46 ICULocaleService::get(const Locale& locale, UErrorCode& status) const
47 {
48 return get(locale, LocaleKey::KIND_ANY, NULL, status);
49 }
50
51 UObject*
get(const Locale & locale,int32_t kind,UErrorCode & status) const52 ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
53 {
54 return get(locale, kind, NULL, status);
55 }
56
57 UObject*
get(const Locale & locale,Locale * actualReturn,UErrorCode & status) const58 ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
59 {
60 return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
61 }
62
63 UObject*
get(const Locale & locale,int32_t kind,Locale * actualReturn,UErrorCode & status) const64 ICULocaleService::get(const Locale& locale, int32_t kind, Locale* actualReturn, UErrorCode& status) const
65 {
66 UObject* result = NULL;
67 if (U_FAILURE(status)) {
68 return result;
69 }
70
71 UnicodeString locName(locale.getName(), -1, US_INV);
72 if (locName.isBogus()) {
73 status = U_MEMORY_ALLOCATION_ERROR;
74 } else {
75 ICUServiceKey* key = createKey(&locName, kind, status);
76 if (key) {
77 if (actualReturn == NULL) {
78 result = getKey(*key, status);
79 } else {
80 UnicodeString temp;
81 result = getKey(*key, &temp, status);
82
83 if (result != NULL) {
84 key->parseSuffix(temp);
85 LocaleUtility::initLocaleFromName(temp, *actualReturn);
86 }
87 }
88 delete key;
89 }
90 }
91 return result;
92 }
93
94
95 URegistryKey
registerInstance(UObject * objToAdopt,const UnicodeString & locale,UBool visible,UErrorCode & status)96 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale,
97 UBool visible, UErrorCode& status)
98 {
99 Locale loc;
100 LocaleUtility::initLocaleFromName(locale, loc);
101 return registerInstance(objToAdopt, loc, LocaleKey::KIND_ANY,
102 visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE, status);
103 }
104
105 URegistryKey
registerInstance(UObject * objToAdopt,const Locale & locale,UErrorCode & status)106 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
107 {
108 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
109 }
110
111 URegistryKey
registerInstance(UObject * objToAdopt,const Locale & locale,int32_t kind,UErrorCode & status)112 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
113 {
114 return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
115 }
116
117 URegistryKey
registerInstance(UObject * objToAdopt,const Locale & locale,int32_t kind,int32_t coverage,UErrorCode & status)118 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, int32_t coverage, UErrorCode& status)
119 {
120 ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
121 if (factory != NULL) {
122 return registerFactory(factory, status);
123 }
124 delete objToAdopt;
125 return NULL;
126 }
127
128 #if 0
129 URegistryKey
130 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
131 {
132 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
133 }
134
135 URegistryKey
136 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UBool visible, UErrorCode& status)
137 {
138 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY,
139 visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE,
140 status);
141 }
142
143 URegistryKey
144 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, int32_t kind, int32_t coverage, UErrorCode& status)
145 {
146 ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
147 if (factory != NULL) {
148 return registerFactory(factory, status);
149 }
150 delete objToAdopt;
151 return NULL;
152 }
153 #endif
154
155 class ServiceEnumeration : public StringEnumeration {
156 private:
157 const ICULocaleService* _service;
158 int32_t _timestamp;
159 UVector _ids;
160 int32_t _pos;
161
162 private:
ServiceEnumeration(const ICULocaleService * service,UErrorCode & status)163 ServiceEnumeration(const ICULocaleService* service, UErrorCode &status)
164 : _service(service)
165 , _timestamp(service->getTimestamp())
166 , _ids(uprv_deleteUObject, NULL, status)
167 , _pos(0)
168 {
169 _service->getVisibleIDs(_ids, status);
170 }
171
ServiceEnumeration(const ServiceEnumeration & other,UErrorCode & status)172 ServiceEnumeration(const ServiceEnumeration &other, UErrorCode &status)
173 : _service(other._service)
174 , _timestamp(other._timestamp)
175 , _ids(uprv_deleteUObject, NULL, status)
176 , _pos(0)
177 {
178 if(U_SUCCESS(status)) {
179 int32_t i, length;
180
181 length = other._ids.size();
182 for(i = 0; i < length; ++i) {
183 _ids.addElement(((UnicodeString *)other._ids.elementAt(i))->clone(), status);
184 }
185
186 if(U_SUCCESS(status)) {
187 _pos = other._pos;
188 }
189 }
190 }
191
192 public:
create(const ICULocaleService * service)193 static ServiceEnumeration* create(const ICULocaleService* service) {
194 UErrorCode status = U_ZERO_ERROR;
195 ServiceEnumeration* result = new ServiceEnumeration(service, status);
196 if (U_SUCCESS(status)) {
197 return result;
198 }
199 delete result;
200 return NULL;
201 }
202
203 virtual ~ServiceEnumeration();
204
clone() const205 virtual StringEnumeration *clone() const {
206 UErrorCode status = U_ZERO_ERROR;
207 ServiceEnumeration *cl = new ServiceEnumeration(*this, status);
208 if(U_FAILURE(status)) {
209 delete cl;
210 cl = NULL;
211 }
212 return cl;
213 }
214
upToDate(UErrorCode & status) const215 UBool upToDate(UErrorCode& status) const {
216 if (U_SUCCESS(status)) {
217 if (_timestamp == _service->getTimestamp()) {
218 return TRUE;
219 }
220 status = U_ENUM_OUT_OF_SYNC_ERROR;
221 }
222 return FALSE;
223 }
224
count(UErrorCode & status) const225 virtual int32_t count(UErrorCode& status) const {
226 return upToDate(status) ? _ids.size() : 0;
227 }
228
snext(UErrorCode & status)229 virtual const UnicodeString* snext(UErrorCode& status) {
230 if (upToDate(status) && (_pos < _ids.size())) {
231 return (const UnicodeString*)_ids[_pos++];
232 }
233 return NULL;
234 }
235
reset(UErrorCode & status)236 virtual void reset(UErrorCode& status) {
237 if (status == U_ENUM_OUT_OF_SYNC_ERROR) {
238 status = U_ZERO_ERROR;
239 }
240 if (U_SUCCESS(status)) {
241 _timestamp = _service->getTimestamp();
242 _pos = 0;
243 _service->getVisibleIDs(_ids, status);
244 }
245 }
246
247 public:
248 static UClassID U_EXPORT2 getStaticClassID(void);
249 virtual UClassID getDynamicClassID(void) const;
250 };
251
~ServiceEnumeration()252 ServiceEnumeration::~ServiceEnumeration() {}
253
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)254 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
255
256 StringEnumeration*
257 ICULocaleService::getAvailableLocales(void) const
258 {
259 return ServiceEnumeration::create(this);
260 }
261
262 const UnicodeString&
validateFallbackLocale() const263 ICULocaleService::validateFallbackLocale() const
264 {
265 const Locale& loc = Locale::getDefault();
266 ICULocaleService* ncThis = (ICULocaleService*)this;
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