1/**
2 *******************************************************************************
3 * Copyright (C) 2001-2012, 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 "ucln_cmn.h"
20#include "uassert.h"
21
22#define UNDERSCORE_CHAR ((UChar)0x005f)
23#define AT_SIGN_CHAR    ((UChar)64)
24#define PERIOD_CHAR     ((UChar)46)
25
26U_NAMESPACE_BEGIN
27
28static UMutex llock = U_MUTEX_INITIALIZER;
29ICULocaleService::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) {
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
191public:
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
204    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
214    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
224    virtual int32_t count(UErrorCode& status) const {
225        return upToDate(status) ? _ids.size() : 0;
226    }
227
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
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
246public:
247    static UClassID U_EXPORT2 getStaticClassID(void);
248    virtual UClassID getDynamicClassID(void) const;
249};
250
251ServiceEnumeration::~ServiceEnumeration() {}
252
253UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
254
255StringEnumeration*
256ICULocaleService::getAvailableLocales(void) const
257{
258    return ServiceEnumeration::create(this);
259}
260
261const UnicodeString&
262ICULocaleService::validateFallbackLocale() const
263{
264    const Locale&     loc    = Locale::getDefault();
265    ICULocaleService* ncThis = (ICULocaleService*)this;
266    {
267        Mutex mutex(&llock);
268        if (loc != fallbackLocale) {
269            ncThis->fallbackLocale = loc;
270            LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
271            ncThis->clearServiceCache();
272        }
273    }
274    return fallbackLocaleName;
275}
276
277ICUServiceKey*
278ICULocaleService::createKey(const UnicodeString* id, UErrorCode& status) const
279{
280    return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), status);
281}
282
283ICUServiceKey*
284ICULocaleService::createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const
285{
286    return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), kind, status);
287}
288
289U_NAMESPACE_END
290
291/* !UCONFIG_NO_SERVICE */
292#endif
293
294
295