]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/ualoc.cpp
ICU-531.30.tar.gz
[apple/icu.git] / icuSources / common / ualoc.cpp
CommitLineData
57a6839d
A
1/*
2*****************************************************************************************
3* Copyright (C) 2014 Apple Inc. All Rights Reserved.
4*****************************************************************************************
5*/
6
7#include "unicode/utypes.h"
8#include "unicode/ualoc.h"
9#include "unicode/uloc.h"
10#include "unicode/ures.h"
11#include "unicode/putil.h"
12#include "cstring.h"
13#include "cmemory.h"
14// the following has replacements for some math.h funcs etc
15#include "putilimp.h"
16
17
18// The numeric values in territoryInfo are in "IntF" format from LDML2ICUConverter.
19// From its docs (adapted): [IntF is] a special integer that represents the number in
20// normalized scientific notation.
21// Resultant integers are in the form -?xxyyyyyy, where xx is the exponent
22// offset by 50 and yyyyyy is the coefficient to 5 decimal places (range 1.0 to 9.99999), e.g.
23// 14660000000000 -> 1.46600E13 -> 63146600
24// 0.0001 -> 1.00000E-4 -> 46100000
25// -123.456 -> -1.23456E-2 -> -48123456
26//
27// Here to avoid an extra division we have the max coefficient as 999999 (instead of
28// 9.99999) and instead offset the exponent by -55.
29//
30static double doubleFromIntF(int32_t intF) {
31 double coefficient = (double)(intF % 1000000);
32 int32_t exponent = (intF / 1000000) - 55;
33 return coefficient * uprv_pow10(exponent);
34}
35
36static int compareLangEntries(const void * entry1, const void * entry2) {
37 double fraction1 = ((const UALanguageEntry *)entry1)->userFraction;
38 double fraction2 = ((const UALanguageEntry *)entry2)->userFraction;
39 // want descending order
40 if (fraction1 > fraction2) return -1;
41 if (fraction1 < fraction2) return 1;
42 // userFractions the same, sort by languageCode
43 return uprv_strcmp(((const UALanguageEntry *)entry1)->languageCode,((const UALanguageEntry *)entry2)->languageCode);
44}
45
46static const UChar ustrLangStatusDefacto[] = {0x64,0x65,0x5F,0x66,0x61,0x63,0x74,0x6F,0x5F,0x6F,0x66,0x66,0x69,0x63,0x69,0x61,0x6C,0}; //"de_facto_official"
47static const UChar ustrLangStatusOfficial[] = {0x6F,0x66,0x66,0x69,0x63,0x69,0x61,0x6C,0}; //"official"
48static const UChar ustrLangStatusRegional[] = {0x6F,0x66,0x66,0x69,0x63,0x69,0x61,0x6C,0x5F,0x72,0x65,0x67,0x69,0x6F,0x6E,0x61,0x6C,0}; //"official_regional"
49
50enum {
51 kLocalLangEntriesMax = 26, // enough for most regions to minimumFraction 0.001 except India
52 kLangEntriesFactor = 3 // if we have to allocate, multiply existing size by this
53};
54
55U_CAPI int32_t U_EXPORT2
56ualoc_getLanguagesForRegion(const char *regionID, double minimumFraction,
57 UALanguageEntry *entries, int32_t entriesCapacity,
58 UErrorCode *err)
59{
60 if (U_FAILURE(*err)) {
61 return 0;
62 }
63 if ( regionID == NULL || minimumFraction < 0.0 || minimumFraction > 1.0 ||
64 ((entries==NULL)? entriesCapacity!=0: entriesCapacity<0) ) {
65 *err = U_ILLEGAL_ARGUMENT_ERROR;
66 return 0;
67 }
68 UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", err);
69 rb = ures_getByKey(rb, "territoryInfo", rb, err);
70 rb = ures_getByKey(rb, regionID, rb, err);
71 if (U_FAILURE(*err)) {
72 ures_close(rb);
73 return 0;
74 }
75
76 int32_t entryCount = 0;
77 UResourceBundle *langBund = NULL;
78 int32_t lbIdx, lbCount = ures_getSize(rb);
79 UALanguageEntry localLangEntries[kLocalLangEntriesMax];
80 UALanguageEntry * langEntries = localLangEntries;
81 int32_t langEntriesMax = kLocalLangEntriesMax;
82
83 for (lbIdx = 0; lbIdx < lbCount; lbIdx++) {
84 langBund = ures_getByIndex(rb, lbIdx, langBund, err);
85 if (U_FAILURE(*err)) {
86 break;
87 }
88 const char * langCode = ures_getKey(langBund);
89 if (uprv_strcmp(langCode,"territoryF") == 0) {
90 continue;
91 }
92 if (strnlen(langCode, UALANGDATA_CODELEN+1) > UALANGDATA_CODELEN) { // no uprv_strnlen
93 continue; // a code we cannot handle
94 }
95
96 UErrorCode localErr = U_ZERO_ERROR;
97 double userFraction = 0.0;
98 UResourceBundle *itemBund = ures_getByKey(langBund, "populationShareF", NULL, &localErr);
99 if (U_SUCCESS(localErr)) {
100 int32_t intF = ures_getInt(itemBund, &localErr);
101 if (U_SUCCESS(localErr)) {
102 userFraction = doubleFromIntF(intF);
103 }
104 ures_close(itemBund);
105 }
106 if (userFraction < minimumFraction) {
107 continue;
108 }
109 if (entries != NULL) {
110 localErr = U_ZERO_ERROR;
111 UALanguageStatus langStatus = UALANGSTATUS_UNSPECIFIED;
112 int32_t ulen;
113 const UChar * ustrLangStatus = ures_getStringByKey(langBund, "officialStatus", &ulen, &localErr);
114 if (U_SUCCESS(localErr)) {
115 int32_t cmp = u_strcmp(ustrLangStatus, ustrLangStatusOfficial);
116 if (cmp == 0) {
117 langStatus = UALANGSTATUS_OFFICIAL;
118 } else if (cmp < 0 && u_strcmp(ustrLangStatus, ustrLangStatusDefacto) == 0) {
119 langStatus = UALANGSTATUS_DEFACTO_OFFICIAL;
120 } else if (u_strcmp(ustrLangStatus, ustrLangStatusRegional) == 0) {
121 langStatus = UALANGSTATUS_REGIONAL_OFFICIAL;
122 }
123 }
124 // Now we have all of the info for our next entry
125 if (entryCount >= langEntriesMax) {
126 int32_t newMax = langEntriesMax * kLangEntriesFactor;
127 if (langEntries == localLangEntries) {
128 // first allocation, copy from local buf
129 langEntries = (UALanguageEntry*)uprv_malloc(newMax*sizeof(UALanguageEntry));
130 if (langEntries == NULL) {
131 *err = U_MEMORY_ALLOCATION_ERROR;
132 break;
133 }
134 uprv_memcpy(langEntries, localLangEntries, entryCount*sizeof(UALanguageEntry));
135 } else {
136 langEntries = (UALanguageEntry*)uprv_realloc(langEntries, newMax*sizeof(UALanguageEntry));
137 if (langEntries == NULL) {
138 *err = U_MEMORY_ALLOCATION_ERROR;
139 break;
140 }
141 }
142 langEntriesMax = newMax;
143 }
144 uprv_strcpy(langEntries[entryCount].languageCode, langCode);
145 langEntries[entryCount].userFraction = userFraction;
146 langEntries[entryCount].status = langStatus;
147 }
148 entryCount++;
149 }
150 ures_close(langBund);
151 ures_close(rb);
152 if (U_FAILURE(*err)) {
153 if (langEntries != localLangEntries) {
154 free(langEntries);
155 }
156 return 0;
157 }
158 if (entries != NULL) {
159 // sort langEntries, copy entries that fit to provided array
160 qsort(langEntries, entryCount, sizeof(UALanguageEntry), compareLangEntries);
161 if (entryCount > entriesCapacity) {
162 entryCount = entriesCapacity;
163 }
164 uprv_memcpy(entries, langEntries, entryCount*sizeof(UALanguageEntry));
165 if (langEntries != localLangEntries) {
166 free(langEntries);
167 }
168 }
169 return entryCount;
170}
171
172
173static const char * forceParent[] = {
174 "zh", "zh_CN",
175 "zh_CN", "root",
176 "zh_Hant", "zh_TW",
177 "zh_TW", "root",
178 NULL
179};
180
181U_CAPI int32_t U_EXPORT2
182ualoc_getAppleParent(const char* localeID,
183 char * parent,
184 int32_t parentCapacity,
185 UErrorCode* err)
186{
187 UResourceBundle *rb;
188 int32_t len;
189 UErrorCode tempStatus;
190 char locbuf[ULOC_FULLNAME_CAPACITY+1];
191
192 if (U_FAILURE(*err)) {
193 return 0;
194 }
195 if ( (parent==NULL)? parentCapacity!=0: parentCapacity<0 ) {
196 *err = U_ILLEGAL_ARGUMENT_ERROR;
197 return 0;
198 }
199 len = uloc_canonicalize(localeID, locbuf, ULOC_FULLNAME_CAPACITY, err);
200 if (U_FAILURE(*err)) {
201 return 0;
202 }
203 if (*err == U_STRING_NOT_TERMINATED_WARNING) {
204 locbuf[ULOC_FULLNAME_CAPACITY] = 0;
205 *err = U_ZERO_ERROR;
206 }
207 if (len >= 2 && uprv_strncmp(locbuf, "zh", 2) == 0) {
208 const char ** forceParentPtr = forceParent;
209 const char * testCurLoc;
210 while ( (testCurLoc = *forceParentPtr++) != NULL ) {
211 int cmp = uprv_strcmp(locbuf, testCurLoc);
212 if (cmp <= 0) {
213 if (cmp == 0) {
214 len = uprv_strlen(*forceParentPtr);
215 if (len < parentCapacity) {
216 uprv_strcpy(parent, *forceParentPtr);
217 } else {
218 *err = U_BUFFER_OVERFLOW_ERROR;
219 }
220 return len;
221 }
222 break;
223 }
224 forceParentPtr++;
225 }
226 }
227 tempStatus = U_ZERO_ERROR;
228 rb = ures_openDirect(NULL, locbuf, &tempStatus);
229 if (U_SUCCESS(tempStatus)) {
230 const char * actualLocale = ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &tempStatus);
231 if (U_SUCCESS(tempStatus) && uprv_strcmp(locbuf, actualLocale) != 0) {
232 // we have followed an alias
233 len = uprv_strlen(actualLocale);
234 if (len < parentCapacity) {
235 uprv_strcpy(parent, actualLocale);
236 } else {
237 *err = U_BUFFER_OVERFLOW_ERROR;
238 }
239 ures_close(rb);
240 return len;
241 }
242 tempStatus = U_ZERO_ERROR;
243 const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &len, &tempStatus);
244 if (U_SUCCESS(tempStatus) && tempStatus != U_USING_FALLBACK_WARNING) {
245 if (len < parentCapacity) {
246 u_UCharsToChars(parentUName, parent, len + 1);
247 } else {
248 *err = U_BUFFER_OVERFLOW_ERROR;
249 }
250 ures_close(rb);
251 return len;
252 }
253 ures_close(rb);
254 }
255 len = uloc_getParent(locbuf, parent, parentCapacity, err);
256 if (U_SUCCESS(*err) && len == 0) {
257 len = 4;
258 if (len < parentCapacity) {
259 uprv_strcpy(parent, "root");
260 } else {
261 *err = U_BUFFER_OVERFLOW_ERROR;
262 }
263 }
264 return len;
265}
266