1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/region.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,690 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 2013, International Business Machines Corporation and 1.7 +* others. All Rights Reserved. 1.8 +******************************************************************************* 1.9 +* 1.10 +* 1.11 +* File REGION.CPP 1.12 +* 1.13 +* Modification History:* 1.14 +* Date Name Description 1.15 +* 01/15/13 Emmons Original Port from ICU4J 1.16 +******************************************************************************** 1.17 +*/ 1.18 + 1.19 +/** 1.20 + * \file 1.21 + * \brief C++ API: Region classes (territory containment) 1.22 + */ 1.23 + 1.24 +#include "unicode/region.h" 1.25 +#include "unicode/utypes.h" 1.26 +#include "unicode/uobject.h" 1.27 +#include "unicode/unistr.h" 1.28 +#include "unicode/ures.h" 1.29 +#include "unicode/decimfmt.h" 1.30 +#include "ucln_in.h" 1.31 +#include "cstring.h" 1.32 +#include "uhash.h" 1.33 +#include "umutex.h" 1.34 +#include "uresimp.h" 1.35 +#include "region_impl.h" 1.36 + 1.37 +#if !UCONFIG_NO_FORMATTING 1.38 + 1.39 + 1.40 +U_CDECL_BEGIN 1.41 + 1.42 +static void U_CALLCONV 1.43 +deleteRegion(void *obj) { 1.44 + delete (icu::Region *)obj; 1.45 +} 1.46 + 1.47 +/** 1.48 + * Cleanup callback func 1.49 + */ 1.50 +static UBool U_CALLCONV region_cleanup(void) 1.51 +{ 1.52 + icu::Region::cleanupRegionData(); 1.53 + 1.54 + return TRUE; 1.55 +} 1.56 + 1.57 +U_CDECL_END 1.58 + 1.59 +U_NAMESPACE_BEGIN 1.60 + 1.61 +static UMutex gRegionDataLock = U_MUTEX_INITIALIZER; 1.62 +static UBool regionDataIsLoaded = false; 1.63 +static UVector* availableRegions[URGN_LIMIT]; 1.64 + 1.65 +static UHashtable *regionAliases; 1.66 +static UHashtable *regionIDMap; 1.67 +static UHashtable *numericCodeMap; 1.68 + 1.69 +static const UChar UNKNOWN_REGION_ID [] = { 0x5A, 0x5A, 0 }; /* "ZZ" */ 1.70 +static const UChar OUTLYING_OCEANIA_REGION_ID [] = { 0x51, 0x4F, 0 }; /* "QO" */ 1.71 +static const UChar WORLD_ID [] = { 0x30, 0x30, 0x31, 0 }; /* "001" */ 1.72 + 1.73 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegionNameEnumeration) 1.74 + 1.75 +/* 1.76 + * Initializes the region data from the ICU resource bundles. The region data 1.77 + * contains the basic relationships such as which regions are known, what the numeric 1.78 + * codes are, any known aliases, and the territory containment data. 1.79 + * 1.80 + * If the region data has already loaded, then this method simply returns without doing 1.81 + * anything meaningful. 1.82 + */ 1.83 +void Region::loadRegionData() { 1.84 + 1.85 + if (regionDataIsLoaded) { 1.86 + return; 1.87 + } 1.88 + 1.89 + umtx_lock(&gRegionDataLock); 1.90 + 1.91 + if (regionDataIsLoaded) { // In case another thread gets to it before we do... 1.92 + umtx_unlock(&gRegionDataLock); 1.93 + return; 1.94 + } 1.95 + 1.96 + 1.97 + UErrorCode status = U_ZERO_ERROR; 1.98 + 1.99 + UResourceBundle* regionCodes = NULL; 1.100 + UResourceBundle* territoryAlias = NULL; 1.101 + UResourceBundle* codeMappings = NULL; 1.102 + UResourceBundle* worldContainment = NULL; 1.103 + UResourceBundle* territoryContainment = NULL; 1.104 + UResourceBundle* groupingContainment = NULL; 1.105 + 1.106 + DecimalFormat *df = new DecimalFormat(status); 1.107 + if (U_FAILURE(status)) { 1.108 + umtx_unlock(&gRegionDataLock); 1.109 + return; 1.110 + } 1.111 + df->setParseIntegerOnly(TRUE); 1.112 + 1.113 + regionIDMap = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status); 1.114 + uhash_setValueDeleter(regionIDMap, deleteRegion); 1.115 + 1.116 + numericCodeMap = uhash_open(uhash_hashLong,uhash_compareLong,NULL,&status); 1.117 + 1.118 + regionAliases = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status); 1.119 + uhash_setKeyDeleter(regionAliases,uprv_deleteUObject); 1.120 + 1.121 + UResourceBundle *rb = ures_openDirect(NULL,"metadata",&status); 1.122 + regionCodes = ures_getByKey(rb,"regionCodes",NULL,&status); 1.123 + territoryAlias = ures_getByKey(rb,"territoryAlias",NULL,&status); 1.124 + 1.125 + UResourceBundle *rb2 = ures_openDirect(NULL,"supplementalData",&status); 1.126 + codeMappings = ures_getByKey(rb2,"codeMappings",NULL,&status); 1.127 + 1.128 + territoryContainment = ures_getByKey(rb2,"territoryContainment",NULL,&status); 1.129 + worldContainment = ures_getByKey(territoryContainment,"001",NULL,&status); 1.130 + groupingContainment = ures_getByKey(territoryContainment,"grouping",NULL,&status); 1.131 + 1.132 + UVector *continents = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 1.133 + 1.134 + while ( ures_hasNext(worldContainment) ) { 1.135 + UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment,NULL,&status)); 1.136 + continents->addElement(continentName,status); 1.137 + } 1.138 + 1.139 + UVector *groupings = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 1.140 + while ( ures_hasNext(groupingContainment) ) { 1.141 + UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment,NULL,&status)); 1.142 + groupings->addElement(groupingName,status); 1.143 + } 1.144 + 1.145 + while ( ures_hasNext(regionCodes) ) { 1.146 + UnicodeString regionID = ures_getNextUnicodeString(regionCodes,NULL,&status); 1.147 + Region *r = new Region(); 1.148 + r->idStr = regionID; 1.149 + r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV); 1.150 + r->type = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known. 1.151 + 1.152 + uhash_put(regionIDMap,(void *)&(r->idStr),(void *)r,&status); 1.153 + Formattable result; 1.154 + UErrorCode ps = U_ZERO_ERROR; 1.155 + df->parse(r->idStr,result,ps); 1.156 + if ( U_SUCCESS(ps) ) { 1.157 + r->code = result.getLong(); // Convert string to number 1.158 + uhash_iput(numericCodeMap,r->code,(void *)r,&status); 1.159 + r->type = URGN_SUBCONTINENT; 1.160 + } else { 1.161 + r->code = -1; 1.162 + } 1.163 + } 1.164 + 1.165 + 1.166 + // Process the territory aliases 1.167 + while ( ures_hasNext(territoryAlias) ) { 1.168 + UResourceBundle *res = ures_getNextResource(territoryAlias,NULL,&status); 1.169 + const char *aliasFrom = ures_getKey(res); 1.170 + UnicodeString* aliasFromStr = new UnicodeString(aliasFrom, -1, US_INV); 1.171 + UnicodeString aliasTo = ures_getUnicodeString(res,&status); 1.172 + ures_close(res); 1.173 + 1.174 + Region *aliasToRegion = (Region *) uhash_get(regionIDMap,&aliasTo); 1.175 + Region *aliasFromRegion = (Region *)uhash_get(regionIDMap,aliasFromStr); 1.176 + 1.177 + if ( aliasToRegion != NULL && aliasFromRegion == NULL ) { // This is just an alias from some string to a region 1.178 + uhash_put(regionAliases,(void *)aliasFromStr, (void *)aliasToRegion,&status); 1.179 + } else { 1.180 + if ( aliasFromRegion == NULL ) { // Deprecated region code not in the master codes list - so need to create a deprecated region for it. 1.181 + aliasFromRegion = new Region(); 1.182 + aliasFromRegion->idStr.setTo(*aliasFromStr); 1.183 + aliasFromRegion->idStr.extract(0,aliasFromRegion->idStr.length(),aliasFromRegion->id,sizeof(aliasFromRegion->id),US_INV); 1.184 + uhash_put(regionIDMap,(void *)&(aliasFromRegion->idStr),(void *)aliasFromRegion,&status); 1.185 + Formattable result; 1.186 + UErrorCode ps = U_ZERO_ERROR; 1.187 + df->parse(aliasFromRegion->idStr,result,ps); 1.188 + if ( U_SUCCESS(ps) ) { 1.189 + aliasFromRegion->code = result.getLong(); // Convert string to number 1.190 + uhash_iput(numericCodeMap,aliasFromRegion->code,(void *)aliasFromRegion,&status); 1.191 + } else { 1.192 + aliasFromRegion->code = -1; 1.193 + } 1.194 + aliasFromRegion->type = URGN_DEPRECATED; 1.195 + } else { 1.196 + aliasFromRegion->type = URGN_DEPRECATED; 1.197 + } 1.198 + delete aliasFromStr; 1.199 + 1.200 + aliasFromRegion->preferredValues = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 1.201 + UnicodeString currentRegion; 1.202 + currentRegion.remove(); 1.203 + for (int32_t i = 0 ; i < aliasTo.length() ; i++ ) { 1.204 + if ( aliasTo.charAt(i) != 0x0020 ) { 1.205 + currentRegion.append(aliasTo.charAt(i)); 1.206 + } 1.207 + if ( aliasTo.charAt(i) == 0x0020 || i+1 == aliasTo.length() ) { 1.208 + Region *target = (Region *)uhash_get(regionIDMap,(void *)¤tRegion); 1.209 + if (target) { 1.210 + UnicodeString *preferredValue = new UnicodeString(target->idStr); 1.211 + aliasFromRegion->preferredValues->addElement((void *)preferredValue,status); 1.212 + } 1.213 + currentRegion.remove(); 1.214 + } 1.215 + } 1.216 + } 1.217 + } 1.218 + 1.219 + // Process the code mappings - This will allow us to assign numeric codes to most of the territories. 1.220 + while ( ures_hasNext(codeMappings) ) { 1.221 + UResourceBundle *mapping = ures_getNextResource(codeMappings,NULL,&status); 1.222 + if ( ures_getType(mapping) == URES_ARRAY && ures_getSize(mapping) == 3) { 1.223 + UnicodeString codeMappingID = ures_getUnicodeStringByIndex(mapping,0,&status); 1.224 + UnicodeString codeMappingNumber = ures_getUnicodeStringByIndex(mapping,1,&status); 1.225 + UnicodeString codeMapping3Letter = ures_getUnicodeStringByIndex(mapping,2,&status); 1.226 + 1.227 + Region *r = (Region *)uhash_get(regionIDMap,(void *)&codeMappingID); 1.228 + if ( r ) { 1.229 + Formattable result; 1.230 + UErrorCode ps = U_ZERO_ERROR; 1.231 + df->parse(codeMappingNumber,result,ps); 1.232 + if ( U_SUCCESS(ps) ) { 1.233 + r->code = result.getLong(); // Convert string to number 1.234 + uhash_iput(numericCodeMap,r->code,(void *)r,&status); 1.235 + } 1.236 + UnicodeString *code3 = new UnicodeString(codeMapping3Letter); 1.237 + uhash_put(regionAliases,(void *)code3, (void *)r,&status); 1.238 + } 1.239 + } 1.240 + ures_close(mapping); 1.241 + } 1.242 + 1.243 + // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS 1.244 + Region *r; 1.245 + UnicodeString WORLD_ID_STRING(WORLD_ID); 1.246 + r = (Region *) uhash_get(regionIDMap,(void *)&WORLD_ID_STRING); 1.247 + if ( r ) { 1.248 + r->type = URGN_WORLD; 1.249 + } 1.250 + 1.251 + UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID); 1.252 + r = (Region *) uhash_get(regionIDMap,(void *)&UNKNOWN_REGION_ID_STRING); 1.253 + if ( r ) { 1.254 + r->type = URGN_UNKNOWN; 1.255 + } 1.256 + 1.257 + for ( int32_t i = 0 ; i < continents->size() ; i++ ) { 1.258 + r = (Region *) uhash_get(regionIDMap,(void *)continents->elementAt(i)); 1.259 + if ( r ) { 1.260 + r->type = URGN_CONTINENT; 1.261 + } 1.262 + } 1.263 + delete continents; 1.264 + 1.265 + for ( int32_t i = 0 ; i < groupings->size() ; i++ ) { 1.266 + r = (Region *) uhash_get(regionIDMap,(void *)groupings->elementAt(i)); 1.267 + if ( r ) { 1.268 + r->type = URGN_GROUPING; 1.269 + } 1.270 + } 1.271 + delete groupings; 1.272 + 1.273 + // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR 1.274 + // even though it looks like a territory code. Need to handle it here. 1.275 + 1.276 + UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID); 1.277 + r = (Region *) uhash_get(regionIDMap,(void *)&OUTLYING_OCEANIA_REGION_ID_STRING); 1.278 + if ( r ) { 1.279 + r->type = URGN_SUBCONTINENT; 1.280 + } 1.281 + 1.282 + // Load territory containment info from the supplemental data. 1.283 + while ( ures_hasNext(territoryContainment) ) { 1.284 + UResourceBundle *mapping = ures_getNextResource(territoryContainment,NULL,&status); 1.285 + const char *parent = ures_getKey(mapping); 1.286 + UnicodeString parentStr = UnicodeString(parent, -1 , US_INV); 1.287 + Region *parentRegion = (Region *) uhash_get(regionIDMap,(void *)&parentStr); 1.288 + 1.289 + for ( int j = 0 ; j < ures_getSize(mapping); j++ ) { 1.290 + UnicodeString child = ures_getUnicodeStringByIndex(mapping,j,&status); 1.291 + Region *childRegion = (Region *) uhash_get(regionIDMap,(void *)&child); 1.292 + if ( parentRegion != NULL && childRegion != NULL ) { 1.293 + 1.294 + // Add the child region to the set of regions contained by the parent 1.295 + if (parentRegion->containedRegions == NULL) { 1.296 + parentRegion->containedRegions = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 1.297 + } 1.298 + 1.299 + UnicodeString *childStr = new UnicodeString(); 1.300 + childStr->fastCopyFrom(childRegion->idStr); 1.301 + parentRegion->containedRegions->addElement((void *)childStr,status); 1.302 + 1.303 + // Set the parent region to be the containing region of the child. 1.304 + // Regions of type GROUPING can't be set as the parent, since another region 1.305 + // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent. 1.306 + if ( parentRegion->type != URGN_GROUPING) { 1.307 + childRegion->containingRegion = parentRegion; 1.308 + } 1.309 + } 1.310 + } 1.311 + ures_close(mapping); 1.312 + } 1.313 + 1.314 + // Create the availableRegions lists 1.315 + int32_t pos = -1; 1.316 + while ( const UHashElement* element = uhash_nextElement(regionIDMap,&pos)) { 1.317 + Region *ar = (Region *)element->value.pointer; 1.318 + if ( availableRegions[ar->type] == NULL ) { 1.319 + availableRegions[ar->type] = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status); 1.320 + } 1.321 + UnicodeString *arString = new UnicodeString(ar->idStr); 1.322 + availableRegions[ar->type]->addElement((void *)arString,status); 1.323 + } 1.324 + 1.325 + ures_close(territoryContainment); 1.326 + ures_close(worldContainment); 1.327 + ures_close(groupingContainment); 1.328 + 1.329 + ures_close(codeMappings); 1.330 + ures_close(rb2); 1.331 + ures_close(territoryAlias); 1.332 + ures_close(regionCodes); 1.333 + ures_close(rb); 1.334 + 1.335 + delete df; 1.336 + 1.337 + ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup); 1.338 + 1.339 + regionDataIsLoaded = true; 1.340 + umtx_unlock(&gRegionDataLock); 1.341 + 1.342 +} 1.343 + 1.344 +void Region::cleanupRegionData() { 1.345 + 1.346 + for (int32_t i = 0 ; i < URGN_LIMIT ; i++ ) { 1.347 + if ( availableRegions[i] ) { 1.348 + delete availableRegions[i]; 1.349 + } 1.350 + } 1.351 + 1.352 + if (regionAliases) { 1.353 + uhash_close(regionAliases); 1.354 + } 1.355 + 1.356 + if (numericCodeMap) { 1.357 + uhash_close(numericCodeMap); 1.358 + } 1.359 + 1.360 + if (regionIDMap) { 1.361 + uhash_close(regionIDMap); 1.362 + } 1.363 +} 1.364 + 1.365 +Region::Region () 1.366 + : code(-1), 1.367 + type(URGN_UNKNOWN), 1.368 + containingRegion(NULL), 1.369 + containedRegions(NULL), 1.370 + preferredValues(NULL) { 1.371 + id[0] = 0; 1.372 +} 1.373 + 1.374 +Region::~Region () { 1.375 + if (containedRegions) { 1.376 + delete containedRegions; 1.377 + } 1.378 + if (preferredValues) { 1.379 + delete preferredValues; 1.380 + } 1.381 +} 1.382 + 1.383 +/** 1.384 + * Returns true if the two regions are equal. 1.385 + */ 1.386 +UBool 1.387 +Region::operator==(const Region &that) const { 1.388 + return (idStr == that.idStr); 1.389 +} 1.390 + 1.391 +/** 1.392 + * Returns true if the two regions are NOT equal; that is, if operator ==() returns false. 1.393 + */ 1.394 +UBool 1.395 +Region::operator!=(const Region &that) const { 1.396 + return (idStr != that.idStr); 1.397 +} 1.398 + 1.399 +/** 1.400 + * Returns a pointer to a Region using the given region code. The region code can be either 2-letter ISO code, 1.401 + * 3-letter ISO code, UNM.49 numeric code, or other valid Unicode Region Code as defined by the LDML specification. 1.402 + * The identifier will be canonicalized internally using the supplemental metadata as defined in the CLDR. 1.403 + * If the region code is NULL or not recognized, the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ) 1.404 + */ 1.405 +const Region* U_EXPORT2 1.406 +Region::getInstance(const char *region_code, UErrorCode &status) { 1.407 + 1.408 + if ( !region_code ) { 1.409 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.410 + return NULL; 1.411 + } 1.412 + 1.413 + loadRegionData(); 1.414 + 1.415 + if (regionIDMap == NULL) { 1.416 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.417 + return NULL; 1.418 + } 1.419 + 1.420 + UnicodeString regionCodeString = UnicodeString(region_code, -1, US_INV); 1.421 + Region *r = (Region *)uhash_get(regionIDMap,(void *)®ionCodeString); 1.422 + 1.423 + if ( !r ) { 1.424 + r = (Region *)uhash_get(regionAliases,(void *)®ionCodeString); 1.425 + } 1.426 + 1.427 + if ( !r ) { // Unknown region code 1.428 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.429 + return NULL; 1.430 + } 1.431 + 1.432 + if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) { 1.433 + StringEnumeration *pv = r->getPreferredValues(); 1.434 + pv->reset(status); 1.435 + const UnicodeString *ustr = pv->snext(status); 1.436 + r = (Region *)uhash_get(regionIDMap,(void *)ustr); 1.437 + delete pv; 1.438 + } 1.439 + 1.440 + return r; 1.441 + 1.442 +} 1.443 + 1.444 +/** 1.445 + * Returns a pointer to a Region using the given numeric region code. If the numeric region code is not recognized, 1.446 + * the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ). 1.447 + */ 1.448 +const Region* U_EXPORT2 1.449 +Region::getInstance (int32_t code, UErrorCode &status) { 1.450 + 1.451 + loadRegionData(); 1.452 + 1.453 + if (numericCodeMap == NULL) { 1.454 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.455 + return NULL; 1.456 + } 1.457 + 1.458 + Region *r = (Region *)uhash_iget(numericCodeMap,code); 1.459 + 1.460 + if ( !r ) { // Just in case there's an alias that's numeric, try to find it. 1.461 + UErrorCode fs = U_ZERO_ERROR; 1.462 + UnicodeString pat = UNICODE_STRING_SIMPLE("00#"); 1.463 + DecimalFormat *df = new DecimalFormat(pat,fs); 1.464 + 1.465 + UnicodeString id; 1.466 + id.remove(); 1.467 + df->format(code,id); 1.468 + delete df; 1.469 + r = (Region *)uhash_get(regionAliases,&id); 1.470 + } 1.471 + 1.472 + if ( !r ) { 1.473 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.474 + return NULL; 1.475 + } 1.476 + 1.477 + if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) { 1.478 + StringEnumeration *pv = r->getPreferredValues(); 1.479 + pv->reset(status); 1.480 + const UnicodeString *ustr = pv->snext(status); 1.481 + r = (Region *)uhash_get(regionIDMap,(void *)ustr); 1.482 + delete pv; 1.483 + } 1.484 + 1.485 + return r; 1.486 +} 1.487 + 1.488 + 1.489 +/** 1.490 + * Returns an enumeration over the IDs of all known regions that match the given type. 1.491 + */ 1.492 +StringEnumeration* U_EXPORT2 1.493 +Region::getAvailable(URegionType type) { 1.494 + 1.495 + loadRegionData(); 1.496 + UErrorCode status = U_ZERO_ERROR; 1.497 + return new RegionNameEnumeration(availableRegions[type],status); 1.498 + 1.499 + return NULL; 1.500 +} 1.501 + 1.502 +/** 1.503 + * Returns a pointer to the region that contains this region. Returns NULL if this region is code "001" (World) 1.504 + * or "ZZ" (Unknown region). For example, calling this method with region "IT" (Italy) returns the 1.505 + * region "039" (Southern Europe). 1.506 + */ 1.507 +const Region* 1.508 +Region::getContainingRegion() const { 1.509 + loadRegionData(); 1.510 + return containingRegion; 1.511 +} 1.512 + 1.513 +/** 1.514 + * Return a pointer to the region that geographically contains this region and matches the given type, 1.515 + * moving multiple steps up the containment chain if necessary. Returns NULL if no containing region can be found 1.516 + * that matches the given type. Note: The URegionTypes = "URGN_GROUPING", "URGN_DEPRECATED", or "URGN_UNKNOWN" 1.517 + * are not appropriate for use in this API. NULL will be returned in this case. For example, calling this method 1.518 + * with region "IT" (Italy) for type "URGN_CONTINENT" returns the region "150" ( Europe ). 1.519 + */ 1.520 +const Region* 1.521 +Region::getContainingRegion(URegionType type) const { 1.522 + loadRegionData(); 1.523 + if ( containingRegion == NULL ) { 1.524 + return NULL; 1.525 + } 1.526 + 1.527 + if ( containingRegion->type == type ) { 1.528 + return containingRegion; 1.529 + } else { 1.530 + return containingRegion->getContainingRegion(type); 1.531 + } 1.532 +} 1.533 + 1.534 +/** 1.535 + * Return an enumeration over the IDs of all the regions that are immediate children of this region in the 1.536 + * region hierarchy. These returned regions could be either macro regions, territories, or a mixture of the two, 1.537 + * depending on the containment data as defined in CLDR. This API may return NULL if this region doesn't have 1.538 + * any sub-regions. For example, calling this method with region "150" (Europe) returns an enumeration containing 1.539 + * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe) - "154" (Northern Europe) 1.540 + * and "155" (Western Europe). 1.541 + */ 1.542 +StringEnumeration* 1.543 +Region::getContainedRegions() const { 1.544 + loadRegionData(); 1.545 + UErrorCode status = U_ZERO_ERROR; 1.546 + return new RegionNameEnumeration(containedRegions,status); 1.547 +} 1.548 + 1.549 +/** 1.550 + * Returns an enumeration over the IDs of all the regions that are children of this region anywhere in the region 1.551 + * hierarchy and match the given type. This API may return an empty enumeration if this region doesn't have any 1.552 + * sub-regions that match the given type. For example, calling this method with region "150" (Europe) and type 1.553 + * "URGN_TERRITORY" returns a set containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. ) 1.554 + */ 1.555 +StringEnumeration* 1.556 +Region::getContainedRegions( URegionType type ) const { 1.557 + loadRegionData(); 1.558 + 1.559 + UErrorCode status = U_ZERO_ERROR; 1.560 + UVector *result = new UVector(NULL, uhash_compareChars, status); 1.561 + 1.562 + StringEnumeration *cr = getContainedRegions(); 1.563 + 1.564 + for ( int32_t i = 0 ; i < cr->count(status) ; i++ ) { 1.565 + const char *id = cr->next(NULL,status); 1.566 + const Region *r = Region::getInstance(id,status); 1.567 + if ( r->getType() == type ) { 1.568 + result->addElement((void *)&r->idStr,status); 1.569 + } else { 1.570 + StringEnumeration *children = r->getContainedRegions(type); 1.571 + for ( int32_t j = 0 ; j < children->count(status) ; j++ ) { 1.572 + const char *id2 = children->next(NULL,status); 1.573 + const Region *r2 = Region::getInstance(id2,status); 1.574 + result->addElement((void *)&r2->idStr,status); 1.575 + } 1.576 + delete children; 1.577 + } 1.578 + } 1.579 + delete cr; 1.580 + StringEnumeration* resultEnumeration = new RegionNameEnumeration(result,status); 1.581 + delete result; 1.582 + return resultEnumeration; 1.583 +} 1.584 + 1.585 +/** 1.586 + * Returns true if this region contains the supplied other region anywhere in the region hierarchy. 1.587 + */ 1.588 +UBool 1.589 +Region::contains(const Region &other) const { 1.590 + loadRegionData(); 1.591 + 1.592 + if (!containedRegions) { 1.593 + return FALSE; 1.594 + } 1.595 + if (containedRegions->contains((void *)&other.idStr)) { 1.596 + return TRUE; 1.597 + } else { 1.598 + for ( int32_t i = 0 ; i < containedRegions->size() ; i++ ) { 1.599 + UnicodeString *crStr = (UnicodeString *)containedRegions->elementAt(i); 1.600 + Region *cr = (Region *) uhash_get(regionIDMap,(void *)crStr); 1.601 + if ( cr && cr->contains(other) ) { 1.602 + return TRUE; 1.603 + } 1.604 + } 1.605 + } 1.606 + 1.607 + return FALSE; 1.608 +} 1.609 + 1.610 +/** 1.611 + * For deprecated regions, return an enumeration over the IDs of the regions that are the preferred replacement 1.612 + * regions for this region. Returns NULL for a non-deprecated region. For example, calling this method with region 1.613 + * "SU" (Soviet Union) would return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc... 1.614 + */ 1.615 +StringEnumeration* 1.616 +Region::getPreferredValues() const { 1.617 + loadRegionData(); 1.618 + UErrorCode status = U_ZERO_ERROR; 1.619 + if ( type == URGN_DEPRECATED ) { 1.620 + return new RegionNameEnumeration(preferredValues,status); 1.621 + } else { 1.622 + return NULL; 1.623 + } 1.624 +} 1.625 + 1.626 + 1.627 +/** 1.628 + * Return this region's canonical region code. 1.629 + */ 1.630 +const char* 1.631 +Region::getRegionCode() const { 1.632 + return id; 1.633 +} 1.634 + 1.635 +int32_t 1.636 +Region::getNumericCode() const { 1.637 + return code; 1.638 +} 1.639 + 1.640 +/** 1.641 + * Returns the region type of this region. 1.642 + */ 1.643 +URegionType 1.644 +Region::getType() const { 1.645 + return type; 1.646 +} 1.647 + 1.648 +RegionNameEnumeration::RegionNameEnumeration(UVector *fNameList, UErrorCode& status) { 1.649 + pos=0; 1.650 + if (fNameList && U_SUCCESS(status)) { 1.651 + fRegionNames = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, fNameList->size(),status); 1.652 + for ( int32_t i = 0 ; i < fNameList->size() ; i++ ) { 1.653 + UnicodeString* this_region_name = (UnicodeString *)fNameList->elementAt(i); 1.654 + UnicodeString* new_region_name = new UnicodeString(*this_region_name); 1.655 + fRegionNames->addElement((void *)new_region_name,status); 1.656 + } 1.657 + } 1.658 + else { 1.659 + fRegionNames = NULL; 1.660 + } 1.661 +} 1.662 + 1.663 +const UnicodeString* 1.664 +RegionNameEnumeration::snext(UErrorCode& status) { 1.665 + if (U_FAILURE(status) || (fRegionNames==NULL)) { 1.666 + return NULL; 1.667 + } 1.668 + const UnicodeString* nextStr = (const UnicodeString *)fRegionNames->elementAt(pos); 1.669 + if (nextStr!=NULL) { 1.670 + pos++; 1.671 + } 1.672 + return nextStr; 1.673 +} 1.674 + 1.675 +void 1.676 +RegionNameEnumeration::reset(UErrorCode& /*status*/) { 1.677 + pos=0; 1.678 +} 1.679 + 1.680 +int32_t 1.681 +RegionNameEnumeration::count(UErrorCode& /*status*/) const { 1.682 + return (fRegionNames==NULL) ? 0 : fRegionNames->size(); 1.683 +} 1.684 + 1.685 +RegionNameEnumeration::~RegionNameEnumeration() { 1.686 + delete fRegionNames; 1.687 +} 1.688 + 1.689 +U_NAMESPACE_END 1.690 + 1.691 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.692 + 1.693 +//eof