1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "ICU"
18
19 #include "ErrorCode.h"
20 #include "JNIHelp.h"
21 #include "JniConstants.h"
22 #include "ScopedJavaUnicodeString.h"
23 #include "ScopedLocalRef.h"
24 #include "ScopedUtfChars.h"
25 #include "UniquePtr.h"
26 #include "cutils/log.h"
27 #include "unicode/calendar.h"
28 #include "unicode/datefmt.h"
29 #include "unicode/dcfmtsym.h"
30 #include "unicode/decimfmt.h"
31 #include "unicode/dtfmtsym.h"
32 #include "unicode/gregocal.h"
33 #include "unicode/locid.h"
34 #include "unicode/numfmt.h"
35 #include "unicode/strenum.h"
36 #include "unicode/ubrk.h"
37 #include "unicode/ucal.h"
38 #include "unicode/uclean.h"
39 #include "unicode/ucol.h"
40 #include "unicode/ucurr.h"
41 #include "unicode/udat.h"
42 #include "unicode/ustring.h"
43 #include "ureslocs.h"
44 #include "valueOf.h"
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48 #include <sys/time.h>
49
50 class ScopedResourceBundle {
51 public:
ScopedResourceBundle(UResourceBundle * bundle)52 ScopedResourceBundle(UResourceBundle* bundle) : mBundle(bundle) {
53 }
54
~ScopedResourceBundle()55 ~ScopedResourceBundle() {
56 if (mBundle != NULL) {
57 ures_close(mBundle);
58 }
59 }
60
get()61 UResourceBundle* get() {
62 return mBundle;
63 }
64
65 private:
66 UResourceBundle* mBundle;
67
68 // Disallow copy and assignment.
69 ScopedResourceBundle(const ScopedResourceBundle&);
70 void operator=(const ScopedResourceBundle&);
71 };
72
getLocale(JNIEnv * env,jstring localeName)73 Locale getLocale(JNIEnv* env, jstring localeName) {
74 return Locale::createFromName(ScopedUtfChars(env, localeName).c_str());
75 }
76
ICU_getCurrencyFractionDigitsNative(JNIEnv * env,jclass,jstring javaCurrencyCode)77 static jint ICU_getCurrencyFractionDigitsNative(JNIEnv* env, jclass, jstring javaCurrencyCode) {
78 UErrorCode status = U_ZERO_ERROR;
79 UniquePtr<NumberFormat> fmt(NumberFormat::createCurrencyInstance(status));
80 if (U_FAILURE(status)) {
81 return -1;
82 }
83 ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
84 fmt->setCurrency(currencyCode.unicodeString().getBuffer(), status);
85 if (U_FAILURE(status)) {
86 return -1;
87 }
88 // for CurrencyFormats the minimum and maximum fraction digits are the same.
89 return fmt->getMinimumFractionDigits();
90 }
91
ICU_getCurrencyCodeNative(JNIEnv * env,jclass,jstring javaKey)92 static jstring ICU_getCurrencyCodeNative(JNIEnv* env, jclass, jstring javaKey) {
93 UErrorCode status = U_ZERO_ERROR;
94 ScopedResourceBundle supplData(ures_openDirect(U_ICUDATA_CURR, "supplementalData", &status));
95 if (U_FAILURE(status)) {
96 return NULL;
97 }
98
99 ScopedResourceBundle currencyMap(ures_getByKey(supplData.get(), "CurrencyMap", NULL, &status));
100 if (U_FAILURE(status)) {
101 return NULL;
102 }
103
104 ScopedUtfChars key(env, javaKey);
105 ScopedResourceBundle currency(ures_getByKey(currencyMap.get(), key.c_str(), NULL, &status));
106 if (U_FAILURE(status)) {
107 return NULL;
108 }
109
110 ScopedResourceBundle currencyElem(ures_getByIndex(currency.get(), 0, NULL, &status));
111 if (U_FAILURE(status)) {
112 return env->NewStringUTF("None");
113 }
114
115 // check if there is a 'to' date. If there is, the currency isn't used anymore.
116 ScopedResourceBundle currencyTo(ures_getByKey(currencyElem.get(), "to", NULL, &status));
117 if (!U_FAILURE(status)) {
118 // return and let the caller throw an exception
119 return NULL;
120 }
121 // We need to reset 'status'. It works like errno in that ICU doesn't set it
122 // to U_ZERO_ERROR on success: it only touches it on error, and the test
123 // above means it now holds a failure code.
124 status = U_ZERO_ERROR;
125
126 ScopedResourceBundle currencyId(ures_getByKey(currencyElem.get(), "id", NULL, &status));
127 if (U_FAILURE(status)) {
128 // No id defined for this country
129 return env->NewStringUTF("None");
130 }
131
132 int length;
133 const jchar* id = ures_getString(currencyId.get(), &length, &status);
134 if (U_FAILURE(status) || length == 0) {
135 return env->NewStringUTF("None");
136 }
137 return env->NewString(id, length);
138 }
139
ICU_getCurrencySymbolNative(JNIEnv * env,jclass,jstring locale,jstring currencyCode)140 static jstring ICU_getCurrencySymbolNative(JNIEnv* env, jclass, jstring locale, jstring currencyCode) {
141 ScopedUtfChars localeName(env, locale);
142 UErrorCode status = U_ZERO_ERROR;
143 ScopedResourceBundle currLoc(ures_open(U_ICUDATA_CURR, localeName.c_str(), &status));
144 if (U_FAILURE(status)) {
145 return NULL;
146 }
147
148 ScopedResourceBundle currencies(ures_getByKey(currLoc.get(), "Currencies", NULL, &status));
149 if (U_FAILURE(status)) {
150 return NULL;
151 }
152
153 ScopedUtfChars currency(env, currencyCode);
154 ScopedResourceBundle currencyElems(ures_getByKey(currencies.get(), currency.c_str(), NULL, &status));
155 if (U_FAILURE(status)) {
156 return NULL;
157 }
158
159 int currSymbL;
160 const jchar* currSymbU = ures_getStringByIndex(currencyElems.get(), 0, &currSymbL, &status);
161 if (U_FAILURE(status)) {
162 return NULL;
163 }
164
165 return (currSymbL == 0) ? NULL : env->NewString(currSymbU, currSymbL);
166 }
167
ICU_getDisplayCountryNative(JNIEnv * env,jclass,jstring targetLocale,jstring locale)168 static jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
169 Locale loc = getLocale(env, locale);
170 Locale targetLoc = getLocale(env, targetLocale);
171 UnicodeString str;
172 targetLoc.getDisplayCountry(loc, str);
173 return env->NewString(str.getBuffer(), str.length());
174 }
175
ICU_getDisplayLanguageNative(JNIEnv * env,jclass,jstring targetLocale,jstring locale)176 static jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
177 Locale loc = getLocale(env, locale);
178 Locale targetLoc = getLocale(env, targetLocale);
179 UnicodeString str;
180 targetLoc.getDisplayLanguage(loc, str);
181 return env->NewString(str.getBuffer(), str.length());
182 }
183
ICU_getDisplayVariantNative(JNIEnv * env,jclass,jstring targetLocale,jstring locale)184 static jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
185 Locale loc = getLocale(env, locale);
186 Locale targetLoc = getLocale(env, targetLocale);
187 UnicodeString str;
188 targetLoc.getDisplayVariant(loc, str);
189 return env->NewString(str.getBuffer(), str.length());
190 }
191
ICU_getISO3CountryNative(JNIEnv * env,jclass,jstring locale)192 static jstring ICU_getISO3CountryNative(JNIEnv* env, jclass, jstring locale) {
193 Locale loc = getLocale(env, locale);
194 return env->NewStringUTF(loc.getISO3Country());
195 }
196
ICU_getISO3LanguageNative(JNIEnv * env,jclass,jstring locale)197 static jstring ICU_getISO3LanguageNative(JNIEnv* env, jclass, jstring locale) {
198 Locale loc = getLocale(env, locale);
199 return env->NewStringUTF(loc.getISO3Language());
200 }
201
toStringArray(JNIEnv * env,const char * const * strings)202 static jobjectArray toStringArray(JNIEnv* env, const char* const* strings) {
203 size_t count = 0;
204 while (strings[count] != NULL) {
205 ++count;
206 }
207 jobjectArray result = env->NewObjectArray(count, JniConstants::stringClass, NULL);
208 for (size_t i = 0; i < count; ++i) {
209 ScopedLocalRef<jstring> s(env, env->NewStringUTF(strings[i]));
210 env->SetObjectArrayElement(result, i, s.get());
211 }
212 return result;
213 }
214
ICU_getISOCountriesNative(JNIEnv * env,jclass)215 static jobjectArray ICU_getISOCountriesNative(JNIEnv* env, jclass) {
216 return toStringArray(env, Locale::getISOCountries());
217 }
218
ICU_getISOLanguagesNative(JNIEnv * env,jclass)219 static jobjectArray ICU_getISOLanguagesNative(JNIEnv* env, jclass) {
220 return toStringArray(env, Locale::getISOLanguages());
221 }
222
223 template <typename Counter, typename Getter>
getAvailableLocales(JNIEnv * env,Counter * counter,Getter * getter)224 static jobjectArray getAvailableLocales(JNIEnv* env, Counter* counter, Getter* getter) {
225 size_t count = (*counter)();
226 jobjectArray result = env->NewObjectArray(count, JniConstants::stringClass, NULL);
227 for (size_t i = 0; i < count; ++i) {
228 ScopedLocalRef<jstring> s(env, env->NewStringUTF((*getter)(i)));
229 env->SetObjectArrayElement(result, i, s.get());
230 }
231 return result;
232 }
233
ICU_getAvailableLocalesNative(JNIEnv * env,jclass)234 static jobjectArray ICU_getAvailableLocalesNative(JNIEnv* env, jclass) {
235 return getAvailableLocales(env, uloc_countAvailable, uloc_getAvailable);
236 }
237
ICU_getAvailableBreakIteratorLocalesNative(JNIEnv * env,jclass)238 static jobjectArray ICU_getAvailableBreakIteratorLocalesNative(JNIEnv* env, jclass) {
239 return getAvailableLocales(env, ubrk_countAvailable, ubrk_getAvailable);
240 }
241
ICU_getAvailableCalendarLocalesNative(JNIEnv * env,jclass)242 static jobjectArray ICU_getAvailableCalendarLocalesNative(JNIEnv* env, jclass) {
243 return getAvailableLocales(env, ucal_countAvailable, ucal_getAvailable);
244 }
245
ICU_getAvailableCollatorLocalesNative(JNIEnv * env,jclass)246 static jobjectArray ICU_getAvailableCollatorLocalesNative(JNIEnv* env, jclass) {
247 return getAvailableLocales(env, ucol_countAvailable, ucol_getAvailable);
248 }
249
ICU_getAvailableDateFormatLocalesNative(JNIEnv * env,jclass)250 static jobjectArray ICU_getAvailableDateFormatLocalesNative(JNIEnv* env, jclass) {
251 return getAvailableLocales(env, udat_countAvailable, udat_getAvailable);
252 }
253
ICU_getAvailableNumberFormatLocalesNative(JNIEnv * env,jclass)254 static jobjectArray ICU_getAvailableNumberFormatLocalesNative(JNIEnv* env, jclass) {
255 return getAvailableLocales(env, unum_countAvailable, unum_getAvailable);
256 }
257
getDayIntVector(JNIEnv *,UResourceBundle * gregorian,int * values)258 static bool getDayIntVector(JNIEnv*, UResourceBundle* gregorian, int* values) {
259 // get the First day of week and the minimal days in first week numbers
260 UErrorCode status = U_ZERO_ERROR;
261 ScopedResourceBundle gregorianElems(ures_getByKey(gregorian, "DateTimeElements", NULL, &status));
262 if (U_FAILURE(status)) {
263 return false;
264 }
265
266 int intVectSize;
267 const int* result = ures_getIntVector(gregorianElems.get(), &intVectSize, &status);
268 if (U_FAILURE(status) || intVectSize != 2) {
269 return false;
270 }
271
272 values[0] = result[0];
273 values[1] = result[1];
274 return true;
275 }
276
getAmPmMarkers(JNIEnv * env,UResourceBundle * gregorian)277 static jobjectArray getAmPmMarkers(JNIEnv* env, UResourceBundle* gregorian) {
278 UErrorCode status = U_ZERO_ERROR;
279 ScopedResourceBundle gregorianElems(ures_getByKey(gregorian, "AmPmMarkers", NULL, &status));
280 if (U_FAILURE(status)) {
281 return NULL;
282 }
283
284 int lengthAm, lengthPm;
285 const jchar* am = ures_getStringByIndex(gregorianElems.get(), 0, &lengthAm, &status);
286 const jchar* pm = ures_getStringByIndex(gregorianElems.get(), 1, &lengthPm, &status);
287
288 if (U_FAILURE(status)) {
289 return NULL;
290 }
291
292 jobjectArray amPmMarkers = env->NewObjectArray(2, JniConstants::stringClass, NULL);
293 ScopedLocalRef<jstring> amU(env, env->NewString(am, lengthAm));
294 env->SetObjectArrayElement(amPmMarkers, 0, amU.get());
295 ScopedLocalRef<jstring> pmU(env, env->NewString(pm, lengthPm));
296 env->SetObjectArrayElement(amPmMarkers, 1, pmU.get());
297
298 return amPmMarkers;
299 }
300
getEras(JNIEnv * env,UResourceBundle * gregorian)301 static jobjectArray getEras(JNIEnv* env, UResourceBundle* gregorian) {
302 UErrorCode status = U_ZERO_ERROR;
303 ScopedResourceBundle gregorianElems(ures_getByKey(gregorian, "eras", NULL, &status));
304 if (U_FAILURE(status)) {
305 return NULL;
306 }
307
308 ScopedResourceBundle eraElems(ures_getByKey(gregorianElems.get(), "abbreviated", NULL, &status));
309 if (U_FAILURE(status)) {
310 return NULL;
311 }
312
313 int eraCount = ures_getSize(eraElems.get());
314 jobjectArray eras = env->NewObjectArray(eraCount, JniConstants::stringClass, NULL);
315 for (int i = 0; i < eraCount; ++i) {
316 int eraLength;
317 const jchar* era = ures_getStringByIndex(eraElems.get(), i, &eraLength, &status);
318 if (U_FAILURE(status)) {
319 return NULL;
320 }
321 ScopedLocalRef<jstring> eraU(env, env->NewString(era, eraLength));
322 env->SetObjectArrayElement(eras, i, eraU.get());
323 }
324 return eras;
325 }
326
327 enum NameType { REGULAR, STAND_ALONE };
328 enum NameWidth { LONG, SHORT };
getNames(JNIEnv * env,UResourceBundle * namesBundle,bool months,NameType type,NameWidth width)329 static jobjectArray getNames(JNIEnv* env, UResourceBundle* namesBundle, bool months, NameType type, NameWidth width) {
330 const char* typeKey = (type == REGULAR) ? "format" : "stand-alone";
331 const char* widthKey = (width == LONG) ? "wide" : "abbreviated";
332 UErrorCode status = U_ZERO_ERROR;
333 ScopedResourceBundle formatBundle(ures_getByKey(namesBundle, typeKey, NULL, &status));
334 ScopedResourceBundle valuesBundle(ures_getByKey(formatBundle.get(), widthKey, NULL, &status));
335 if (U_FAILURE(status)) {
336 return NULL;
337 }
338
339 // The months array has a trailing empty string. The days array has a leading empty string.
340 int count = ures_getSize(valuesBundle.get());
341 jobjectArray result = env->NewObjectArray(count + 1, JniConstants::stringClass, NULL);
342 env->SetObjectArrayElement(result, months ? count : 0, env->NewStringUTF(""));
343 int arrayOffset = months ? 0 : 1;
344 for (int i = 0; i < count; ++i) {
345 int nameLength;
346 const jchar* name = ures_getStringByIndex(valuesBundle.get(), i, &nameLength, &status);
347 if (U_FAILURE(status)) {
348 return NULL;
349 }
350 ScopedLocalRef<jstring> nameString(env, env->NewString(name, nameLength));
351 env->SetObjectArrayElement(result, arrayOffset++, nameString.get());
352 }
353 return result;
354 }
355
getIntCurrencyCode(JNIEnv * env,jstring locale)356 static jstring getIntCurrencyCode(JNIEnv* env, jstring locale) {
357 ScopedUtfChars localeChars(env, locale);
358
359 // Extract the 2-character country name.
360 if (strlen(localeChars.c_str()) < 5) {
361 return NULL;
362 }
363 if (localeChars[3] < 'A' || localeChars[3] > 'Z' || localeChars[4] < 'A' || localeChars[4] > 'Z') {
364 return NULL;
365 }
366
367 char country[3] = { localeChars[3], localeChars[4], 0 };
368 return ICU_getCurrencyCodeNative(env, NULL, env->NewStringUTF(country));
369 }
370
setIntegerField(JNIEnv * env,jobject obj,const char * fieldName,int value)371 static void setIntegerField(JNIEnv* env, jobject obj, const char* fieldName, int value) {
372 ScopedLocalRef<jobject> integerValue(env, integerValueOf(env, value));
373 jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "Ljava/lang/Integer;");
374 env->SetObjectField(obj, fid, integerValue.get());
375 }
376
setStringField(JNIEnv * env,jobject obj,const char * fieldName,jstring value)377 static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, jstring value) {
378 jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "Ljava/lang/String;");
379 env->SetObjectField(obj, fid, value);
380 }
381
setStringArrayField(JNIEnv * env,jobject obj,const char * fieldName,jobjectArray value)382 static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, jobjectArray value) {
383 jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "[Ljava/lang/String;");
384 env->SetObjectField(obj, fid, value);
385 }
386
setStringField(JNIEnv * env,jobject obj,const char * fieldName,UResourceBundle * bundle,int index)387 static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
388 UErrorCode status = U_ZERO_ERROR;
389 int charCount;
390 const UChar* chars = ures_getStringByIndex(bundle, index, &charCount, &status);
391 if (U_SUCCESS(status)) {
392 setStringField(env, obj, fieldName, env->NewString(chars, charCount));
393 } else {
394 LOGE("Error setting String field %s from ICU resource: %s", fieldName, u_errorName(status));
395 }
396 }
397
setCharField(JNIEnv * env,jobject obj,const char * fieldName,UResourceBundle * bundle,int index)398 static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
399 UErrorCode status = U_ZERO_ERROR;
400 int charCount;
401 const UChar* chars = ures_getStringByIndex(bundle, index, &charCount, &status);
402 if (U_SUCCESS(status)) {
403 jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "C");
404 env->SetCharField(obj, fid, chars[0]);
405 } else {
406 LOGE("Error setting char field %s from ICU resource: %s", fieldName, u_errorName(status));
407 }
408 }
409
ICU_initLocaleDataImpl(JNIEnv * env,jclass,jstring locale,jobject localeData)410 static jboolean ICU_initLocaleDataImpl(JNIEnv* env, jclass, jstring locale, jobject localeData) {
411 ScopedUtfChars localeName(env, locale);
412 UErrorCode status = U_ZERO_ERROR;
413 ScopedResourceBundle root(ures_open(NULL, localeName.c_str(), &status));
414 if (U_FAILURE(status)) {
415 LOGE("Error getting ICU resource bundle: %s", u_errorName(status));
416 status = U_ZERO_ERROR;
417 return JNI_FALSE;
418 }
419
420 ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
421 if (U_FAILURE(status)) {
422 LOGE("Error getting ICU calendar resource bundle: %s", u_errorName(status));
423 return JNI_FALSE;
424 }
425
426 ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
427 if (U_FAILURE(status)) {
428 LOGE("Error getting ICU gregorian resource bundle: %s", u_errorName(status));
429 return JNI_FALSE;
430 }
431
432 int firstDayVals[] = { 0, 0 };
433 if (getDayIntVector(env, gregorian.get(), firstDayVals)) {
434 setIntegerField(env, localeData, "firstDayOfWeek", firstDayVals[0]);
435 setIntegerField(env, localeData, "minimalDaysInFirstWeek", firstDayVals[1]);
436 }
437
438 setStringArrayField(env, localeData, "amPm", getAmPmMarkers(env, gregorian.get()));
439 setStringArrayField(env, localeData, "eras", getEras(env, gregorian.get()));
440
441 ScopedResourceBundle dayNames(ures_getByKey(gregorian.get(), "dayNames", NULL, &status));
442 ScopedResourceBundle monthNames(ures_getByKey(gregorian.get(), "monthNames", NULL, &status));
443
444 // Get the regular month and weekday names.
445 jobjectArray longMonthNames = getNames(env, monthNames.get(), true, REGULAR, LONG);
446 jobjectArray shortMonthNames = getNames(env, monthNames.get(), true, REGULAR, SHORT);
447 jobjectArray longWeekdayNames = getNames(env, dayNames.get(), false, REGULAR, LONG);
448 jobjectArray shortWeekdayNames = getNames(env, dayNames.get(), false, REGULAR, SHORT);
449 setStringArrayField(env, localeData, "longMonthNames", longMonthNames);
450 setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames);
451 setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames);
452 setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames);
453
454 // Get the stand-alone month and weekday names. If they're not available (as they aren't for
455 // English), we reuse the regular names. If we returned null to Java, the usual fallback
456 // mechanisms would come into play and we'd end up with the bogus stand-alone names from the
457 // root locale ("1" for January, and so on).
458 jobjectArray longStandAloneMonthNames = getNames(env, monthNames.get(), true, STAND_ALONE, LONG);
459 if (longStandAloneMonthNames == NULL) {
460 longStandAloneMonthNames = longMonthNames;
461 }
462 jobjectArray shortStandAloneMonthNames = getNames(env, monthNames.get(), true, STAND_ALONE, SHORT);
463 if (shortStandAloneMonthNames == NULL) {
464 shortStandAloneMonthNames = shortMonthNames;
465 }
466 jobjectArray longStandAloneWeekdayNames = getNames(env, dayNames.get(), false, STAND_ALONE, LONG);
467 if (longStandAloneWeekdayNames == NULL) {
468 longStandAloneWeekdayNames = longWeekdayNames;
469 }
470 jobjectArray shortStandAloneWeekdayNames = getNames(env, dayNames.get(), false, STAND_ALONE, SHORT);
471 if (shortStandAloneWeekdayNames == NULL) {
472 shortStandAloneWeekdayNames = shortWeekdayNames;
473 }
474 setStringArrayField(env, localeData, "longStandAloneMonthNames", longStandAloneMonthNames);
475 setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames);
476 setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames);
477 setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames);
478
479 ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
480 if (U_SUCCESS(status)) {
481 setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
482 setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
483 setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
484 setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
485 setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
486 setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
487 setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
488 setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
489 }
490 status = U_ZERO_ERROR;
491
492 ScopedResourceBundle numberElements(ures_getByKey(root.get(), "NumberElements", NULL, &status));
493 if (U_SUCCESS(status) && ures_getSize(numberElements.get()) >= 11) {
494 setCharField(env, localeData, "zeroDigit", numberElements.get(), 4);
495 setCharField(env, localeData, "digit", numberElements.get(), 5);
496 setCharField(env, localeData, "decimalSeparator", numberElements.get(), 0);
497 setCharField(env, localeData, "groupingSeparator", numberElements.get(), 1);
498 setCharField(env, localeData, "patternSeparator", numberElements.get(), 2);
499 setCharField(env, localeData, "percent", numberElements.get(), 3);
500 setCharField(env, localeData, "perMill", numberElements.get(), 8);
501 setCharField(env, localeData, "monetarySeparator", numberElements.get(), 0);
502 setCharField(env, localeData, "minusSign", numberElements.get(), 6);
503 setStringField(env, localeData, "exponentSeparator", numberElements.get(), 7);
504 setStringField(env, localeData, "infinity", numberElements.get(), 9);
505 setStringField(env, localeData, "NaN", numberElements.get(), 10);
506 }
507 status = U_ZERO_ERROR;
508
509 jstring internationalCurrencySymbol = getIntCurrencyCode(env, locale);
510 jstring currencySymbol = NULL;
511 if (internationalCurrencySymbol != NULL) {
512 currencySymbol = ICU_getCurrencySymbolNative(env, NULL, locale, internationalCurrencySymbol);
513 } else {
514 internationalCurrencySymbol = env->NewStringUTF("XXX");
515 }
516 if (currencySymbol == NULL) {
517 // This is the UTF-8 encoding of U+00A4 (CURRENCY SIGN).
518 currencySymbol = env->NewStringUTF("\xc2\xa4");
519 }
520 setStringField(env, localeData, "currencySymbol", currencySymbol);
521 setStringField(env, localeData, "internationalCurrencySymbol", internationalCurrencySymbol);
522
523 ScopedResourceBundle numberPatterns(ures_getByKey(root.get(), "NumberPatterns", NULL, &status));
524 if (U_SUCCESS(status) && ures_getSize(numberPatterns.get()) >= 3) {
525 setStringField(env, localeData, "numberPattern", numberPatterns.get(), 0);
526 setStringField(env, localeData, "currencyPattern", numberPatterns.get(), 1);
527 setStringField(env, localeData, "percentPattern", numberPatterns.get(), 2);
528 }
529
530 return JNI_TRUE;
531 }
532
ICU_toLowerCase(JNIEnv * env,jclass,jstring javaString,jstring localeName)533 static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) {
534 ScopedJavaUnicodeString scopedString(env, javaString);
535 UnicodeString& s(scopedString.unicodeString());
536 UnicodeString original(s);
537 s.toLower(Locale::createFromName(ScopedUtfChars(env, localeName).c_str()));
538 return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
539 }
540
ICU_toUpperCase(JNIEnv * env,jclass,jstring javaString,jstring localeName)541 static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) {
542 ScopedJavaUnicodeString scopedString(env, javaString);
543 UnicodeString& s(scopedString.unicodeString());
544 UnicodeString original(s);
545 s.toUpper(Locale::createFromName(ScopedUtfChars(env, localeName).c_str()));
546 return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
547 }
548
549 static JNINativeMethod gMethods[] = {
550 NATIVE_METHOD(ICU, getAvailableBreakIteratorLocalesNative, "()[Ljava/lang/String;"),
551 NATIVE_METHOD(ICU, getAvailableCalendarLocalesNative, "()[Ljava/lang/String;"),
552 NATIVE_METHOD(ICU, getAvailableCollatorLocalesNative, "()[Ljava/lang/String;"),
553 NATIVE_METHOD(ICU, getAvailableDateFormatLocalesNative, "()[Ljava/lang/String;"),
554 NATIVE_METHOD(ICU, getAvailableLocalesNative, "()[Ljava/lang/String;"),
555 NATIVE_METHOD(ICU, getAvailableNumberFormatLocalesNative, "()[Ljava/lang/String;"),
556 NATIVE_METHOD(ICU, getCurrencyCodeNative, "(Ljava/lang/String;)Ljava/lang/String;"),
557 NATIVE_METHOD(ICU, getCurrencyFractionDigitsNative, "(Ljava/lang/String;)I"),
558 NATIVE_METHOD(ICU, getCurrencySymbolNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
559 NATIVE_METHOD(ICU, getDisplayCountryNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
560 NATIVE_METHOD(ICU, getDisplayLanguageNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
561 NATIVE_METHOD(ICU, getDisplayVariantNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
562 NATIVE_METHOD(ICU, getISO3CountryNative, "(Ljava/lang/String;)Ljava/lang/String;"),
563 NATIVE_METHOD(ICU, getISO3LanguageNative, "(Ljava/lang/String;)Ljava/lang/String;"),
564 NATIVE_METHOD(ICU, getISOCountriesNative, "()[Ljava/lang/String;"),
565 NATIVE_METHOD(ICU, getISOLanguagesNative, "()[Ljava/lang/String;"),
566 NATIVE_METHOD(ICU, initLocaleDataImpl, "(Ljava/lang/String;Lcom/ibm/icu4jni/util/LocaleData;)Z"),
567 NATIVE_METHOD(ICU, toLowerCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
568 NATIVE_METHOD(ICU, toUpperCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
569 };
register_com_ibm_icu4jni_util_ICU(JNIEnv * env)570 int register_com_ibm_icu4jni_util_ICU(JNIEnv* env) {
571 return jniRegisterNativeMethods(env, "com/ibm/icu4jni/util/ICU", gMethods, NELEM(gMethods));
572 }
573