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