/* * 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 * codes are, any known aliases, and the territory containment data. * * If the region data has already loaded, then this method simply returns without doing * anything meaningful.
*/ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
// Construct service objs first
LocalUHashtablePointer newRegionIDMap(uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, nullptr, &status));
LocalUHashtablePointer newNumericCodeMap(uhash_open(uhash_hashLong,uhash_compareLong,nullptr,&status));
LocalUHashtablePointer newRegionAliases(uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,nullptr,&status));
while (U_SUCCESS(status) && ures_hasNext(regionUnknown.getAlias())) {
LocalPointer<UnicodeString> regionName ( new UnicodeString(ures_getNextUnicodeString(regionUnknown.getAlias(), nullptr, &status), status));
allRegions->adoptElement(regionName.orphan(),status);
}
while (U_SUCCESS(status) && ures_hasNext(worldContainment.getAlias())) {
UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment.getAlias(),nullptr,&status));
continents->adoptElement(continentName,status);
} if (U_FAILURE(status)) { return;
}
for ( int32_t i = 0 ; i < allRegions->size() ; i++ ) {
LocalPointer<Region> r(new Region(), status); if ( U_FAILURE(status) ) { return;
}
UnicodeString* regionName = static_cast<UnicodeString*>(allRegions->elementAt(i));
r->idStr = *regionName;
r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV);
r->fType = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.
int32_t pos = 0;
int32_t result = ICU_Utility::parseAsciiInteger(r->idStr, pos); if (pos > 0) {
r->code = result; // Convert string to number
uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)(r.getAlias()),&status);
r->fType = URGN_SUBCONTINENT;
} else {
r->code = -1;
} void* idStrAlias = (void*)&(r->idStr); // about to orphan 'r'. Save this off.
uhash_put(newRegionIDMap.getAlias(),idStrAlias,(void *)(r.orphan()),&status); // regionIDMap takes ownership
}
UResourceBundle *groupingBundle = nullptr; while (U_SUCCESS(status) && ures_hasNext(groupingContainment.getAlias())) {
groupingBundle = ures_getNextResource(groupingContainment.getAlias(), groupingBundle, &status); if (U_FAILURE(status)) { break;
}
UnicodeString *groupingName = new UnicodeString(ures_getKey(groupingBundle), -1, US_INV);
LocalPointer<UnicodeString> lpGroupingName(groupingName, status);
groupings->adoptElement(lpGroupingName.orphan(), status); if (U_FAILURE(status)) { break;
}
Region* grouping = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), groupingName)); if (grouping != nullptr) { for (int32_t i = 0; i < ures_getSize(groupingBundle) && U_SUCCESS(status); i++) {
UnicodeString child = ures_getUnicodeStringByIndex(groupingBundle, i, &status); if (U_SUCCESS(status)) { if (grouping->containedRegions == nullptr) {
LocalPointer<UVector> lpContainedRegions( new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
grouping->containedRegions = lpContainedRegions.orphan(); if (U_FAILURE(status)) { break;
}
}
LocalPointer<UnicodeString> lpChildCopy(new UnicodeString(child), status);
grouping->containedRegions->adoptElement(lpChildCopy.orphan(), status);
}
}
}
}
ures_close(groupingBundle);
// Process the territory aliases while (U_SUCCESS(status) && ures_hasNext(territoryAlias.getAlias())) {
LocalUResourceBundlePointer res(ures_getNextResource(territoryAlias.getAlias(),nullptr,&status)); constchar *aliasFrom = ures_getKey(res.getAlias());
LocalPointer<UnicodeString> aliasFromStr(new UnicodeString(aliasFrom, -1, US_INV), status);
UnicodeString aliasTo = ures_getUnicodeStringByKey(res.getAlias(),"replacement",&status);
res.adoptInstead(nullptr);
if ( aliasToRegion != nullptr && aliasFromRegion == nullptr ) { // This is just an alias from some string to a region
uhash_put(newRegionAliases.getAlias(),(void *)aliasFromStr.orphan(), (void *)aliasToRegion,&status);
} else { if ( aliasFromRegion == nullptr ) { // Deprecated region code not in the primary codes list - so need to create a deprecated region for it.
LocalPointer<Region> newRgn(new Region, status); if ( U_SUCCESS(status) ) {
aliasFromRegion = newRgn.orphan();
} else { return; // error out
}
aliasFromRegion->idStr.setTo(*aliasFromStr);
aliasFromRegion->idStr.extract(0,aliasFromRegion->idStr.length(),aliasFromRegion->id,sizeof(aliasFromRegion->id),US_INV);
uhash_put(newRegionIDMap.getAlias(),(void *)&(aliasFromRegion->idStr),(void *)aliasFromRegion,&status);
int32_t pos = 0;
int32_t result = ICU_Utility::parseAsciiInteger(aliasFromRegion->idStr, pos); if ( pos > 0 ) {
aliasFromRegion->code = result; // Convert string to number
uhash_iput(newNumericCodeMap.getAlias(),aliasFromRegion->code,(void *)aliasFromRegion,&status);
} else {
aliasFromRegion->code = -1;
}
aliasFromRegion->fType = URGN_DEPRECATED;
} else {
aliasFromRegion->fType = URGN_DEPRECATED;
}
{
LocalPointer<UVector> newPreferredValues(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
aliasFromRegion->preferredValues = newPreferredValues.orphan();
} if( U_FAILURE(status)) { return;
}
UnicodeString currentRegion; //currentRegion.remove(); TODO: was already 0 length? for (int32_t i = 0 ; i < aliasTo.length() && U_SUCCESS(status); i++ ) { if ( aliasTo.charAt(i) != 0x0020 ) {
currentRegion.append(aliasTo.charAt(i));
} if ( aliasTo.charAt(i) == 0x0020 || i+1 == aliasTo.length() ) {
Region* target = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), ¤tRegion)); if (target) {
LocalPointer<UnicodeString> preferredValue(new UnicodeString(target->idStr), status);
aliasFromRegion->preferredValues->adoptElement(preferredValue.orphan(),status); // may add null if err
}
currentRegion.remove();
}
}
}
}
// Process the code mappings - This will allow us to assign numeric codes to most of the territories. while (U_SUCCESS(status) && ures_hasNext(codeMappings.getAlias())) {
UResourceBundle *mapping = ures_getNextResource(codeMappings.getAlias(),nullptr,&status); if (U_SUCCESS(status) && ures_getType(mapping) == URES_ARRAY && ures_getSize(mapping) == 3) {
UnicodeString codeMappingID = ures_getUnicodeStringByIndex(mapping,0,&status);
UnicodeString codeMappingNumber = ures_getUnicodeStringByIndex(mapping,1,&status);
UnicodeString codeMapping3Letter = ures_getUnicodeStringByIndex(mapping,2,&status);
Region* r = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), &codeMappingID)); if ( r ) {
int32_t pos = 0;
int32_t result = ICU_Utility::parseAsciiInteger(codeMappingNumber, pos); if ( pos > 0 ) {
r->code = result; // Convert string to number
uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)r,&status);
}
LocalPointer<UnicodeString> code3(new UnicodeString(codeMapping3Letter), status);
uhash_put(newRegionAliases.getAlias(),(void *)code3.orphan(), (void *)r,&status);
}
}
ures_close(mapping);
}
// Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
Region *r;
UnicodeString WORLD_ID_STRING(WORLD_ID);
r = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), &WORLD_ID_STRING)); if ( r ) {
r->fType = URGN_WORLD;
}
UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID);
r = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), &UNKNOWN_REGION_ID_STRING)); if ( r ) {
r->fType = URGN_UNKNOWN;
}
for ( int32_t i = 0 ; i < continents->size() ; i++ ) {
r = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), continents->elementAt(i))); if ( r ) {
r->fType = URGN_CONTINENT;
}
}
for ( int32_t i = 0 ; i < groupings->size() ; i++ ) {
r = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), groupings->elementAt(i))); if ( r ) {
r->fType = URGN_GROUPING;
}
}
// Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR // even though it looks like a territory code. Need to handle it here.
UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID);
r = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), &OUTLYING_OCEANIA_REGION_ID_STRING)); if ( r ) {
r->fType = URGN_SUBCONTINENT;
}
// Load territory containment info from the supplemental data. while ( ures_hasNext(territoryContainment.getAlias()) ) {
LocalUResourceBundlePointer mapping(ures_getNextResource(territoryContainment.getAlias(),nullptr,&status)); if( U_FAILURE(status) ) { return; // error out
} constchar *parent = ures_getKey(mapping.getAlias()); if (uprv_strcmp(parent, "containedGroupings") == 0 || uprv_strcmp(parent, "deprecated") == 0) { continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip. // #11232 is to do something useful with these.
}
UnicodeString parentStr = UnicodeString(parent, -1 , US_INV);
Region* parentRegion = static_cast<Region*>(uhash_get(newRegionIDMap.getAlias(), &parentStr));
// Add the child region to the set of regions contained by the parent if (parentRegion->containedRegions == nullptr) {
LocalPointer<UVector> lpContainedRegions( new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
parentRegion->containedRegions = lpContainedRegions.orphan(); if (U_FAILURE(status)) { return;
}
}
LocalPointer<UnicodeString> childStr(new UnicodeString(), status); if (U_FAILURE(status)) { return; // error out
}
childStr->fastCopyFrom(childRegion->idStr);
parentRegion->containedRegions->adoptElement(childStr.orphan(),status); if (U_FAILURE(status)) { return;
}
// 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 // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent. if ( parentRegion->fType != URGN_GROUPING) {
childRegion->containingRegion = parentRegion;
}
}
}
}
// Create the availableRegions lists
int32_t pos = UHASH_FIRST; while ( const UHashElement* element = uhash_nextElement(newRegionIDMap.getAlias(),&pos)) {
Region* ar = static_cast<Region*>(element->value.pointer); if ( availableRegions[ar->fType] == nullptr ) {
LocalPointer<UVector> newAr(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
availableRegions[ar->fType] = newAr.orphan();
}
LocalPointer<UnicodeString> arString(new UnicodeString(ar->idStr), status); if( U_FAILURE(status) ) { return; // error out
}
availableRegions[ar->fType]->adoptElement(arString.orphan(), status);
}
/** * Returns true if the two regions are equal. * Per PMC, just use pointer compare, since we have at most one instance of each Region.
*/ bool
Region::operator==(const Region &that) const { return (idStr == that.idStr);
}
/** * Returns true if the two regions are NOT equal; that is, if operator ==() returns false. * Per PMC, just use pointer compare, since we have at most one instance of each Region.
*/ bool
Region::operator!=(const Region &that) const { return (idStr != that.idStr);
}
/** * Returns a pointer to a Region using the given region code. The region code can be either 2-letter ISO code, * 3-letter ISO code, UNM.49 numeric code, or other valid Unicode Region Code as defined by the LDML specification. * The identifier will be canonicalized internally using the supplemental metadata as defined in the CLDR. * If the region code is nullptr or not recognized, the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR )
*/ const Region* U_EXPORT2
Region::getInstance(constchar *region_code, UErrorCode &status) {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); if (U_FAILURE(status)) { return nullptr;
}
if ( !region_code ) {
status = U_ILLEGAL_ARGUMENT_ERROR; return nullptr;
}
/** * Returns a pointer to a Region using the given numeric region code. If the numeric region code is not recognized, * the appropriate error code will be set ( U_ILLEGAL_ARGUMENT_ERROR ).
*/ const Region* U_EXPORT2
Region::getInstance (int32_t code, UErrorCode &status) {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); if (U_FAILURE(status)) { return nullptr;
}
Region* r = static_cast<Region*>(uhash_iget(numericCodeMap, code));
if ( !r ) { // Just in case there's an alias that's numeric, try to find it.
UnicodeString id;
ICU_Utility::appendNumber(id, code, 10, 1);
r = static_cast<Region*>(uhash_get(regionAliases, &id));
}
if( U_FAILURE(status) ) { return nullptr;
}
if ( !r ) {
status = U_ILLEGAL_ARGUMENT_ERROR; return nullptr;
}
/** * Returns an enumeration over the IDs of all known regions that match the given type.
*/
StringEnumeration* U_EXPORT2
Region::getAvailable(URegionType type, UErrorCode &status) {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status) if (U_FAILURE(status)) { return nullptr;
} returnnew RegionNameEnumeration(availableRegions[type],status);
}
/** * Returns a pointer to the region that contains this region. Returns nullptr if this region is code "001" (World) * or "ZZ" (Unknown region). For example, calling this method with region "IT" (Italy) returns the * region "039" (Southern Europe).
*/ const Region*
Region::getContainingRegion() const {
UErrorCode status = U_ZERO_ERROR;
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); return containingRegion;
}
/** * Return a pointer to the region that geographically contains this region and matches the given type, * moving multiple steps up the containment chain if necessary. Returns nullptr if no containing region can be found * that matches the given type. Note: The URegionTypes = "URGN_GROUPING", "URGN_DEPRECATED", or "URGN_UNKNOWN" * are not appropriate for use in this API. nullptr will be returned in this case. For example, calling this method * with region "IT" (Italy) for type "URGN_CONTINENT" returns the region "150" ( Europe ).
*/ const Region*
Region::getContainingRegion(URegionType type) const {
UErrorCode status = U_ZERO_ERROR;
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); if ( containingRegion == nullptr ) { return nullptr;
}
/** * Return an enumeration over the IDs of all the regions that are immediate children of this region in the * region hierarchy. These returned regions could be either macro regions, territories, or a mixture of the two, * depending on the containment data as defined in CLDR. This API may return nullptr if this region doesn't have * any sub-regions. For example, calling this method with region "150" (Europe) returns an enumeration containing * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe) - "154" (Northern Europe) * and "155" (Western Europe).
*/
StringEnumeration*
Region::getContainedRegions(UErrorCode &status) const {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status) if (U_FAILURE(status)) { return nullptr;
} returnnew RegionNameEnumeration(containedRegions,status);
}
/** * Returns an enumeration over the IDs of all the regions that are children of this region anywhere in the region * hierarchy and match the given type. This API may return an empty enumeration if this region doesn't have any * sub-regions that match the given type. For example, calling this method with region "150" (Europe) and type * "URGN_TERRITORY" returns a set containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. )
*/
StringEnumeration*
Region::getContainedRegions( URegionType type, UErrorCode &status ) const {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status)
/** * Returns true if this region contains the supplied other region anywhere in the region hierarchy.
*/
UBool
Region::contains(const Region &other) const {
UErrorCode status = U_ZERO_ERROR;
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status);
if (!containedRegions) { returnfalse;
} if (containedRegions->contains((void *)&other.idStr)) { returntrue;
} else { for ( int32_t i = 0 ; i < containedRegions->size() ; i++ ) {
UnicodeString* crStr = static_cast<UnicodeString*>(containedRegions->elementAt(i));
Region* cr = static_cast<Region*>(uhash_get(regionIDMap, crStr)); if ( cr && cr->contains(other) ) { returntrue;
}
}
}
returnfalse;
}
/** * For deprecated regions, return an enumeration over the IDs of the regions that are the preferred replacement * regions for this region. Returns nullptr for a non-deprecated region. For example, calling this method with region * "SU" (Soviet Union) would return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc...
*/
StringEnumeration*
Region::getPreferredValues(UErrorCode &status) const {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status) if (U_FAILURE(status) || fType != URGN_DEPRECATED) { return nullptr;
} returnnew RegionNameEnumeration(preferredValues,status);
}
/** * Return this region's canonical region code.
*/ constchar*
Region::getRegionCode() const { return id;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.