#include "unicode/utypes.h"
#if !UCONFIG_NO_SERVICE
#include "unicode/resbund.h"
#include "uresimp.h"
#include "cmemory.h"
#include "servloc.h"
#include "ustrfmt.h"
#include "charstr.h"
#include "uassert.h"
#define UNDERSCORE_CHAR …
#define AT_SIGN_CHAR …
#define PERIOD_CHAR …
U_NAMESPACE_BEGIN
ICULocaleService::ICULocaleService()
: fallbackLocale(Locale::getDefault())
{
}
ICULocaleService::ICULocaleService(const UnicodeString& dname)
: ICUService(dname)
, fallbackLocale(Locale::getDefault())
{
}
ICULocaleService::~ICULocaleService()
{
}
UObject*
ICULocaleService::get(const Locale& locale, UErrorCode& status) const
{
return get(locale, LocaleKey::KIND_ANY, nullptr, status);
}
UObject*
ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
{
return get(locale, kind, nullptr, status);
}
UObject*
ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
{
return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
}
UObject*
ICULocaleService::get(const Locale& locale, int32_t kind, Locale* actualReturn, UErrorCode& status) const
{
UObject* result = nullptr;
if (U_FAILURE(status)) {
return result;
}
UnicodeString locName(locale.getName(), -1, US_INV);
if (locName.isBogus()) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
ICUServiceKey* key = createKey(&locName, kind, status);
if (key) {
if (actualReturn == nullptr) {
result = getKey(*key, status);
} else {
UnicodeString temp;
result = getKey(*key, &temp, status);
if (result != nullptr) {
key->parseSuffix(temp);
LocaleUtility::initLocaleFromName(temp, *actualReturn);
}
}
delete key;
}
}
return result;
}
URegistryKey
ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale,
UBool visible, UErrorCode& status)
{
Locale loc;
LocaleUtility::initLocaleFromName(locale, loc);
return registerInstance(objToAdopt, loc, LocaleKey::KIND_ANY,
visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE, status);
}
URegistryKey
ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
{
return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
}
URegistryKey
ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
{
return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
}
URegistryKey
ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, int32_t coverage, UErrorCode& status)
{
ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
if (factory != nullptr) {
return registerFactory(factory, status);
}
delete objToAdopt;
return nullptr;
}
#if 0
URegistryKey
ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
{
return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
}
URegistryKey
ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UBool visible, UErrorCode& status)
{
return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY,
visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE,
status);
}
URegistryKey
ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, int32_t kind, int32_t coverage, UErrorCode& status)
{
ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
if (factory != nullptr) {
return registerFactory(factory, status);
}
delete objToAdopt;
return nullptr;
}
#endif
class ServiceEnumeration : public StringEnumeration {
private:
const ICULocaleService* _service;
int32_t _timestamp;
UVector _ids;
int32_t _pos;
private:
ServiceEnumeration(const ICULocaleService* service, UErrorCode &status)
: _service(service)
, _timestamp(service->getTimestamp())
, _ids(uprv_deleteUObject, nullptr, status)
, _pos(0)
{
_service->getVisibleIDs(_ids, status);
}
ServiceEnumeration(const ServiceEnumeration &other, UErrorCode &status)
: _service(other._service)
, _timestamp(other._timestamp)
, _ids(uprv_deleteUObject, nullptr, status)
, _pos(0)
{
if(U_SUCCESS(status)) {
int32_t i, length;
length = other._ids.size();
for(i = 0; i < length; ++i) {
LocalPointer<UnicodeString> clonedId(static_cast<UnicodeString*>(other._ids.elementAt(i))->clone(), status);
_ids.adoptElement(clonedId.orphan(), status);
}
if(U_SUCCESS(status)) {
_pos = other._pos;
}
}
}
public:
static ServiceEnumeration* create(const ICULocaleService* service) {
UErrorCode status = U_ZERO_ERROR;
ServiceEnumeration* result = new ServiceEnumeration(service, status);
if (U_SUCCESS(status)) {
return result;
}
delete result;
return nullptr;
}
virtual ~ServiceEnumeration();
virtual StringEnumeration *clone() const override {
UErrorCode status = U_ZERO_ERROR;
ServiceEnumeration *cl = new ServiceEnumeration(*this, status);
if(U_FAILURE(status)) {
delete cl;
cl = nullptr;
}
return cl;
}
UBool upToDate(UErrorCode& status) const {
if (U_SUCCESS(status)) {
if (_timestamp == _service->getTimestamp()) {
return true;
}
status = U_ENUM_OUT_OF_SYNC_ERROR;
}
return false;
}
virtual int32_t count(UErrorCode& status) const override {
return upToDate(status) ? _ids.size() : 0;
}
virtual const UnicodeString* snext(UErrorCode& status) override {
if (upToDate(status) && (_pos < _ids.size())) {
return static_cast<const UnicodeString*>(_ids[_pos++]);
}
return nullptr;
}
virtual void reset(UErrorCode& status) override {
if (status == U_ENUM_OUT_OF_SYNC_ERROR) {
status = U_ZERO_ERROR;
}
if (U_SUCCESS(status)) {
_timestamp = _service->getTimestamp();
_pos = 0;
_service->getVisibleIDs(_ids, status);
}
}
public:
static UClassID U_EXPORT2 getStaticClassID();
virtual UClassID getDynamicClassID() const override;
};
ServiceEnumeration::~ServiceEnumeration() {}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
StringEnumeration*
ICULocaleService::getAvailableLocales() const
{
return ServiceEnumeration::create(this);
}
const UnicodeString&
ICULocaleService::validateFallbackLocale() const
{
const Locale& loc = Locale::getDefault();
ICULocaleService* ncThis = const_cast<ICULocaleService*>(this);
static UMutex llock;
{
Mutex mutex(&llock);
if (loc != fallbackLocale) {
ncThis->fallbackLocale = loc;
LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
ncThis->clearServiceCache();
}
}
return fallbackLocaleName;
}
ICUServiceKey*
ICULocaleService::createKey(const UnicodeString* id, UErrorCode& status) const
{
return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), status);
}
ICUServiceKey*
ICULocaleService::createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const
{
return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), kind, status);
}
U_NAMESPACE_END
#endif