Home | History | Annotate | Download | only in common
      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 static UMutex llock = U_MUTEX_INITIALIZER;
     30 ICULocaleService::ICULocaleService()
     31   : fallbackLocale(Locale::getDefault())
     32 {
     33 }
     34 
     35 ICULocaleService::ICULocaleService(const UnicodeString& dname)
     36   : ICUService(dname)
     37   , fallbackLocale(Locale::getDefault())
     38 {
     39 }
     40 
     41 ICULocaleService::~ICULocaleService()
     42 {
     43 }
     44 
     45 UObject*
     46 ICULocaleService::get(const Locale& locale, UErrorCode& status) const
     47 {
     48     return get(locale, LocaleKey::KIND_ANY, NULL, status);
     49 }
     50 
     51 UObject*
     52 ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
     53 {
     54     return get(locale, kind, NULL, status);
     55 }
     56 
     57 UObject*
     58 ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
     59 {
     60     return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
     61 }
     62 
     63 UObject*
     64 ICULocaleService::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 
     95 URegistryKey
     96 ICULocaleService::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 
    105 URegistryKey
    106 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
    107 {
    108     return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
    109 }
    110 
    111 URegistryKey
    112 ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
    113 {
    114     return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
    115 }
    116 
    117 URegistryKey
    118 ICULocaleService::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
    129 URegistryKey
    130 ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
    131 {
    132     return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
    133 }
    134 
    135 URegistryKey
    136 ICULocaleService::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 
    143 URegistryKey
    144 ICULocaleService::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 
    155 class ServiceEnumeration : public StringEnumeration {
    156 private:
    157     const ICULocaleService* _service;
    158     int32_t _timestamp;
    159     UVector _ids;
    160     int32_t _pos;
    161 
    162 private:
    163     ServiceEnumeration(const ICULocaleService* service, UErrorCode &status)
    164         : _service(service)
    165         , _timestamp(service->getTimestamp())
    166         , _ids(uprv_deleteUObject, 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(uprv_deleteUObject, 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 
    192 public:
    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 
    247 public:
    248     static UClassID U_EXPORT2 getStaticClassID(void);
    249     virtual UClassID getDynamicClassID(void) const;
    250 };
    251 
    252 ServiceEnumeration::~ServiceEnumeration() {}
    253 
    254 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
    255 
    256 StringEnumeration*
    257 ICULocaleService::getAvailableLocales(void) const
    258 {
    259     return ServiceEnumeration::create(this);
    260 }
    261 
    262 const UnicodeString&
    263 ICULocaleService::validateFallbackLocale() const
    264 {
    265     const Locale&     loc    = Locale::getDefault();
    266     ICULocaleService* ncThis = (ICULocaleService*)this;
    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