ICU-8451 Fix memory leaks in region implementation
X-SVN-Rev: 33054
This commit is contained in:
parent
7aa5b16036
commit
734cb70cc4
@ -24,23 +24,62 @@
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/ures.h"
|
||||
#include "unicode/decimfmt.h"
|
||||
#include "ucln_in.h"
|
||||
#include "cstring.h"
|
||||
#include "uhash.h"
|
||||
#include "umutex.h"
|
||||
#include "uresimp.h"
|
||||
#include "region_impl.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
static UMutex gRegionDataLock = U_MUTEX_INITIALIZER;
|
||||
static UBool regionDataIsLoaded = false;
|
||||
static UVector* regions = NULL;
|
||||
static UVector* availableRegions[URGN_LIMIT];
|
||||
|
||||
static UHashtable *regionAliases;
|
||||
static UHashtable *regionIDMap;
|
||||
static UHashtable *numericCodeMap;
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
static void U_CALLCONV
|
||||
deleteRegion(void *obj) {
|
||||
delete (icu::Region *)obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup callback func
|
||||
*/
|
||||
static UBool U_CALLCONV region_cleanup(void)
|
||||
{
|
||||
for (int32_t i = 0 ; i < URGN_LIMIT ; i++ ) {
|
||||
if ( availableRegions[i] ) {
|
||||
delete availableRegions[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (regionAliases) {
|
||||
uhash_close(regionAliases);
|
||||
}
|
||||
|
||||
if (numericCodeMap) {
|
||||
uhash_close(numericCodeMap);
|
||||
}
|
||||
|
||||
if (regionIDMap) {
|
||||
uhash_close(regionIDMap);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U_CDECL_END
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
static UnicodeString UNKNOWN_REGION_ID = UNICODE_STRING_SIMPLE("ZZ");
|
||||
static UnicodeString OUTLYING_OCEANIA_REGION_ID = UNICODE_STRING_SIMPLE("QO");
|
||||
static UnicodeString WORLD_ID = UNICODE_STRING_SIMPLE("001");
|
||||
@ -48,24 +87,6 @@ static UnicodeString WORLD_ID = UNICODE_STRING_SIMPLE("001");
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Region)
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegionNameEnumeration)
|
||||
|
||||
void addRegion( Region *r ) {
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
if ( regions == NULL ) {
|
||||
regions = new UVector(NULL, NULL, status);
|
||||
}
|
||||
regions->addElement(r,status);
|
||||
}
|
||||
|
||||
void addAvailableRegion( const Region *r , URegionType type) {
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
if ( availableRegions[type] == NULL ) {
|
||||
availableRegions[type] = new UVector(NULL, uhash_compareChars, status);
|
||||
}
|
||||
|
||||
availableRegions[type]->addElement((void *)r->getRegionCode(),status);
|
||||
}
|
||||
/*
|
||||
* Initializes the region data from the ICU resource bundles. The region data
|
||||
* contains the basic relationships such as which regions are known, what the numeric
|
||||
@ -79,7 +100,15 @@ void Region::loadRegionData() {
|
||||
if (regionDataIsLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
umtx_lock(&gRegionDataLock);
|
||||
|
||||
if (regionDataIsLoaded) { // In case another thread gets to it before we do...
|
||||
umtx_unlock(&gRegionDataLock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
UResourceBundle* regionCodes = NULL;
|
||||
@ -92,10 +121,14 @@ void Region::loadRegionData() {
|
||||
DecimalFormat *df = new DecimalFormat(status);
|
||||
df->setParseIntegerOnly(TRUE);
|
||||
|
||||
regionAliases = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status);
|
||||
regionIDMap = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status);
|
||||
uhash_setValueDeleter(regionIDMap, deleteRegion);
|
||||
|
||||
numericCodeMap = uhash_open(uhash_hashLong,uhash_compareLong,NULL,&status);
|
||||
|
||||
regionAliases = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status);
|
||||
uhash_setKeyDeleter(regionAliases,uprv_deleteUObject);
|
||||
|
||||
UResourceBundle *rb = ures_openDirect(NULL,"metadata",&status);
|
||||
regionCodes = ures_getByKey(rb,"regionCodes",NULL,&status);
|
||||
territoryAlias = ures_getByKey(rb,"territoryAlias",NULL,&status);
|
||||
@ -138,7 +171,6 @@ void Region::loadRegionData() {
|
||||
} else {
|
||||
r->code = Region::UNDEFINED_NUMERIC_CODE;
|
||||
}
|
||||
addRegion(r);
|
||||
}
|
||||
|
||||
|
||||
@ -171,13 +203,12 @@ void Region::loadRegionData() {
|
||||
aliasFromRegion->code = Region::UNDEFINED_NUMERIC_CODE;
|
||||
}
|
||||
aliasFromRegion->type = URGN_DEPRECATED;
|
||||
addRegion(aliasFromRegion);
|
||||
} else {
|
||||
aliasFromRegion->type = URGN_DEPRECATED;
|
||||
}
|
||||
delete aliasFromStr;
|
||||
|
||||
aliasFromRegion->preferredValues = new UVector(NULL, uhash_compareChars, status);
|
||||
aliasFromRegion->preferredValues = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
|
||||
UnicodeString currentRegion;
|
||||
currentRegion.remove();
|
||||
for (int32_t i = 0 ; i < aliasTo.length() ; i++ ) {
|
||||
@ -187,7 +218,8 @@ void Region::loadRegionData() {
|
||||
if ( aliasTo.charAt(i) == 0x0020 || i+1 == aliasTo.length() ) {
|
||||
Region *target = (Region *)uhash_get(regionIDMap,(void *)¤tRegion);
|
||||
if (target) {
|
||||
aliasFromRegion->preferredValues->addElement((void *)target->id,status);
|
||||
UnicodeString *preferredValue = new UnicodeString(target->idStr);
|
||||
aliasFromRegion->preferredValues->addElement((void *)preferredValue,status);
|
||||
}
|
||||
currentRegion.remove();
|
||||
}
|
||||
@ -269,9 +301,12 @@ void Region::loadRegionData() {
|
||||
|
||||
// Add the child region to the set of regions contained by the parent
|
||||
if (parentRegion->containedRegions == NULL) {
|
||||
parentRegion->containedRegions = new UVector(NULL, uhash_compareChars, status);
|
||||
parentRegion->containedRegions = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
|
||||
}
|
||||
parentRegion->containedRegions->addElement((void *)childRegion->id,status);
|
||||
|
||||
UnicodeString *childStr = new UnicodeString(status);
|
||||
childStr->fastCopyFrom(childRegion->idStr);
|
||||
parentRegion->containedRegions->addElement((void *)childStr,status);
|
||||
|
||||
// Set the parent region to be the containing region of the child.
|
||||
// Regions of type GROUPING can't be set as the parent, since another region
|
||||
@ -281,17 +316,20 @@ void Region::loadRegionData() {
|
||||
}
|
||||
}
|
||||
}
|
||||
ures_close(mapping);
|
||||
}
|
||||
|
||||
// Create the availableRegions lists
|
||||
|
||||
for ( int32_t i = 0 ; i < regions->size() ; i++ ) {
|
||||
Region *ar = (Region *)regions->elementAt(i);
|
||||
addAvailableRegion(ar,ar->type);
|
||||
int32_t pos = -1;
|
||||
while ( const UHashElement* element = uhash_nextElement(regionIDMap,&pos)) {
|
||||
Region *ar = (Region *)element->value.pointer;
|
||||
if ( availableRegions[ar->type] == NULL ) {
|
||||
availableRegions[ar->type] = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
|
||||
}
|
||||
UnicodeString *arString = new UnicodeString(ar->idStr);
|
||||
availableRegions[ar->type]->addElement((void *)arString,status);
|
||||
}
|
||||
|
||||
regionDataIsLoaded = true;
|
||||
|
||||
ures_close(territoryContainment);
|
||||
ures_close(worldContainment);
|
||||
ures_close(groupingContainment);
|
||||
@ -303,6 +341,12 @@ void Region::loadRegionData() {
|
||||
ures_close(rb);
|
||||
|
||||
delete df;
|
||||
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup);
|
||||
|
||||
regionDataIsLoaded = true;
|
||||
umtx_unlock(&gRegionDataLock);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -321,6 +365,14 @@ Region::Region () {
|
||||
preferredValues = NULL;
|
||||
}
|
||||
|
||||
Region::~Region () {
|
||||
if (containedRegions) {
|
||||
delete containedRegions;
|
||||
}
|
||||
if (preferredValues) {
|
||||
delete preferredValues;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the two regions are equal.
|
||||
@ -497,18 +549,21 @@ Region::getContainedRegions( URegionType type ) const {
|
||||
const char *id = cr->next(NULL,status);
|
||||
const Region *r = Region::getInstance(id,status);
|
||||
if ( r->getType() == type ) {
|
||||
result->addElement((void *)r->id,status);
|
||||
result->addElement((void *)&r->idStr,status);
|
||||
} else {
|
||||
StringEnumeration *children = r->getContainedRegions(type);
|
||||
for ( int32_t j = 0 ; j < children->count(status) ; j++ ) {
|
||||
const char *id2 = children->next(NULL,status);
|
||||
const Region *r2 = Region::getInstance(id2,status);
|
||||
result->addElement((void *)r2->id,status);
|
||||
result->addElement((void *)&r2->idStr,status);
|
||||
}
|
||||
delete children;
|
||||
}
|
||||
}
|
||||
return new RegionNameEnumeration(result,status);
|
||||
delete cr;
|
||||
StringEnumeration* resultEnumeration = new RegionNameEnumeration(result,status);
|
||||
delete result;
|
||||
return resultEnumeration;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -521,12 +576,12 @@ Region::contains(const Region &other) const {
|
||||
if (!containedRegions) {
|
||||
return FALSE;
|
||||
}
|
||||
if (containedRegions->contains((void *)other.id)) {
|
||||
if (containedRegions->contains((void *)&other.idStr)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
for ( int32_t i = 0 ; i < containedRegions->size() ; i++ ) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
const Region *cr = Region::getInstance((const char *)containedRegions->elementAt(i),status);
|
||||
UnicodeString *crStr = (UnicodeString *)containedRegions->elementAt(i);
|
||||
Region *cr = (Region *) uhash_get(regionIDMap,(void *)crStr);
|
||||
if ( cr && cr->contains(other) ) {
|
||||
return TRUE;
|
||||
}
|
||||
@ -580,41 +635,21 @@ Region::getType() const {
|
||||
RegionNameEnumeration::RegionNameEnumeration(UVector *fNameList, UErrorCode& status) {
|
||||
pos=0;
|
||||
if (fNameList) {
|
||||
fRegionNames = new UVector(NULL, uhash_compareChars, fNameList->size(),status);
|
||||
fRegionNames = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, fNameList->size(),status);
|
||||
for ( int32_t i = 0 ; i < fNameList->size() ; i++ ) {
|
||||
char *region_name = (char *) uprv_malloc(sizeof(fNameList->elementAt(i)));
|
||||
if (!region_name) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
delete fRegionNames;
|
||||
fRegionNames = NULL;
|
||||
return;
|
||||
}
|
||||
uprv_strcpy(region_name,(char *)fNameList->elementAt(i));
|
||||
fRegionNames->addElement(region_name,status);
|
||||
|
||||
UnicodeString* this_region_name = (UnicodeString *)fNameList->elementAt(i);
|
||||
UnicodeString* new_region_name = new UnicodeString(*this_region_name);
|
||||
fRegionNames->addElement((void *)new_region_name,status);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fRegionNames = fNameList;
|
||||
fRegionNames = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
RegionNameEnumeration::next(int32_t *resultLength, UErrorCode& status) {
|
||||
if (U_SUCCESS(status) && pos < fRegionNames->size()) {
|
||||
if (resultLength != NULL) {
|
||||
*resultLength = uprv_strlen((const char *)fRegionNames->elementAt(pos));
|
||||
}
|
||||
return (const char *)fRegionNames->elementAt(pos++);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const UnicodeString*
|
||||
RegionNameEnumeration::snext(UErrorCode& status) {
|
||||
int32_t resultLength=0;
|
||||
const char *s=next(&resultLength, status);
|
||||
return setChars(s, resultLength, status);
|
||||
RegionNameEnumeration::snext(UErrorCode& /*status*/) {
|
||||
return (const UnicodeString *)fRegionNames->elementAt(pos++);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -28,7 +28,6 @@ public:
|
||||
virtual ~RegionNameEnumeration();
|
||||
static UClassID U_EXPORT2 getStaticClassID(void);
|
||||
virtual UClassID getDynamicClassID(void) const;
|
||||
virtual const char *next(int32_t *resultLength, UErrorCode& status);
|
||||
virtual const UnicodeString* snext(UErrorCode& status);
|
||||
virtual void reset(UErrorCode& status);
|
||||
virtual int32_t count(UErrorCode& status) const;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2001-2012, International Business Machines *
|
||||
* Copyright (C) 2001-2013, International Business Machines *
|
||||
* Corporation and others. All Rights Reserved. *
|
||||
* *
|
||||
******************************************************************************
|
||||
@ -51,6 +51,7 @@ typedef enum ECleanupI18NType {
|
||||
UCLN_I18N_INDEX_CHARACTERS,
|
||||
UCLN_I18N_GENDERINFO,
|
||||
UCLN_I18N_CDFINFO,
|
||||
UCLN_I18N_REGION,
|
||||
UCLN_I18N_COUNT /* This must be last */
|
||||
} ECleanupI18NType;
|
||||
|
||||
|
@ -135,6 +135,13 @@ public:
|
||||
*/
|
||||
Region();
|
||||
|
||||
/**
|
||||
* Default Destructor.
|
||||
*
|
||||
* @draft ICU 51
|
||||
*/
|
||||
~Region();
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the two regions are equal.
|
||||
|
@ -512,6 +512,7 @@ void RegionTest::TestGetContainedRegions() {
|
||||
r->getRegionCode(),cr->getRegionCode(),containingRegion?containingRegion->getRegionCode():"NULL");
|
||||
}
|
||||
}
|
||||
delete containedRegions;
|
||||
} else {
|
||||
errln("Known region %s was not recognized.",rd.code);
|
||||
}
|
||||
@ -538,6 +539,7 @@ void RegionTest::TestGetContainedRegionsWithType() {
|
||||
r->getRegionCode(),cr->getRegionCode(),containingRegion?containingRegion->getRegionCode():"NULL");
|
||||
}
|
||||
}
|
||||
delete containedRegions;
|
||||
} else {
|
||||
errln("Known region %s was not recognized.",rd.code);
|
||||
}
|
||||
@ -623,6 +625,7 @@ void RegionTest::TestGetPreferredValues() {
|
||||
errln("Region::getPreferredValues() for region \"%s\" should have contained \"%s\" but it didn't.",r->getRegionCode(),data[i]);
|
||||
}
|
||||
}
|
||||
delete preferredValues;
|
||||
} else {
|
||||
errln("Known region %s was not recognized.",data[0]);
|
||||
}
|
||||
@ -682,6 +685,8 @@ void RegionTest::TestAvailableTerritories() {
|
||||
errln("Available territories and all territories contained in world should be the same set.\nAvailable = %s\nContained in World = %s",
|
||||
availableTerritoriesString,containedInWorldString);
|
||||
}
|
||||
delete availableTerritories;
|
||||
delete containedInWorld;
|
||||
}
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user