| 1 | // © 2016 and later: Unicode, Inc. and others. | 
|---|
| 2 | // License & terms of use: http://www.unicode.org/copyright.html | 
|---|
| 3 | /** | 
|---|
| 4 | ******************************************************************************* | 
|---|
| 5 | * Copyright (C) 2001-2014, International Business Machines Corporation and    * | 
|---|
| 6 | * 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" | 
|---|
| 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 |  | 
|---|
| 27 | U_NAMESPACE_BEGIN | 
|---|
| 28 |  | 
|---|
| 29 | ICULocaleService::ICULocaleService() | 
|---|
| 30 | : fallbackLocale(Locale::getDefault()) | 
|---|
| 31 | { | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | ICULocaleService::ICULocaleService(const UnicodeString& dname) | 
|---|
| 35 | : ICUService(dname) | 
|---|
| 36 | , fallbackLocale(Locale::getDefault()) | 
|---|
| 37 | { | 
|---|
| 38 | } | 
|---|
| 39 |  | 
|---|
| 40 | ICULocaleService::~ICULocaleService() | 
|---|
| 41 | { | 
|---|
| 42 | } | 
|---|
| 43 |  | 
|---|
| 44 | UObject* | 
|---|
| 45 | ICULocaleService::get(const Locale& locale, UErrorCode& status) const | 
|---|
| 46 | { | 
|---|
| 47 | return get(locale, LocaleKey::KIND_ANY, NULL, status); | 
|---|
| 48 | } | 
|---|
| 49 |  | 
|---|
| 50 | UObject* | 
|---|
| 51 | ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const | 
|---|
| 52 | { | 
|---|
| 53 | return get(locale, kind, NULL, status); | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | UObject* | 
|---|
| 57 | ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const | 
|---|
| 58 | { | 
|---|
| 59 | return get(locale, LocaleKey::KIND_ANY, actualReturn, status); | 
|---|
| 60 | } | 
|---|
| 61 |  | 
|---|
| 62 | UObject* | 
|---|
| 63 | ICULocaleService::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 |  | 
|---|
| 94 | URegistryKey | 
|---|
| 95 | ICULocaleService::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 |  | 
|---|
| 104 | URegistryKey | 
|---|
| 105 | ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status) | 
|---|
| 106 | { | 
|---|
| 107 | return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status); | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 | URegistryKey | 
|---|
| 111 | ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status) | 
|---|
| 112 | { | 
|---|
| 113 | return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status); | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | URegistryKey | 
|---|
| 117 | ICULocaleService::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 | 
|---|
| 128 | URegistryKey | 
|---|
| 129 | ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status) | 
|---|
| 130 | { | 
|---|
| 131 | return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status); | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | URegistryKey | 
|---|
| 135 | ICULocaleService::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 |  | 
|---|
| 142 | URegistryKey | 
|---|
| 143 | ICULocaleService::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 |  | 
|---|
| 154 | class ServiceEnumeration : public StringEnumeration { | 
|---|
| 155 | private: | 
|---|
| 156 | const ICULocaleService* _service; | 
|---|
| 157 | int32_t _timestamp; | 
|---|
| 158 | UVector _ids; | 
|---|
| 159 | int32_t _pos; | 
|---|
| 160 |  | 
|---|
| 161 | private: | 
|---|
| 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 |  | 
|---|
| 191 | public: | 
|---|
| 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 |  | 
|---|
| 246 | public: | 
|---|
| 247 | static UClassID U_EXPORT2 getStaticClassID(void); | 
|---|
| 248 | virtual UClassID getDynamicClassID(void) const; | 
|---|
| 249 | }; | 
|---|
| 250 |  | 
|---|
| 251 | ServiceEnumeration::~ServiceEnumeration() {} | 
|---|
| 252 |  | 
|---|
| 253 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration) | 
|---|
| 254 |  | 
|---|
| 255 | StringEnumeration* | 
|---|
| 256 | ICULocaleService::getAvailableLocales(void) const | 
|---|
| 257 | { | 
|---|
| 258 | return ServiceEnumeration::create(this); | 
|---|
| 259 | } | 
|---|
| 260 |  | 
|---|
| 261 | const UnicodeString& | 
|---|
| 262 | ICULocaleService::validateFallbackLocale() const | 
|---|
| 263 | { | 
|---|
| 264 | const Locale&     loc    = Locale::getDefault(); | 
|---|
| 265 | ICULocaleService* ncThis = (ICULocaleService*)this; | 
|---|
| 266 | static UMutex llock; | 
|---|
| 267 | { | 
|---|
| 268 | Mutex mutex(&llock); | 
|---|
| 269 | if (loc != fallbackLocale) { | 
|---|
| 270 | ncThis->fallbackLocale = loc; | 
|---|
| 271 | LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName); | 
|---|
| 272 | ncThis->clearServiceCache(); | 
|---|
| 273 | } | 
|---|
| 274 | } | 
|---|
| 275 | return fallbackLocaleName; | 
|---|
| 276 | } | 
|---|
| 277 |  | 
|---|
| 278 | ICUServiceKey* | 
|---|
| 279 | ICULocaleService::createKey(const UnicodeString* id, UErrorCode& status) const | 
|---|
| 280 | { | 
|---|
| 281 | return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), status); | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 | ICUServiceKey* | 
|---|
| 285 | ICULocaleService::createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const | 
|---|
| 286 | { | 
|---|
| 287 | return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), kind, status); | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | U_NAMESPACE_END | 
|---|
| 291 |  | 
|---|
| 292 | /* !UCONFIG_NO_SERVICE */ | 
|---|
| 293 | #endif | 
|---|
| 294 |  | 
|---|
| 295 |  | 
|---|
| 296 |  | 
|---|