53e086dc9a
X-SVN-Rev: 16193
965 lines
26 KiB
C++
965 lines
26 KiB
C++
/**
|
|
*******************************************************************************
|
|
* Copyright (C) 2001-2004, International Business Machines Corporation and *
|
|
* others. All Rights Reserved. *
|
|
*******************************************************************************
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
#include "unicode/utypes.h"
|
|
|
|
#if !UCONFIG_NO_SERVICE
|
|
|
|
#include "unicode/resbund.h"
|
|
#include "cmemory.h"
|
|
#include "iculserv.h"
|
|
#include "ustrfmt.h"
|
|
#include "uhash.h"
|
|
#include "charstr.h"
|
|
#include "uassert.h"
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
// see LocaleUtility::getAvailableLocaleNames
|
|
static Hashtable * LocaleUtility_cache = NULL;
|
|
|
|
#define UNDERSCORE_CHAR ((UChar)0x005f)
|
|
#define AT_SIGN_CHAR ((UChar)64)
|
|
#define PERIOD_CHAR ((UChar)46)
|
|
|
|
/*
|
|
******************************************************************
|
|
*/
|
|
|
|
UnicodeString&
|
|
LocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& result)
|
|
{
|
|
if (id == NULL) {
|
|
result.setToBogus();
|
|
} else {
|
|
// Fix case only (no other changes) up to the first '@' or '.' or
|
|
// end of string, whichever comes first. In 3.0 I changed this to
|
|
// stop at first '@' or '.'. It used to run out to the end of
|
|
// string. My fix makes the tests pass but is probably
|
|
// structurally incorrect. See below. [alan 3.0]
|
|
|
|
// TODO: Doug, you might want to revise this...
|
|
result = *id;
|
|
int32_t i = 0;
|
|
int32_t end = result.indexOf(AT_SIGN_CHAR);
|
|
int32_t n = result.indexOf(PERIOD_CHAR);
|
|
if (n >= 0 && n < end) {
|
|
end = n;
|
|
}
|
|
if (end < 0) {
|
|
end = result.length();
|
|
}
|
|
n = result.indexOf(UNDERSCORE_CHAR);
|
|
if (n < 0) {
|
|
n = end;
|
|
}
|
|
for (; i < n; ++i) {
|
|
UChar c = result.charAt(i);
|
|
if (c >= 0x0041 && c <= 0x005a) {
|
|
c += 0x20;
|
|
result.setCharAt(i, c);
|
|
}
|
|
}
|
|
for (n = end; i < n; ++i) {
|
|
UChar c = result.charAt(i);
|
|
if (c >= 0x0061 && c <= 0x007a) {
|
|
c -= 0x20;
|
|
result.setCharAt(i, c);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
|
|
#if 0
|
|
// This code does a proper full level 2 canonicalization of id.
|
|
// It's nasty to go from UChar to char to char to UChar -- but
|
|
// that's what you have to do to use the uloc_canonicalize
|
|
// function on UnicodeStrings.
|
|
|
|
// I ended up doing the alternate fix (see above) not for
|
|
// performance reasons, although performance will certainly be
|
|
// better, but because doing a full level 2 canonicalization
|
|
// causes some tests to fail. [alan 3.0]
|
|
|
|
// TODO: Doug, you might want to revisit this...
|
|
result.setToBogus();
|
|
if (id != 0) {
|
|
int32_t buflen = id->length() + 8; // space for NUL
|
|
char* buf = (char*) uprv_malloc(buflen);
|
|
char* canon = (buf == 0) ? 0 : (char*) uprv_malloc(buflen);
|
|
if (buf != 0 && canon != 0) {
|
|
U_ASSERT(id->extract(0, INT32_MAX, buf, buflen) < buflen);
|
|
UErrorCode ec = U_ZERO_ERROR;
|
|
uloc_canonicalize(buf, canon, buflen, &ec);
|
|
if (U_SUCCESS(ec)) {
|
|
result = UnicodeString(canon);
|
|
}
|
|
}
|
|
uprv_free(buf);
|
|
uprv_free(canon);
|
|
}
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
Locale&
|
|
LocaleUtility::initLocaleFromName(const UnicodeString& id, Locale& result)
|
|
{
|
|
enum { BUFLEN = 128 }; // larger than ever needed
|
|
|
|
if (id.isBogus() || id.length() >= BUFLEN) {
|
|
result.setToBogus();
|
|
} else {
|
|
/*
|
|
* We need to convert from a UnicodeString to char * in order to
|
|
* create a Locale.
|
|
*
|
|
* Problem: Locale ID strings may contain '@' which is a variant
|
|
* character and cannot be handled by invariant-character conversion.
|
|
*
|
|
* Hack: Since ICU code can handle locale IDs with multiple encodings
|
|
* of '@' (at least for EBCDIC; it's not known to be a problem for
|
|
* ASCII-based systems),
|
|
* we use regular invariant-character conversion for everything else
|
|
* and manually convert U+0040 into a compiler-char-constant '@'.
|
|
* While this compilation-time constant may not match the runtime
|
|
* encoding of '@', it should be one of the encodings which ICU
|
|
* recognizes.
|
|
*
|
|
* There should be only at most one '@' in a locale ID.
|
|
*/
|
|
char buffer[BUFLEN];
|
|
int32_t prev, i;
|
|
prev = 0;
|
|
for(;;) {
|
|
i = id.indexOf((UChar)0x40, prev);
|
|
if(i < 0) {
|
|
// no @ between prev and the rest of the string
|
|
id.extract(prev, INT32_MAX, buffer + prev, BUFLEN - prev, US_INV);
|
|
break; // done
|
|
} else {
|
|
// normal invariant-character conversion for text between @s
|
|
id.extract(prev, i - prev, buffer + prev, BUFLEN - prev, US_INV);
|
|
// manually "convert" U+0040 at id[i] into '@' at buffer[i]
|
|
buffer[i] = '@';
|
|
prev = i + 1;
|
|
}
|
|
}
|
|
result = Locale::createFromName(buffer);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
UnicodeString&
|
|
LocaleUtility::initNameFromLocale(const Locale& locale, UnicodeString& result)
|
|
{
|
|
if (locale.isBogus()) {
|
|
result.setToBogus();
|
|
} else {
|
|
result.append(UnicodeString(locale.getName(), -1, US_INV));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const Hashtable*
|
|
LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
|
|
{
|
|
// LocaleUtility_cache is a hash-of-hashes. The top-level keys
|
|
// are path strings ('bundleID') passed to
|
|
// ures_openAvailableLocales. The top-level values are
|
|
// second-level hashes. The second-level keys are result strings
|
|
// from ures_openAvailableLocales. The second-level values are
|
|
// garbage ((void*)1 or other random pointer).
|
|
|
|
Hashtable* cache;
|
|
umtx_lock(NULL);
|
|
cache = LocaleUtility_cache;
|
|
umtx_unlock(NULL);
|
|
|
|
if (cache == NULL) {
|
|
cache = new Hashtable();
|
|
if (cache == NULL) {
|
|
return NULL; // catastrophic failure; e.g. out of memory
|
|
}
|
|
cache->setValueDeleter(uhash_deleteHashtable);
|
|
Hashtable* h; // set this to final LocaleUtility_cache value
|
|
umtx_lock(NULL);
|
|
h = LocaleUtility_cache;
|
|
if (h == NULL) {
|
|
LocaleUtility_cache = h = cache;
|
|
cache = NULL;
|
|
}
|
|
umtx_unlock(NULL);
|
|
delete cache;
|
|
cache = h;
|
|
}
|
|
|
|
U_ASSERT(cache != NULL);
|
|
|
|
Hashtable* htp;
|
|
umtx_lock(NULL);
|
|
htp = (Hashtable*) cache->get(bundleID);
|
|
umtx_unlock(NULL);
|
|
|
|
if (htp == NULL) {
|
|
htp = new Hashtable();
|
|
if (htp) {
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
CharString cbundleID(bundleID);
|
|
const char* path = (const char*) cbundleID;
|
|
if (*path == 0) path = NULL; // empty string => NULL
|
|
UEnumeration *uenum = ures_openAvailableLocales(path, &status);
|
|
for (;;) {
|
|
const UChar* id = uenum_unext(uenum, NULL, &status);
|
|
if (id == NULL) {
|
|
break;
|
|
}
|
|
htp->put(UnicodeString(id), (void*)htp, status);
|
|
}
|
|
uenum_close(uenum);
|
|
if (U_FAILURE(status)) {
|
|
delete htp;
|
|
return NULL;
|
|
}
|
|
umtx_lock(NULL);
|
|
cache->put(bundleID, (void*)htp, status);
|
|
umtx_unlock(NULL);
|
|
}
|
|
}
|
|
return htp;
|
|
}
|
|
|
|
UBool
|
|
LocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& child)
|
|
{
|
|
return child.indexOf(root) == 0 &&
|
|
(child.length() == root.length() ||
|
|
child.charAt(root.length()) == UNDERSCORE_CHAR);
|
|
}
|
|
|
|
UBool
|
|
LocaleUtility::cleanup(void) {
|
|
if (LocaleUtility_cache) {
|
|
delete LocaleUtility_cache;
|
|
LocaleUtility_cache = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
******************************************************************
|
|
*/
|
|
|
|
const int32_t LocaleKey::KIND_ANY = -1;
|
|
|
|
LocaleKey*
|
|
LocaleKey::createWithCanonicalFallback(const UnicodeString* primaryID,
|
|
const UnicodeString* canonicalFallbackID,
|
|
UErrorCode& status)
|
|
{
|
|
return LocaleKey::createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY, status);
|
|
}
|
|
|
|
LocaleKey*
|
|
LocaleKey::createWithCanonicalFallback(const UnicodeString* primaryID,
|
|
const UnicodeString* canonicalFallbackID,
|
|
int32_t kind,
|
|
UErrorCode& status)
|
|
{
|
|
if (primaryID == NULL || U_FAILURE(status)) {
|
|
return NULL;
|
|
}
|
|
UnicodeString canonicalPrimaryID;
|
|
LocaleUtility::canonicalLocaleString(primaryID, canonicalPrimaryID);
|
|
return new LocaleKey(*primaryID, canonicalPrimaryID, canonicalFallbackID, kind);
|
|
}
|
|
|
|
LocaleKey::LocaleKey(const UnicodeString& primaryID,
|
|
const UnicodeString& canonicalPrimaryID,
|
|
const UnicodeString* canonicalFallbackID,
|
|
int32_t kind)
|
|
: ICUServiceKey(primaryID)
|
|
, _kind(kind)
|
|
, _primaryID(canonicalPrimaryID)
|
|
, _fallbackID()
|
|
, _currentID()
|
|
{
|
|
_fallbackID.setToBogus();
|
|
if (_primaryID.length() != 0) {
|
|
if (canonicalFallbackID != NULL && _primaryID != *canonicalFallbackID) {
|
|
_fallbackID = *canonicalFallbackID;
|
|
}
|
|
}
|
|
|
|
_currentID = _primaryID;
|
|
}
|
|
|
|
LocaleKey::~LocaleKey() {}
|
|
|
|
UnicodeString&
|
|
LocaleKey::prefix(UnicodeString& result) const {
|
|
if (_kind != KIND_ANY) {
|
|
UChar buffer[64];
|
|
uprv_itou(buffer, 64, _kind, 10, 0);
|
|
UnicodeString temp(buffer);
|
|
result.append(temp);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int32_t
|
|
LocaleKey::kind() const {
|
|
return _kind;
|
|
}
|
|
|
|
UnicodeString&
|
|
LocaleKey::canonicalID(UnicodeString& result) const {
|
|
return result.append(_primaryID);
|
|
}
|
|
|
|
UnicodeString&
|
|
LocaleKey::currentID(UnicodeString& result) const {
|
|
if (!_currentID.isBogus()) {
|
|
result.append(_currentID);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
UnicodeString&
|
|
LocaleKey::currentDescriptor(UnicodeString& result) const {
|
|
if (!_currentID.isBogus()) {
|
|
prefix(result).append(PREFIX_DELIMITER).append(_currentID);
|
|
} else {
|
|
result.setToBogus();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Locale&
|
|
LocaleKey::canonicalLocale(Locale& result) const {
|
|
return LocaleUtility::initLocaleFromName(_primaryID, result);
|
|
}
|
|
|
|
Locale&
|
|
LocaleKey::currentLocale(Locale& result) const {
|
|
return LocaleUtility::initLocaleFromName(_currentID, result);
|
|
}
|
|
|
|
UBool
|
|
LocaleKey::fallback() {
|
|
if (!_currentID.isBogus()) {
|
|
int x = _currentID.lastIndexOf(UNDERSCORE_CHAR);
|
|
if (x != -1) {
|
|
_currentID.remove(x); // truncate current or fallback, whichever we're pointing to
|
|
return TRUE;
|
|
}
|
|
|
|
if (!_fallbackID.isBogus()) {
|
|
_currentID = _fallbackID;
|
|
_fallbackID.setToBogus();
|
|
return TRUE;
|
|
}
|
|
|
|
if (_currentID.length() > 0) {
|
|
_currentID.remove(0); // completely truncate
|
|
return TRUE;
|
|
}
|
|
|
|
_currentID.setToBogus();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
UBool
|
|
LocaleKey::isFallbackOf(const UnicodeString& id) const {
|
|
UnicodeString temp(id);
|
|
parseSuffix(temp);
|
|
return temp.indexOf(_primaryID) == 0 &&
|
|
(temp.length() == _primaryID.length() ||
|
|
temp.charAt(_primaryID.length()) == UNDERSCORE_CHAR);
|
|
}
|
|
|
|
#ifdef SERVICE_DEBUG
|
|
UnicodeString&
|
|
LocaleKey::debug(UnicodeString& result) const
|
|
{
|
|
ICUServiceKey::debug(result);
|
|
result.append(" kind: ");
|
|
result.append(_kind);
|
|
result.append(" primaryID: ");
|
|
result.append(_primaryID);
|
|
result.append(" fallbackID: ");
|
|
result.append(_fallbackID);
|
|
result.append(" currentID: ");
|
|
result.append(_currentID);
|
|
return result;
|
|
}
|
|
|
|
UnicodeString&
|
|
LocaleKey::debugClass(UnicodeString& result) const
|
|
{
|
|
return result.append("LocaleKey ");
|
|
}
|
|
#endif
|
|
|
|
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocaleKey)
|
|
|
|
/*
|
|
******************************************************************
|
|
*/
|
|
|
|
LocaleKeyFactory::LocaleKeyFactory(int32_t coverage)
|
|
: _name()
|
|
, _coverage(coverage)
|
|
{
|
|
}
|
|
|
|
LocaleKeyFactory::LocaleKeyFactory(int32_t coverage, const UnicodeString& name)
|
|
: _name(name)
|
|
, _coverage(coverage)
|
|
{
|
|
}
|
|
|
|
LocaleKeyFactory::~LocaleKeyFactory() {
|
|
}
|
|
|
|
UObject*
|
|
LocaleKeyFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const {
|
|
if (handlesKey(key, status)) {
|
|
const LocaleKey& lkey = (const LocaleKey&)key;
|
|
int32_t kind = lkey.kind();
|
|
Locale loc;
|
|
lkey.currentLocale(loc);
|
|
|
|
return handleCreate(loc, kind, service, status);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UBool
|
|
LocaleKeyFactory::handlesKey(const ICUServiceKey& key, UErrorCode& status) const {
|
|
const Hashtable* supported = getSupportedIDs(status);
|
|
if (supported) {
|
|
UnicodeString id;
|
|
key.currentID(id);
|
|
return supported->get(id) != NULL;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
LocaleKeyFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
|
|
const Hashtable* supported = getSupportedIDs(status);
|
|
if (supported) {
|
|
UBool visible = (_coverage & 0x1) == 0;
|
|
|
|
const UHashElement* elem = NULL;
|
|
int32_t pos = 0;
|
|
while ((elem = supported->nextElement(pos)) != NULL) {
|
|
const UnicodeString& id = *((const UnicodeString*)elem->key.pointer);
|
|
if (!visible) {
|
|
result.remove(id);
|
|
} else {
|
|
result.put(id, (void*)this, status); // this is dummy non-void marker used for set semantics
|
|
if (U_FAILURE(status)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UnicodeString&
|
|
LocaleKeyFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const {
|
|
if ((_coverage & 0x1) == 0) {
|
|
//UErrorCode status = U_ZERO_ERROR;
|
|
// assume if this is called on us, we support some fallback of this id
|
|
// if (isSupportedID(id, status)) {
|
|
Locale loc;
|
|
LocaleUtility::initLocaleFromName(id, loc);
|
|
return loc.getDisplayName(locale, result);
|
|
// }
|
|
}
|
|
result.setToBogus();
|
|
return result;
|
|
}
|
|
|
|
UObject*
|
|
LocaleKeyFactory::handleCreate(const Locale& /* loc */,
|
|
int32_t /* kind */,
|
|
const ICUService* /* service */,
|
|
UErrorCode& /* status */) const {
|
|
return NULL;
|
|
}
|
|
|
|
UBool
|
|
LocaleKeyFactory::isSupportedID(const UnicodeString& id, UErrorCode& status) const {
|
|
const Hashtable* ids = getSupportedIDs(status);
|
|
return ids && ids->get(id);
|
|
}
|
|
|
|
const Hashtable*
|
|
LocaleKeyFactory::getSupportedIDs(UErrorCode& /* status */) const {
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef SERVICE_DEBUG
|
|
UnicodeString&
|
|
LocaleKeyFactory::debug(UnicodeString& result) const
|
|
{
|
|
debugClass(result);
|
|
result.append(", name: ");
|
|
result.append(_name);
|
|
result.append(", coverage: ");
|
|
result.append(_coverage);
|
|
return result;
|
|
}
|
|
|
|
UnicodeString&
|
|
LocaleKeyFactory::debugClass(UnicodeString& result) const
|
|
{
|
|
return result.append("LocaleKeyFactory");
|
|
}
|
|
#endif
|
|
|
|
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocaleKeyFactory)
|
|
|
|
/*
|
|
******************************************************************
|
|
*/
|
|
|
|
SimpleLocaleKeyFactory::SimpleLocaleKeyFactory(UObject* objToAdopt,
|
|
const UnicodeString& locale,
|
|
int32_t kind,
|
|
int32_t coverage)
|
|
: LocaleKeyFactory(coverage)
|
|
, _obj(objToAdopt)
|
|
, _id(locale)
|
|
, _kind(kind)
|
|
{
|
|
}
|
|
|
|
SimpleLocaleKeyFactory::SimpleLocaleKeyFactory(UObject* objToAdopt,
|
|
const Locale& locale,
|
|
int32_t kind,
|
|
int32_t coverage)
|
|
: LocaleKeyFactory(coverage)
|
|
, _obj(objToAdopt)
|
|
, _id()
|
|
, _kind(kind)
|
|
{
|
|
LocaleUtility::initNameFromLocale(locale, _id);
|
|
}
|
|
|
|
SimpleLocaleKeyFactory::~SimpleLocaleKeyFactory()
|
|
{
|
|
delete _obj;
|
|
_obj = NULL;
|
|
}
|
|
|
|
UObject*
|
|
SimpleLocaleKeyFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
|
|
{
|
|
if (U_SUCCESS(status)) {
|
|
const LocaleKey& lkey = (const LocaleKey&)key;
|
|
if (_kind == LocaleKey::KIND_ANY || _kind == lkey.kind()) {
|
|
UnicodeString keyID;
|
|
lkey.currentID(keyID);
|
|
if (_id == keyID) {
|
|
return service->cloneInstance(_obj);
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UBool
|
|
SimpleLocaleKeyFactory::isSupportedID(const UnicodeString& id, UErrorCode& /* status */) const
|
|
{
|
|
return id == _id;
|
|
}
|
|
|
|
void
|
|
SimpleLocaleKeyFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const
|
|
{
|
|
if (U_SUCCESS(status)) {
|
|
if (_coverage & 0x1) {
|
|
result.remove(_id);
|
|
} else {
|
|
result.put(_id, (void*)this, status);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef SERVICE_DEBUG
|
|
UnicodeString&
|
|
SimpleLocaleKeyFactory::debug(UnicodeString& result) const
|
|
{
|
|
LocaleKeyFactory::debug(result);
|
|
result.append(", id: ");
|
|
result.append(_id);
|
|
result.append(", kind: ");
|
|
result.append(_kind);
|
|
return result;
|
|
}
|
|
|
|
UnicodeString&
|
|
SimpleLocaleKeyFactory::debugClass(UnicodeString& result) const
|
|
{
|
|
return result.append("SimpleLocaleKeyFactory");
|
|
}
|
|
#endif
|
|
|
|
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleLocaleKeyFactory)
|
|
|
|
/*
|
|
******************************************************************
|
|
*/
|
|
|
|
ICUResourceBundleFactory::ICUResourceBundleFactory()
|
|
: LocaleKeyFactory(VISIBLE)
|
|
, _bundleName()
|
|
{
|
|
}
|
|
|
|
ICUResourceBundleFactory::ICUResourceBundleFactory(const UnicodeString& bundleName)
|
|
: LocaleKeyFactory(VISIBLE)
|
|
, _bundleName(bundleName)
|
|
{
|
|
}
|
|
|
|
ICUResourceBundleFactory::~ICUResourceBundleFactory() {}
|
|
|
|
const Hashtable*
|
|
ICUResourceBundleFactory::getSupportedIDs(UErrorCode& status) const
|
|
{
|
|
if (U_SUCCESS(status)) {
|
|
return LocaleUtility::getAvailableLocaleNames(_bundleName);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UObject*
|
|
ICUResourceBundleFactory::handleCreate(const Locale& loc, int32_t /* kind */, const ICUService* /* service */, UErrorCode& status) const
|
|
{
|
|
if (U_SUCCESS(status)) {
|
|
// _bundleName is a package name
|
|
// and should only contain invariant characters
|
|
char pkg[20];
|
|
int32_t length;
|
|
length=_bundleName.extract(0, INT32_MAX, pkg, (int32_t)sizeof(pkg), US_INV);
|
|
if(length>=sizeof(pkg)) {
|
|
return NULL;
|
|
}
|
|
return new ResourceBundle(pkg, loc, status);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef SERVICE_DEBUG
|
|
UnicodeString&
|
|
ICUResourceBundleFactory::debug(UnicodeString& result) const
|
|
{
|
|
LocaleKeyFactory::debug(result);
|
|
result.append(", bundle: ");
|
|
return result.append(_bundleName);
|
|
}
|
|
|
|
UnicodeString&
|
|
ICUResourceBundleFactory::debugClass(UnicodeString& result) const
|
|
{
|
|
return result.append("ICUResourceBundleFactory");
|
|
}
|
|
#endif
|
|
|
|
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUResourceBundleFactory)
|
|
|
|
/*
|
|
******************************************************************
|
|
*/
|
|
|
|
ICULocaleService::ICULocaleService()
|
|
: fallbackLocale(Locale::getDefault())
|
|
, llock(0)
|
|
{
|
|
umtx_init(&llock);
|
|
}
|
|
|
|
ICULocaleService::ICULocaleService(const UnicodeString& dname)
|
|
: ICUService(dname)
|
|
, fallbackLocale(Locale::getDefault())
|
|
, llock(0)
|
|
{
|
|
umtx_init(&llock);
|
|
}
|
|
|
|
ICULocaleService::~ICULocaleService()
|
|
{
|
|
umtx_destroy(&llock);
|
|
}
|
|
|
|
UObject*
|
|
ICULocaleService::get(const Locale& locale, UErrorCode& status) const
|
|
{
|
|
return get(locale, LocaleKey::KIND_ANY, NULL, status);
|
|
}
|
|
|
|
UObject*
|
|
ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
|
|
{
|
|
return get(locale, kind, NULL, 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 = NULL;
|
|
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 == NULL) {
|
|
result = getKey(*key, status);
|
|
} else {
|
|
UnicodeString temp;
|
|
result = getKey(*key, &temp, status);
|
|
|
|
if (result != NULL) {
|
|
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 != NULL) {
|
|
return registerFactory(factory, status);
|
|
}
|
|
delete objToAdopt;
|
|
return NULL;
|
|
}
|
|
|
|
#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 != NULL) {
|
|
return registerFactory(factory, status);
|
|
}
|
|
delete objToAdopt;
|
|
return NULL;
|
|
}
|
|
#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(uhash_deleteUnicodeString, NULL, status)
|
|
, _pos(0)
|
|
{
|
|
_service->getVisibleIDs(_ids, status);
|
|
}
|
|
|
|
ServiceEnumeration(const ServiceEnumeration &other, UErrorCode &status)
|
|
: _service(other._service)
|
|
, _timestamp(other._timestamp)
|
|
, _ids(uhash_deleteUnicodeString, NULL, status)
|
|
, _pos(0)
|
|
{
|
|
if(U_SUCCESS(status)) {
|
|
int32_t i, length;
|
|
|
|
length = other._ids.size();
|
|
for(i = 0; i < length; ++i) {
|
|
_ids.addElement(((UnicodeString *)other._ids.elementAt(i))->clone(), 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 NULL;
|
|
}
|
|
|
|
virtual ~ServiceEnumeration() {}
|
|
|
|
virtual StringEnumeration *clone() const {
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
ServiceEnumeration *cl = new ServiceEnumeration(*this, status);
|
|
if(U_FAILURE(status)) {
|
|
delete cl;
|
|
cl = NULL;
|
|
}
|
|
return cl;
|
|
}
|
|
|
|
virtual int32_t count(UErrorCode& status) const {
|
|
return upToDate(status) ? _ids.size() : 0;
|
|
}
|
|
|
|
const UnicodeString* snext(UErrorCode& status) {
|
|
if (upToDate(status) && (_pos < _ids.size())) {
|
|
return (const UnicodeString*)_ids[_pos++];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UBool upToDate(UErrorCode& status) const {
|
|
if (U_SUCCESS(status)) {
|
|
if (_timestamp == _service->getTimestamp()) {
|
|
return TRUE;
|
|
}
|
|
status = U_ENUM_OUT_OF_SYNC_ERROR;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void reset(UErrorCode& status) {
|
|
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(void);
|
|
virtual UClassID getDynamicClassID(void) const;
|
|
};
|
|
|
|
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
|
|
|
|
StringEnumeration*
|
|
ICULocaleService::getAvailableLocales(void) const
|
|
{
|
|
return ServiceEnumeration::create(this);
|
|
}
|
|
|
|
const UnicodeString&
|
|
ICULocaleService::validateFallbackLocale() const
|
|
{
|
|
const Locale& loc = Locale::getDefault();
|
|
ICULocaleService* ncThis = (ICULocaleService*)this;
|
|
{
|
|
Mutex mutex(&ncThis->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
|
|
|
|
// defined in ucln_cmn.h
|
|
|
|
/**
|
|
* Release all static memory held by Locale Utility.
|
|
*/
|
|
U_CFUNC UBool service_cleanup(void) {
|
|
return LocaleUtility::cleanup();
|
|
}
|
|
|
|
/* !UCONFIG_NO_SERVICE */
|
|
#endif
|
|
|
|
|