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
ulocdata_open(const char * localeID,UErrorCode * status)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
ulocdata_close(ULocaleData * uld)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
ulocdata_setNoSubstitute(ULocaleData * uld,UBool setting)99 ulocdata_setNoSubstitute(ULocaleData *uld, UBool setting)
100 {
101 uld->noSubstitute = setting;
102 }
103
104 U_CAPI UBool U_EXPORT2
ulocdata_getNoSubstitute(ULocaleData * uld)105 ulocdata_getNoSubstitute(ULocaleData *uld)
106 {
107 return uld->noSubstitute;
108 }
109
110 U_CAPI USet* U_EXPORT2
ulocdata_getExemplarSet(ULocaleData * uld,USet * fillIn,uint32_t options,ULocaleDataExemplarSetType extype,UErrorCode * status)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
ulocdata_getDelimiter(ULocaleData * uld,ULocaleDataDelimiterType type,char16_t * result,int32_t resultLength,UErrorCode * status)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
measurementTypeBundleForLocale(const char * localeID,const char * measurementType,UErrorCode * status)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
ulocdata_getMeasurementSystem(const char * localeID,UErrorCode * status)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
ulocdata_getPaperSize(const char * localeID,int32_t * height,int32_t * width,UErrorCode * status)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
ulocdata_getCLDRVersion(UVersionInfo versionArray,UErrorCode * status)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
ulocdata_getLocaleDisplayPattern(ULocaleData * uld,char16_t * result,int32_t resultCapacity,UErrorCode * status)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
ulocdata_getLocaleSeparator(ULocaleData * uld,char16_t * result,int32_t resultCapacity,UErrorCode * status)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 }
413