ICU-6444 Modified the code not to depend on gUStringTable. Instead, use the data in resource directly.
X-SVN-Rev: 27554
This commit is contained in:
parent
3ea9a0e230
commit
d8db690e28
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* Copyright (C) 1997-2009, International Business Machines Corporation and *
|
* Copyright (C) 1997-2010, International Business Machines Corporation and *
|
||||||
* others. All Rights Reserved. *
|
* others. All Rights Reserved. *
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
*
|
*
|
||||||
@ -1088,29 +1088,45 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
|
|||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
||||||
UnicodeString&
|
// These two methods are used by ZoneMeta class only.
|
||||||
TimeZone::dereferOlsonLink(const UnicodeString& linkTo, UnicodeString& linkFrom) {
|
|
||||||
|
const UChar*
|
||||||
|
TimeZone::dereferOlsonLink(const UnicodeString& id) {
|
||||||
|
const UChar *result = NULL;
|
||||||
UErrorCode ec = U_ZERO_ERROR;
|
UErrorCode ec = U_ZERO_ERROR;
|
||||||
linkFrom.remove();
|
UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
|
||||||
UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
|
|
||||||
UResourceBundle *res = getZoneByName(top, linkTo, NULL, ec);
|
// resolve zone index by name
|
||||||
|
UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec);
|
||||||
|
int32_t idx = findInStringArray(names, id, ec);
|
||||||
|
result = ures_getStringByIndex(names, idx, NULL, &ec);
|
||||||
|
|
||||||
|
// open the zone bundle by index
|
||||||
|
ures_getByKey(rb, kZONES, rb, &ec);
|
||||||
|
ures_getByIndex(rb, idx, rb, &ec);
|
||||||
|
|
||||||
if (U_SUCCESS(ec)) {
|
if (U_SUCCESS(ec)) {
|
||||||
if (ures_getSize(res) == 1) {
|
if (ures_getSize(rb) == 1) {
|
||||||
int32_t deref = ures_getInt(res, &ec);
|
// this is a link - dereference the link
|
||||||
UResourceBundle *nres = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Names section
|
int32_t deref = ures_getInt(rb, &ec);
|
||||||
int32_t len;
|
const UChar* tmp = ures_getStringByIndex(names, deref, NULL, &ec);
|
||||||
const UChar* tmp = ures_getStringByIndex(nres, deref, &len, &ec);
|
|
||||||
if (U_SUCCESS(ec)) {
|
if (U_SUCCESS(ec)) {
|
||||||
linkFrom.setTo(tmp, len);
|
result = tmp;
|
||||||
}
|
}
|
||||||
ures_close(nres);
|
|
||||||
} else {
|
|
||||||
linkFrom.setTo(linkTo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ures_close(res);
|
|
||||||
ures_close(top);
|
ures_close(names);
|
||||||
return linkFrom;
|
ures_close(rb);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UResourceBundle*
|
||||||
|
TimeZone::getIDArray(UErrorCode& status) {
|
||||||
|
UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &status);
|
||||||
|
ures_getByKey(rb, kNAMES, rb, &status);
|
||||||
|
return rb;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
@ -746,12 +746,14 @@ private:
|
|||||||
* Resolve a link in Olson tzdata. When the given id is known and it's not a link,
|
* Resolve a link in Olson tzdata. When the given id is known and it's not a link,
|
||||||
* the id itself is returned. When the given id is known and it is a link, then
|
* the id itself is returned. When the given id is known and it is a link, then
|
||||||
* dereferenced zone id is returned. When the given id is unknown, then it returns
|
* dereferenced zone id is returned. When the given id is unknown, then it returns
|
||||||
* empty string.
|
* NULL.
|
||||||
* @param linkTo Input zone id string
|
* @param id Receives the dereferenced zone id string
|
||||||
* @param linkFrom Receives the dereferenced zone id string
|
* @return the dereferenced zone or NULL
|
||||||
* @return The reference to the result (linkFrom)
|
|
||||||
*/
|
*/
|
||||||
static UnicodeString& dereferOlsonLink(const UnicodeString& linkTo, UnicodeString& linkFrom);
|
static const UChar* dereferOlsonLink(const UnicodeString& id);
|
||||||
|
|
||||||
|
/* Retuns a resource bundle array contains all time zone IDs. This is only used by ZoneMeta class. */
|
||||||
|
static UResourceBundle* getIDArray(UErrorCode& status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the given custom time zone identifier
|
* Parses the given custom time zone identifier
|
||||||
|
@ -28,85 +28,9 @@ static UHashtable *gCanonicalMap = NULL;
|
|||||||
static UHashtable *gOlsonToMeta = NULL;
|
static UHashtable *gOlsonToMeta = NULL;
|
||||||
static UBool gCanonicalMapInitialized = FALSE;
|
static UBool gCanonicalMapInitialized = FALSE;
|
||||||
static UBool gOlsonToMetaInitialized = FALSE;
|
static UBool gOlsonToMetaInitialized = FALSE;
|
||||||
static UChar **gUStringTable = NULL;
|
|
||||||
static int32_t gUStringCount = 0;
|
|
||||||
static int32_t gUStringAlloc = 0;
|
|
||||||
|
|
||||||
// Currently (ICU 4.1.3+), gUStringTable only contains strings allocated in the section of
|
|
||||||
// createCanonicalMap that iterates over the enumerator created with TimeZone::createEnumeration.
|
|
||||||
// And currently, that allocates a total of 22 strings. So USTRING_ALLOC_START is defined to
|
|
||||||
// be adequate for that set, and USTRING_ALLOC_INCR is a reasonable expansion increment. In
|
|
||||||
// future versions of ICU, these numbers may need adjusting to avoid excessive reallocs, or to
|
|
||||||
// avoid allocating unused memory (but in any case the effects are small).
|
|
||||||
#define USTRING_ALLOC_START 24
|
|
||||||
#define USTRING_ALLOC_INCR 12
|
|
||||||
|
|
||||||
U_CDECL_BEGIN
|
U_CDECL_BEGIN
|
||||||
|
|
||||||
// We have switched CanonicalMap to use const UChar* strings for the key and for the id field of
|
|
||||||
// CanonicalMapEntry; that is because for the most part these now point into UChar strings in the
|
|
||||||
// shared data file, in order to reduce process-specific dynamically-allocated memory. Consequently,
|
|
||||||
// there is no longer a deleter for the key field, and the deleter for CanonicalMapEntry
|
|
||||||
// no longer frees the id field. However, for the few strings that are obtained from the
|
|
||||||
// TimeZone::createEnumeration() enumerator or from TimeZone::dereferOlsonLink instead of the
|
|
||||||
// data file, we do need to allocate copies. In order to ensure that these strings are freed by
|
|
||||||
// zoneMeta_cleanup(), we need to create a little memory manager for them; this is in the form of
|
|
||||||
// a table that tracks the strings allocated for this purpose. The following three functions
|
|
||||||
// (along with the gUStringXxxxx statics) are used to allocate and free such strings.
|
|
||||||
|
|
||||||
// The following allocs space for a UChar* string of the specified length, puts a pointer to the string
|
|
||||||
// in gUStringTable, and returns either a pointer to the allocated string space, or NULL for failure.
|
|
||||||
static UChar * allocUStringInTable(int32_t uStringLen) {
|
|
||||||
UChar * uStringSpace = NULL;
|
|
||||||
// initialize the table if necessary
|
|
||||||
umtx_lock(&gZoneMetaLock);
|
|
||||||
if (gUStringTable == NULL) {
|
|
||||||
gUStringTable = (UChar**)uprv_malloc(USTRING_ALLOC_START*sizeof(UChar*));
|
|
||||||
if (gUStringTable != NULL) {
|
|
||||||
gUStringAlloc = USTRING_ALLOC_START;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (gUStringTable != NULL) {
|
|
||||||
// expand the table if necessary
|
|
||||||
if (gUStringCount == gUStringAlloc) {
|
|
||||||
UChar ** newTable = (UChar**)uprv_realloc(gUStringTable, (gUStringAlloc+USTRING_ALLOC_INCR)*sizeof(UChar*));
|
|
||||||
if (newTable != NULL) {
|
|
||||||
gUStringTable = newTable;
|
|
||||||
gUStringAlloc += USTRING_ALLOC_INCR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add the string if possible
|
|
||||||
if (gUStringCount < gUStringAlloc) {
|
|
||||||
uStringSpace = (UChar*)uprv_malloc(uStringLen*sizeof(UChar));
|
|
||||||
if (uStringSpace != NULL) {
|
|
||||||
gUStringTable[gUStringCount++] = uStringSpace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
umtx_unlock(&gZoneMetaLock);
|
|
||||||
return uStringSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void removeLastUStringFromTable(void) {
|
|
||||||
umtx_lock(&gZoneMetaLock);
|
|
||||||
if (gUStringCount > 0) {
|
|
||||||
free(gUStringTable[--gUStringCount]);
|
|
||||||
}
|
|
||||||
umtx_unlock(&gZoneMetaLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void freeUStringTable(void) {
|
|
||||||
int32_t uStringCount = gUStringCount;
|
|
||||||
gUStringCount = 0;
|
|
||||||
gUStringAlloc = 0;
|
|
||||||
if (gUStringTable != NULL) {
|
|
||||||
while (uStringCount > 0) {
|
|
||||||
free(gUStringTable[--uStringCount]);
|
|
||||||
}
|
|
||||||
free(gUStringTable);
|
|
||||||
gUStringTable = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup callback func
|
* Cleanup callback func
|
||||||
@ -127,8 +51,6 @@ static UBool U_CALLCONV zoneMeta_cleanup(void)
|
|||||||
}
|
}
|
||||||
gOlsonToMetaInitialized = FALSE;
|
gOlsonToMetaInitialized = FALSE;
|
||||||
|
|
||||||
freeUStringTable();
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +94,6 @@ U_CDECL_END
|
|||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
#define ZID_KEY_MAX 128
|
#define ZID_KEY_MAX 128
|
||||||
static const char gZoneStringsTag[] = "zoneStrings";
|
|
||||||
static const char gUseMetazoneTag[] = "um";
|
|
||||||
|
|
||||||
static const char gSupplementalData[] = "supplementalData";
|
static const char gSupplementalData[] = "supplementalData";
|
||||||
static const char gMapTimezonesTag[] = "mapTimezones";
|
static const char gMapTimezonesTag[] = "mapTimezones";
|
||||||
static const char gZoneFormattingTag[] = "zoneFormatting";
|
static const char gZoneFormattingTag[] = "zoneFormatting";
|
||||||
@ -186,9 +105,6 @@ static const char gMultizoneTag[] = "multizone";
|
|||||||
static const char gMetaZones[] = "metaZones";
|
static const char gMetaZones[] = "metaZones";
|
||||||
static const char gMetazoneInfo[] = "metazoneInfo";
|
static const char gMetazoneInfo[] = "metazoneInfo";
|
||||||
|
|
||||||
static const char gWorldChar[] = "001";
|
|
||||||
#define WORLD_LEN 3
|
|
||||||
|
|
||||||
static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
|
static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
|
||||||
|
|
||||||
static const UChar gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31,
|
static const UChar gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31,
|
||||||
@ -282,8 +198,7 @@ ZoneMeta::createCanonicalMap(void) {
|
|||||||
UResourceBundle *tzitem = NULL;
|
UResourceBundle *tzitem = NULL;
|
||||||
UResourceBundle *aliases = NULL;
|
UResourceBundle *aliases = NULL;
|
||||||
|
|
||||||
StringEnumeration* tzenum = NULL;
|
UResourceBundle *idArray = NULL;
|
||||||
int32_t numZones;
|
|
||||||
|
|
||||||
canonicalMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
|
canonicalMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
@ -382,35 +297,34 @@ ZoneMeta::createCanonicalMap(void) {
|
|||||||
// Also, when we update Olson tzdata, new zones may be added.
|
// Also, when we update Olson tzdata, new zones may be added.
|
||||||
// This code scans all available zones in zoneinfo.res, and if any of them are
|
// This code scans all available zones in zoneinfo.res, and if any of them are
|
||||||
// missing, add them to the map.
|
// missing, add them to the map.
|
||||||
tzenum = TimeZone::createEnumeration();
|
idArray = TimeZone::getIDArray(status);
|
||||||
numZones = tzenum->count(status);
|
|
||||||
if (U_SUCCESS(status)) {
|
if (U_SUCCESS(status)) {
|
||||||
|
const UChar *zone;
|
||||||
|
int32_t numZones = ures_getSize(idArray);
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
UnicodeString zoneStr;
|
||||||
for (i = 0; i < numZones; i++) {
|
for (i = 0; i < numZones; i++) {
|
||||||
const UnicodeString *zone = tzenum->snext(status);
|
zone = ures_getStringByIndex(idArray, i, NULL, &status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
// We should not get here.
|
// ignore this
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
UChar zoneUChars[ZID_KEY_MAX];
|
CanonicalMapEntry *entry = (CanonicalMapEntry*)uhash_get(canonicalMap, zone);
|
||||||
int32_t zoneUCharsLen = zone->extract(zoneUChars, ZID_KEY_MAX, status) + 1; // Add one for NUL termination
|
|
||||||
if (U_FAILURE(status) || status==U_STRING_NOT_TERMINATED_WARNING) {
|
|
||||||
status = U_ZERO_ERROR;
|
|
||||||
continue; // zone id is too long to extract
|
|
||||||
}
|
|
||||||
CanonicalMapEntry *entry = (CanonicalMapEntry*)uhash_get(canonicalMap, zoneUChars);
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
// Already included in CLDR data
|
// Already included in CLDR data
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zoneStr.setTo(zone, -1);
|
||||||
|
|
||||||
// Not in CLDR data, but it could be new one whose alias is available
|
// Not in CLDR data, but it could be new one whose alias is available
|
||||||
// in CLDR.
|
// in CLDR.
|
||||||
int32_t nTzdataEquivalent = TimeZone::countEquivalentIDs(*zone);
|
int32_t nTzdataEquivalent = TimeZone::countEquivalentIDs(zoneStr);
|
||||||
int32_t j;
|
int32_t j;
|
||||||
for (j = 0; j < nTzdataEquivalent; j++) {
|
for (j = 0; j < nTzdataEquivalent; j++) {
|
||||||
UnicodeString alias = TimeZone::getEquivalentID(*zone, j);
|
UnicodeString alias = TimeZone::getEquivalentID(zoneStr, j);
|
||||||
if (alias == *zone) {
|
if (alias == zoneStr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
UChar aliasUChars[ZID_KEY_MAX];
|
UChar aliasUChars[ZID_KEY_MAX];
|
||||||
@ -426,33 +340,20 @@ ZoneMeta::createCanonicalMap(void) {
|
|||||||
}
|
}
|
||||||
// Create a new map entry
|
// Create a new map entry
|
||||||
CanonicalMapEntry* newEntry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry));
|
CanonicalMapEntry* newEntry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry));
|
||||||
int32_t idLen;
|
|
||||||
if (newEntry == NULL) {
|
if (newEntry == NULL) {
|
||||||
status = U_MEMORY_ALLOCATION_ERROR;
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
goto error_cleanup;
|
goto error_cleanup;
|
||||||
}
|
}
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
// Set dereferenced zone ID as the canonical ID
|
// Set dereferenced zone ID as the canonical ID
|
||||||
UnicodeString derefZone;
|
const UChar* derefZone = TimeZone::dereferOlsonLink(zoneStr);
|
||||||
TimeZone::dereferOlsonLink(*zone, derefZone);
|
if (derefZone == NULL) {
|
||||||
if (derefZone.length() == 0) {
|
// it should never happen..
|
||||||
// It should never happen.. but just in case
|
delete newEntry;
|
||||||
derefZone = *zone;
|
continue;
|
||||||
}
|
|
||||||
idLen = derefZone.length() + 1;
|
|
||||||
newEntry->id = allocUStringInTable(idLen);
|
|
||||||
if (newEntry->id == NULL) {
|
|
||||||
status = U_MEMORY_ALLOCATION_ERROR;
|
|
||||||
uprv_free(newEntry);
|
|
||||||
goto error_cleanup;
|
|
||||||
}
|
|
||||||
// Copy NULL terminated string
|
|
||||||
derefZone.extract((UChar*)(newEntry->id), idLen, status);
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
removeLastUStringFromTable();
|
|
||||||
uprv_free(newEntry);
|
|
||||||
goto error_cleanup;
|
|
||||||
}
|
}
|
||||||
|
newEntry->id = derefZone;
|
||||||
|
|
||||||
// No territory information available
|
// No territory information available
|
||||||
newEntry->country = NULL;
|
newEntry->country = NULL;
|
||||||
} else {
|
} else {
|
||||||
@ -461,15 +362,9 @@ ZoneMeta::createCanonicalMap(void) {
|
|||||||
newEntry->country = entry->country;
|
newEntry->country = entry->country;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put this entry in the hashtable
|
// Put this entry in the hashtable.
|
||||||
UChar *key = allocUStringInTable(zoneUCharsLen);
|
// key is treated as const, but must be passed as non-const.
|
||||||
if (key == NULL) {
|
uhash_put(canonicalMap, (UChar*)zone, newEntry, &status);
|
||||||
status = U_MEMORY_ALLOCATION_ERROR;
|
|
||||||
deleteCanonicalMapEntry(newEntry);
|
|
||||||
goto error_cleanup;
|
|
||||||
}
|
|
||||||
u_strncpy(key, zoneUChars, zoneUCharsLen);
|
|
||||||
uhash_put(canonicalMap, key, newEntry, &status);
|
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
goto error_cleanup;
|
goto error_cleanup;
|
||||||
}
|
}
|
||||||
@ -480,7 +375,7 @@ normal_cleanup:
|
|||||||
ures_close(aliases);
|
ures_close(aliases);
|
||||||
ures_close(tzitem);
|
ures_close(tzitem);
|
||||||
ures_close(zoneFormatting);
|
ures_close(zoneFormatting);
|
||||||
delete tzenum;
|
ures_close(idArray);
|
||||||
return canonicalMap;
|
return canonicalMap;
|
||||||
|
|
||||||
error_cleanup:
|
error_cleanup:
|
||||||
|
Loading…
Reference in New Issue
Block a user