1/**
2 *******************************************************************************
3 * Copyright (C) 2001-2011, 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
29static UMTX llock;
30ICULocaleService::ICULocaleService()
31  : fallbackLocale(Locale::getDefault())
32{
33}
34
35ICULocaleService::ICULocaleService(const UnicodeString& dname)
36  : ICUService(dname)
37  , fallbackLocale(Locale::getDefault())
38{
39}
40
41ICULocaleService::~ICULocaleService()
42{
43}
44
45UObject*
46ICULocaleService::get(const Locale& locale, UErrorCode& status) const
47{
48    return get(locale, LocaleKey::KIND_ANY, NULL, status);
49}
50
51UObject*
52ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
53{
54    return get(locale, kind, NULL, status);
55}
56
57UObject*
58ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
59{
60    return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
61}
62
63UObject*
64ICULocaleService::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
95URegistryKey
96ICULocaleService::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
105URegistryKey
106ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
107{
108    return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
109}
110
111URegistryKey
112ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
113{
114    return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
115}
116
117URegistryKey
118ICULocaleService::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
129URegistryKey
130ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
131{
132    return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
133}
134
135URegistryKey
136ICULocaleService::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
143URegistryKey
144ICULocaleService::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
155class ServiceEnumeration : public StringEnumeration {
156private:
157    const ICULocaleService* _service;
158    int32_t _timestamp;
159    UVector _ids;
160    int32_t _pos;
161
162private:
163    ServiceEnumeration(const ICULocaleService* service, UErrorCode &status)
164        : _service(service)
165        , _timestamp(service->getTimestamp())
166        , _ids(uhash_deleteUnicodeString, NULL, status)
167        , _pos(0)
168    {
169        _service->getVisibleIDs(_ids, status);
170    }
171
172    ServiceEnumeration(const ServiceEnumeration &other, UErrorCode &status)
173        : _service(other._service)
174        , _timestamp(other._timestamp)
175        , _ids(uhash_deleteUnicodeString, 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
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
205    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
215    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
225    virtual int32_t count(UErrorCode& status) const {
226        return upToDate(status) ? _ids.size() : 0;
227    }
228
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
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
247public:
248    static UClassID U_EXPORT2 getStaticClassID(void);
249    virtual UClassID getDynamicClassID(void) const;
250};
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