ulocdata.cpp (11787B)
1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ****************************************************************************** 5 * * 6 * Copyright (C) 2003-2016, International Business Machines * 7 * Corporation and others. All Rights Reserved. * 8 * * 9 ****************************************************************************** 10 * file name: ulocdata.c 11 * encoding: UTF-8 12 * tab size: 8 (not used) 13 * indentation:4 14 * 15 * created on: 2003Oct21 16 * created by: Ram Viswanadha,John Emmons 17 */ 18 19 #include "charstr.h" 20 #include "cmemory.h" 21 #include "unicode/ustring.h" 22 #include "unicode/ures.h" 23 #include "unicode/uloc.h" 24 #include "unicode/ulocdata.h" 25 #include "uresimp.h" 26 #include "ureslocs.h" 27 #include "ulocimp.h" 28 29 #define MEASUREMENT_SYSTEM "MeasurementSystem" 30 #define PAPER_SIZE "PaperSize" 31 32 /** A locale data object. 33 * For usage in C programs. 34 * @draft ICU 3.4 35 */ 36 struct ULocaleData { 37 /** 38 * Controls the "No Substitute" behavior of this locale data object 39 */ 40 UBool noSubstitute; 41 42 /** 43 * Pointer to the resource bundle associated with this locale data object 44 */ 45 UResourceBundle *bundle; 46 47 /** 48 * Pointer to the lang resource bundle associated with this locale data object 49 */ 50 UResourceBundle *langBundle; 51 }; 52 53 U_CAPI ULocaleData* U_EXPORT2 54 ulocdata_open(const char *localeID, UErrorCode *status) 55 { 56 ULocaleData *uld; 57 58 if (U_FAILURE(*status)) { 59 return nullptr; 60 } 61 62 uld = (ULocaleData *)uprv_malloc(sizeof(ULocaleData)); 63 if (uld == nullptr) { 64 *status = U_MEMORY_ALLOCATION_ERROR; 65 return(nullptr); 66 } 67 68 uld->langBundle = nullptr; 69 70 uld->noSubstitute = false; 71 uld->bundle = ures_open(nullptr, localeID, status); 72 73 if (U_FAILURE(*status)) { 74 uprv_free(uld); 75 return nullptr; 76 } 77 78 // ICU-22149: not all functions require lang data, so fail gracefully if it is not present 79 UErrorCode oldStatus = *status; 80 uld->langBundle = ures_open(U_ICUDATA_LANG, localeID, status); 81 if (*status == U_MISSING_RESOURCE_ERROR) { 82 *status = oldStatus; 83 } 84 85 return uld; 86 } 87 88 U_CAPI void U_EXPORT2 89 ulocdata_close(ULocaleData *uld) 90 { 91 if ( uld != nullptr ) { 92 ures_close(uld->langBundle); 93 ures_close(uld->bundle); 94 uprv_free(uld); 95 } 96 } 97 98 U_CAPI void U_EXPORT2 99 ulocdata_setNoSubstitute(ULocaleData *uld, UBool setting) 100 { 101 uld->noSubstitute = setting; 102 } 103 104 U_CAPI UBool U_EXPORT2 105 ulocdata_getNoSubstitute(ULocaleData *uld) 106 { 107 return uld->noSubstitute; 108 } 109 110 U_CAPI USet* U_EXPORT2 111 ulocdata_getExemplarSet(ULocaleData *uld, USet *fillIn, 112 uint32_t options, ULocaleDataExemplarSetType extype, UErrorCode *status){ 113 114 static const char* const exemplarSetTypes[] = { "ExemplarCharacters", 115 "AuxExemplarCharacters", 116 "ExemplarCharactersIndex", 117 "ExemplarCharactersPunctuation"}; 118 const char16_t *exemplarChars = nullptr; 119 int32_t len = 0; 120 UErrorCode localStatus = U_ZERO_ERROR; 121 122 if (U_FAILURE(*status)) 123 return nullptr; 124 125 exemplarChars = ures_getStringByKey(uld->bundle, exemplarSetTypes[extype], &len, &localStatus); 126 if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) { 127 localStatus = U_MISSING_RESOURCE_ERROR; 128 } 129 130 if (localStatus != U_ZERO_ERROR) { 131 *status = localStatus; 132 } 133 134 if (U_FAILURE(*status)) 135 return nullptr; 136 137 if(fillIn != nullptr) 138 uset_applyPattern(fillIn, exemplarChars, len, 139 USET_IGNORE_SPACE | options, status); 140 else 141 fillIn = uset_openPatternOptions(exemplarChars, len, 142 USET_IGNORE_SPACE | options, status); 143 144 return fillIn; 145 146 } 147 148 U_CAPI int32_t U_EXPORT2 149 ulocdata_getDelimiter(ULocaleData *uld, ULocaleDataDelimiterType type, 150 char16_t *result, int32_t resultLength, UErrorCode *status){ 151 152 static const char* const delimiterKeys[] = { 153 "quotationStart", 154 "quotationEnd", 155 "alternateQuotationStart", 156 "alternateQuotationEnd" 157 }; 158 159 UResourceBundle *delimiterBundle; 160 int32_t len = 0; 161 const char16_t *delimiter = nullptr; 162 UErrorCode localStatus = U_ZERO_ERROR; 163 164 if (U_FAILURE(*status)) 165 return 0; 166 167 delimiterBundle = ures_getByKey(uld->bundle, "delimiters", nullptr, &localStatus); 168 169 if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) { 170 localStatus = U_MISSING_RESOURCE_ERROR; 171 } 172 173 if (localStatus != U_ZERO_ERROR) { 174 *status = localStatus; 175 } 176 177 if (U_FAILURE(*status)){ 178 ures_close(delimiterBundle); 179 return 0; 180 } 181 182 delimiter = ures_getStringByKeyWithFallback(delimiterBundle, delimiterKeys[type], &len, &localStatus); 183 ures_close(delimiterBundle); 184 185 if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) { 186 localStatus = U_MISSING_RESOURCE_ERROR; 187 } 188 189 if (localStatus != U_ZERO_ERROR) { 190 *status = localStatus; 191 } 192 193 if (U_FAILURE(*status)){ 194 return 0; 195 } 196 197 u_strncpy(result,delimiter, resultLength); 198 return len; 199 } 200 201 namespace { 202 203 UResourceBundle * measurementTypeBundleForLocale(const char *localeID, const char *measurementType, UErrorCode *status){ 204 if (U_FAILURE(*status)) { return nullptr; } 205 206 UResourceBundle *rb; 207 UResourceBundle *measTypeBundle = nullptr; 208 209 icu::CharString region = ulocimp_getRegionForSupplementalData(localeID, true, *status); 210 211 rb = ures_openDirect(nullptr, "supplementalData", status); 212 ures_getByKey(rb, "measurementData", rb, status); 213 if (rb != nullptr) { 214 UResourceBundle *measDataBundle = ures_getByKey(rb, region.data(), nullptr, status); 215 if (U_SUCCESS(*status)) { 216 measTypeBundle = ures_getByKey(measDataBundle, measurementType, nullptr, status); 217 } 218 if (*status == U_MISSING_RESOURCE_ERROR) { 219 *status = U_ZERO_ERROR; 220 if (measDataBundle != nullptr) { 221 ures_close(measDataBundle); 222 } 223 measDataBundle = ures_getByKey(rb, "001", nullptr, status); 224 measTypeBundle = ures_getByKey(measDataBundle, measurementType, nullptr, status); 225 } 226 ures_close(measDataBundle); 227 } 228 ures_close(rb); 229 return measTypeBundle; 230 } 231 232 } // namespace 233 234 U_CAPI UMeasurementSystem U_EXPORT2 235 ulocdata_getMeasurementSystem(const char *localeID, UErrorCode *status){ 236 237 UResourceBundle* measurement=nullptr; 238 UMeasurementSystem system = UMS_LIMIT; 239 240 if(status == nullptr || U_FAILURE(*status)){ 241 return system; 242 } 243 244 measurement = measurementTypeBundleForLocale(localeID, MEASUREMENT_SYSTEM, status); 245 int32_t result = ures_getInt(measurement, status); 246 if (U_SUCCESS(*status)) { 247 system = static_cast<UMeasurementSystem>(result); 248 } 249 250 ures_close(measurement); 251 252 return system; 253 254 } 255 256 U_CAPI void U_EXPORT2 257 ulocdata_getPaperSize(const char* localeID, int32_t *height, int32_t *width, UErrorCode *status){ 258 UResourceBundle* paperSizeBundle = nullptr; 259 const int32_t* paperSize=nullptr; 260 int32_t len = 0; 261 262 if(status == nullptr || U_FAILURE(*status)){ 263 return; 264 } 265 266 paperSizeBundle = measurementTypeBundleForLocale(localeID, PAPER_SIZE, status); 267 paperSize = ures_getIntVector(paperSizeBundle, &len, status); 268 269 if(U_SUCCESS(*status)){ 270 if(len < 2){ 271 *status = U_INTERNAL_PROGRAM_ERROR; 272 }else{ 273 *height = paperSize[0]; 274 *width = paperSize[1]; 275 } 276 } 277 278 ures_close(paperSizeBundle); 279 280 } 281 282 U_CAPI void U_EXPORT2 283 ulocdata_getCLDRVersion(UVersionInfo versionArray, UErrorCode *status) { 284 if (U_FAILURE(*status)) { return; } 285 UResourceBundle *rb = nullptr; 286 rb = ures_openDirect(nullptr, "supplementalData", status); 287 ures_getVersionByKey(rb, "cldrVersion", versionArray, status); 288 ures_close(rb); 289 } 290 291 U_CAPI int32_t U_EXPORT2 292 ulocdata_getLocaleDisplayPattern(ULocaleData *uld, 293 char16_t *result, 294 int32_t resultCapacity, 295 UErrorCode *status) { 296 UResourceBundle *patternBundle; 297 int32_t len = 0; 298 const char16_t *pattern = nullptr; 299 UErrorCode localStatus = U_ZERO_ERROR; 300 301 if (U_FAILURE(*status)) 302 return 0; 303 304 if (uld->langBundle == nullptr) { 305 *status = U_MISSING_RESOURCE_ERROR; 306 return 0; 307 } 308 309 patternBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", nullptr, &localStatus); 310 311 if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) { 312 localStatus = U_MISSING_RESOURCE_ERROR; 313 } 314 315 if (localStatus != U_ZERO_ERROR) { 316 *status = localStatus; 317 } 318 319 if (U_FAILURE(*status)){ 320 ures_close(patternBundle); 321 return 0; 322 } 323 324 pattern = ures_getStringByKey(patternBundle, "pattern", &len, &localStatus); 325 ures_close(patternBundle); 326 327 if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) { 328 localStatus = U_MISSING_RESOURCE_ERROR; 329 } 330 331 if (localStatus != U_ZERO_ERROR) { 332 *status = localStatus; 333 } 334 335 if (U_FAILURE(*status)){ 336 return 0; 337 } 338 339 u_strncpy(result, pattern, resultCapacity); 340 return len; 341 } 342 343 344 U_CAPI int32_t U_EXPORT2 345 ulocdata_getLocaleSeparator(ULocaleData *uld, 346 char16_t *result, 347 int32_t resultCapacity, 348 UErrorCode *status) { 349 UResourceBundle *separatorBundle; 350 int32_t len = 0; 351 const char16_t *separator = nullptr; 352 UErrorCode localStatus = U_ZERO_ERROR; 353 char16_t *p0, *p1; 354 static const char16_t sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 }; /* {0} */ 355 static const char16_t sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 }; /* {1} */ 356 static const int32_t subLen = 3; 357 358 if (U_FAILURE(*status)) 359 return 0; 360 361 if (uld->langBundle == nullptr) { 362 *status = U_MISSING_RESOURCE_ERROR; 363 return 0; 364 } 365 366 separatorBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", nullptr, &localStatus); 367 368 if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) { 369 localStatus = U_MISSING_RESOURCE_ERROR; 370 } 371 372 if (localStatus != U_ZERO_ERROR) { 373 *status = localStatus; 374 } 375 376 if (U_FAILURE(*status)){ 377 ures_close(separatorBundle); 378 return 0; 379 } 380 381 separator = ures_getStringByKey(separatorBundle, "separator", &len, &localStatus); 382 ures_close(separatorBundle); 383 384 if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) { 385 localStatus = U_MISSING_RESOURCE_ERROR; 386 } 387 388 if (localStatus != U_ZERO_ERROR) { 389 *status = localStatus; 390 } 391 392 if (U_FAILURE(*status)){ 393 return 0; 394 } 395 396 /* For backwards compatibility, if we have a pattern, return the portion between {0} and {1} */ 397 p0=u_strstr(separator, sub0); 398 p1=u_strstr(separator, sub1); 399 if (p0!=nullptr && p1!=nullptr && p0<=p1) { 400 separator = (const char16_t *)p0 + subLen; 401 len = static_cast<int32_t>(p1 - separator); 402 /* Desired separator is no longer zero-terminated; handle that if necessary */ 403 if (len < resultCapacity) { 404 u_strncpy(result, separator, len); 405 result[len] = 0; 406 return len; 407 } 408 } 409 410 u_strncpy(result, separator, resultCapacity); 411 return len; 412 }