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