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