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