blob: 19481122efa52e1f505704537782808319ab4a07 [file] [log] [blame]
Jungshik Shin87232d82017-05-13 21:10:13 -07001// © 2016 and later: Unicode, Inc. and others.
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07002// License & terms of use: http://www.unicode.org/copyright.html
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003/**
4 *******************************************************************************
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08005 * Copyright (C) 2001-2014, International Business Machines Corporation and *
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00006 * 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"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000021#include "uassert.h"
22
23#define UNDERSCORE_CHAR ((UChar)0x005f)
24#define AT_SIGN_CHAR ((UChar)64)
25#define PERIOD_CHAR ((UChar)46)
26
27U_NAMESPACE_BEGIN
28
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000029ICULocaleService::ICULocaleService()
30 : fallbackLocale(Locale::getDefault())
31{
32}
33
34ICULocaleService::ICULocaleService(const UnicodeString& dname)
35 : ICUService(dname)
36 , fallbackLocale(Locale::getDefault())
37{
38}
39
40ICULocaleService::~ICULocaleService()
41{
42}
43
44UObject*
45ICULocaleService::get(const Locale& locale, UErrorCode& status) const
46{
47 return get(locale, LocaleKey::KIND_ANY, NULL, status);
48}
49
50UObject*
51ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
52{
53 return get(locale, kind, NULL, status);
54}
55
56UObject*
57ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
58{
59 return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
60}
61
62UObject*
63ICULocaleService::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
94URegistryKey
95ICULocaleService::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
104URegistryKey
105ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
106{
107 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
108}
109
110URegistryKey
111ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
112{
113 return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
114}
115
116URegistryKey
117ICULocaleService::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
128URegistryKey
129ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
130{
131 return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
132}
133
134URegistryKey
135ICULocaleService::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
142URegistryKey
143ICULocaleService::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
154class ServiceEnumeration : public StringEnumeration {
155private:
156 const ICULocaleService* _service;
157 int32_t _timestamp;
158 UVector _ids;
159 int32_t _pos;
160
161private:
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
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) {
Frank Tangd2858cb2022-04-08 20:34:12 -0700182 LocalPointer<UnicodeString> clonedId(((UnicodeString *)other._ids.elementAt(i))->clone(), status);
183 _ids.adoptElement(clonedId.orphan(), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000184 }
185
186 if(U_SUCCESS(status)) {
187 _pos = other._pos;
188 }
189 }
190 }
191
192public:
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
Frank Tang3e05d9d2021-11-08 14:04:04 -0800205 virtual StringEnumeration *clone() const override {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000206 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
215 UBool upToDate(UErrorCode& status) const {
216 if (U_SUCCESS(status)) {
217 if (_timestamp == _service->getTimestamp()) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800218 return true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000219 }
220 status = U_ENUM_OUT_OF_SYNC_ERROR;
221 }
Frank Tang1f164ee2022-11-08 12:31:27 -0800222 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000223 }
224
Frank Tang3e05d9d2021-11-08 14:04:04 -0800225 virtual int32_t count(UErrorCode& status) const override {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000226 return upToDate(status) ? _ids.size() : 0;
227 }
228
Frank Tang3e05d9d2021-11-08 14:04:04 -0800229 virtual const UnicodeString* snext(UErrorCode& status) override {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000230 if (upToDate(status) && (_pos < _ids.size())) {
231 return (const UnicodeString*)_ids[_pos++];
232 }
233 return NULL;
234 }
235
Frank Tang3e05d9d2021-11-08 14:04:04 -0800236 virtual void reset(UErrorCode& status) override {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000237 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
247public:
248 static UClassID U_EXPORT2 getStaticClassID(void);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800249 virtual UClassID getDynamicClassID(void) const override;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000250};
251
252ServiceEnumeration::~ServiceEnumeration() {}
253
254UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
255
256StringEnumeration*
257ICULocaleService::getAvailableLocales(void) const
258{
259 return ServiceEnumeration::create(this);
260}
261
262const UnicodeString&
263ICULocaleService::validateFallbackLocale() const
264{
265 const Locale& loc = Locale::getDefault();
266 ICULocaleService* ncThis = (ICULocaleService*)this;
Frank Tangb8696612019-10-25 14:58:21 -0700267 static UMutex llock;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000268 {
Frank Tangb8696612019-10-25 14:58:21 -0700269 Mutex mutex(&llock);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000270 if (loc != fallbackLocale) {
271 ncThis->fallbackLocale = loc;
272 LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
273 ncThis->clearServiceCache();
274 }
275 }
276 return fallbackLocaleName;
277}
278
279ICUServiceKey*
280ICULocaleService::createKey(const UnicodeString* id, UErrorCode& status) const
281{
282 return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), status);
283}
284
285ICUServiceKey*
286ICULocaleService::createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const
287{
288 return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), kind, status);
289}
290
291U_NAMESPACE_END
292
293/* !UCONFIG_NO_SERVICE */
294#endif
295
296