2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "AndroidSystemNatives.h"
19 #include "unicode/numfmt.h"
20 #include "unicode/locid.h"
21 #include "unicode/ucal.h"
22 #include "unicode/gregocal.h"
23 #include "unicode/ucurr.h"
24 #include "unicode/calendar.h"
25 #include "unicode/datefmt.h"
26 #include "unicode/dtfmtsym.h"
27 #include "unicode/decimfmt.h"
28 #include "unicode/dcfmtsym.h"
29 #include "unicode/uclean.h"
30 #include "unicode/smpdtfmt.h"
31 #include "unicode/strenum.h"
32 #include "unicode/ustring.h"
33 #include "unicode/timezone.h"
34 #include "ErrorCode.h"
35 #include <cutils/log.h>
43 static UBool icuError(JNIEnv *env, UErrorCode errorcode)
45 const char *emsg = u_errorName(errorcode);
48 if (U_FAILURE(errorcode)) {
50 case U_ILLEGAL_ARGUMENT_ERROR :
51 exception = env->FindClass("java/lang/IllegalArgumentException");
53 case U_INDEX_OUTOFBOUNDS_ERROR :
54 case U_BUFFER_OVERFLOW_ERROR :
55 exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
57 case U_UNSUPPORTED_ERROR :
58 exception = env->FindClass("java/lang/UnsupportedOperationException");
61 exception = env->FindClass("java/lang/RuntimeException");
64 return (env->ThrowNew(exception, emsg) != 0);
69 static Locale getLocale(JNIEnv *env, jstring locale) {
70 const char *name = env->GetStringUTFChars(locale, NULL);
71 Locale result = Locale::createFromName(name);
72 env->ReleaseStringUTFChars(locale, name);
76 static jstring getJStringFromUnicodeString(JNIEnv *env, UnicodeString string) {
78 UErrorCode status = U_ZERO_ERROR;
80 int stringLength = string.length();
81 jchar *res = (jchar *) malloc(sizeof(jchar) * (stringLength + 1));
82 string.extract(res, stringLength+1, status);
83 if(U_FAILURE(status)) {
85 LOGI("Error getting string for getJStringFromUnicodeString");
86 status = U_ZERO_ERROR;
89 jstring result = env->NewString(res, stringLength);
94 static void addObject(JNIEnv *env, jobjectArray result, const char *keyStr, jobject elem, int index) {
95 jclass objArray_class = env->FindClass("java/lang/Object");
96 jobjectArray element = env->NewObjectArray(2, objArray_class, NULL);
97 jstring key = env->NewStringUTF(keyStr);
98 env->SetObjectArrayElement(element, 0, key);
99 env->SetObjectArrayElement(element, 1, elem);
100 env->SetObjectArrayElement(result, index, element);
101 env->DeleteLocalRef(key);
102 env->DeleteLocalRef(element);
105 static jint getFractionDigitsNative(JNIEnv* env, jclass clazz,
106 jstring currencyCode) {
107 // LOGI("ENTER getFractionDigitsNative");
109 UErrorCode status = U_ZERO_ERROR;
111 NumberFormat *fmt = NumberFormat::createCurrencyInstance(status);
112 if(U_FAILURE(status)) {
116 const jchar *cCode = env->GetStringChars(currencyCode, NULL);
117 fmt->setCurrency(cCode, status);
118 env->ReleaseStringChars(currencyCode, cCode);
119 if(U_FAILURE(status)) {
123 // for CurrencyFormats the minimum and maximum fraction digits are the same.
124 int result = fmt->getMinimumFractionDigits();
129 static jstring getCurrencyCodeNative(JNIEnv* env, jclass clazz,
131 // LOGI("ENTER getCurrencyCodeNative");
133 UErrorCode status = U_ZERO_ERROR;
135 UResourceBundle *supplData = ures_openDirect(NULL, "supplementalData", &status);
136 if(U_FAILURE(status)) {
140 UResourceBundle *currencyMap = ures_getByKey(supplData, "CurrencyMap", NULL, &status);
141 if(U_FAILURE(status)) {
142 ures_close(supplData);
146 const char *keyChars = env->GetStringUTFChars(key, NULL);
147 UResourceBundle *currency = ures_getByKey(currencyMap, keyChars, NULL, &status);
148 env->ReleaseStringUTFChars(key, keyChars);
149 if(U_FAILURE(status)) {
150 ures_close(currencyMap);
151 ures_close(supplData);
155 UResourceBundle *currencyElem = ures_getByIndex(currency, 0, NULL, &status);
156 if(U_FAILURE(status)) {
157 ures_close(currency);
158 ures_close(currencyMap);
159 ures_close(supplData);
160 return env->NewStringUTF("None");
163 // check if there is a to date. If there is, the currency isn't used anymore.
164 UResourceBundle *currencyTo = ures_getByKey(currencyElem, "to", NULL, &status);
165 if(!U_FAILURE(status)) {
166 // return and let the ResourceBundle throw an exception
167 ures_close(currencyElem);
168 ures_close(currency);
169 ures_close(currencyMap);
170 ures_close(supplData);
173 status = U_ZERO_ERROR;
174 ures_close(currencyTo);
176 UResourceBundle *currencyId = ures_getByKey(currencyElem, "id", NULL, &status);
177 if(U_FAILURE(status)) {
178 // No id defined for this country
179 ures_close(currencyElem);
180 ures_close(currency);
181 ures_close(currencyMap);
182 ures_close(supplData);
183 return env->NewStringUTF("None");
187 const jchar *id = ures_getString(currencyId, &length, &status);
188 if(U_FAILURE(status)) {
189 ures_close(currencyId);
190 ures_close(currencyElem);
191 ures_close(currency);
192 ures_close(currencyMap);
193 ures_close(supplData);
194 return env->NewStringUTF("None");
197 ures_close(currencyId);
198 ures_close(currencyElem);
199 ures_close(currency);
200 ures_close(currencyMap);
201 ures_close(supplData);
204 return env->NewStringUTF("None");
206 return env->NewString(id, length);
209 static jstring getCurrencySymbolNative(JNIEnv* env, jclass clazz,
210 jstring locale, jstring currencyCode) {
211 // LOGI("ENTER getCurrencySymbolNative");
213 UErrorCode status = U_ZERO_ERROR;
215 const char *locName = env->GetStringUTFChars(locale, NULL);
216 UResourceBundle *root = ures_open(NULL, locName, &status);
217 env->ReleaseStringUTFChars(locale, locName);
218 if(U_FAILURE(status)) {
222 UResourceBundle *rootElems = ures_getByKey(root, "Currencies", NULL, &status);
223 if(U_FAILURE(status)) {
228 const char *currName = env->GetStringUTFChars(currencyCode, NULL);
229 UResourceBundle *currencyElems = ures_getByKey(rootElems, currName, NULL, &status);
230 env->ReleaseStringUTFChars(currencyCode, currName);
231 if(U_FAILURE(status)) {
232 ures_close(rootElems);
238 const jchar *currSymbU = ures_getStringByIndex(currencyElems, 0, &currSymbL, &status);
239 if(U_FAILURE(status)) {
240 ures_close(currencyElems);
241 ures_close(rootElems);
246 ures_close(currencyElems);
247 ures_close(rootElems);
253 return env->NewString(currSymbU, currSymbL);
256 static jstring getDisplayCountryNative(JNIEnv* env, jclass clazz,
257 jstring targetLocale, jstring locale) {
258 // LOGI("ENTER getDisplayCountryNative");
260 UErrorCode status = U_ZERO_ERROR;
262 Locale loc = getLocale(env, locale);
263 Locale targetLoc = getLocale(env, targetLocale);
265 UnicodeString string;
266 targetLoc.getDisplayCountry(loc, string);
268 jstring result = getJStringFromUnicodeString(env, string);
273 static jstring getDisplayLanguageNative(JNIEnv* env, jclass clazz,
274 jstring targetLocale, jstring locale) {
275 // LOGI("ENTER getDisplayLanguageNative");
277 Locale loc = getLocale(env, locale);
278 Locale targetLoc = getLocale(env, targetLocale);
280 UnicodeString string;
281 targetLoc.getDisplayLanguage(loc, string);
283 jstring result = getJStringFromUnicodeString(env, string);
288 static jstring getDisplayVariantNative(JNIEnv* env, jclass clazz,
289 jstring targetLocale, jstring locale) {
290 // LOGI("ENTER getDisplayVariantNative");
292 Locale loc = getLocale(env, locale);
293 Locale targetLoc = getLocale(env, targetLocale);
295 UnicodeString string;
296 targetLoc.getDisplayVariant(loc, string);
298 jstring result = getJStringFromUnicodeString(env, string);
303 static jstring getISO3CountryNative(JNIEnv* env, jclass clazz, jstring locale) {
304 // LOGI("ENTER getISO3CountryNative");
306 Locale loc = getLocale(env, locale);
308 const char *string = loc.getISO3Country();
310 jstring result = env->NewStringUTF(string);
315 static jstring getISO3LanguageNative(JNIEnv* env, jclass clazz, jstring locale) {
316 // LOGI("ENTER getISO3LanguageNative");
318 Locale loc = getLocale(env, locale);
320 const char *string = loc.getISO3Language();
322 jstring result = env->NewStringUTF(string);
327 static jobjectArray getISOCountriesNative(JNIEnv* env, jclass clazz) {
328 // LOGI("ENTER getISOCountriesNative");
330 const char* const* strings = Locale::getISOCountries();
333 while(strings[count] != NULL) {
337 jobjectArray result = env->NewObjectArray(count, string_class, NULL);
340 for(int i = 0; i < count; i++) {
341 res = env->NewStringUTF(strings[i]);
342 env->SetObjectArrayElement(result, i, res);
343 env->DeleteLocalRef(res);
348 static jobjectArray getISOLanguagesNative(JNIEnv* env, jclass clazz) {
349 // LOGI("ENTER getISOLanguagesNative");
351 const char* const* strings = Locale::getISOLanguages();
353 const char *string = strings[0];
356 while(strings[count] != NULL) {
360 jobjectArray result = env->NewObjectArray(count, string_class, NULL);
363 for(int i = 0; i < count; i++) {
364 res = env->NewStringUTF(strings[i]);
365 env->SetObjectArrayElement(result, i, res);
366 env->DeleteLocalRef(res);
371 static jobjectArray getAvailableLocalesNative(JNIEnv* env, jclass clazz) {
372 // LOGI("ENTER getAvailableLocalesNative");
374 int count = uloc_countAvailable();
376 jobjectArray result = env->NewObjectArray(count, string_class, NULL);
380 for(int i = 0; i < count; i++) {
381 string = uloc_getAvailable(i);
382 res = env->NewStringUTF(string);
383 env->SetObjectArrayElement(result, i, res);
384 env->DeleteLocalRef(res);
390 static void getTimeZonesNative(JNIEnv* env, jclass clazz,
391 jobjectArray outerArray, jstring locale) {
392 // LOGI("ENTER getTimeZonesNative");
394 UErrorCode status = U_ZERO_ERROR;
396 jobjectArray zoneIdArray;
397 jobjectArray longStdTimeArray;
398 jobjectArray shortStdTimeArray;
399 jobjectArray longDlTimeArray;
400 jobjectArray shortDlTimeArray;
407 const UnicodeString *zoneID;
410 UnicodeString longPattern("zzzz","");
411 UnicodeString shortPattern("z","");
413 Locale loc = getLocale(env, locale);
415 SimpleDateFormat longFormat(longPattern, loc, status);
416 SimpleDateFormat shortFormat(shortPattern, loc, status);
419 zoneIdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 0);
420 longStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 1);
421 shortStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 2);
422 longDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 3);
423 shortDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 4);
425 int count = env->GetArrayLength(zoneIdArray);
427 TimeZone* zones[count];
429 // get all timezone objects
430 for(int i = 0; i < count; i++) {
431 strObj = (jstring) env->GetObjectArrayElement(zoneIdArray, i);
432 length = env->GetStringLength(strObj);
433 res = env->GetStringChars(strObj, NULL);
434 const UnicodeString zoneID((UChar *)res, length);
435 env->ReleaseStringChars(strObj, res);
436 zones[i] = TimeZone::createTimeZone(zoneID);
437 env->DeleteLocalRef(strObj);
441 UDate date1 = 1203105600000.0;
443 UDate date2 = 1218826800000.0;
445 for (int i = 0; i < count; i++) {
446 TimeZone *tz = zones[i];
447 longFormat.setTimeZone(*tz);
448 shortFormat.setTimeZone(*tz);
450 int32_t daylightOffset;
453 UDate daylightSavingDate;
454 tz->getOffset(date1, false, rawOffset, daylightOffset, status);
455 if (daylightOffset != 0) {
456 // The Timezone is reporting that we are in daylight time
457 // for the winter date. The dates are for the wrong hemisphere,
459 standardDate = date2;
460 daylightSavingDate = date1;
462 standardDate = date1;
463 daylightSavingDate = date2;
466 UnicodeString shortDayLight;
467 UnicodeString longDayLight;
468 UnicodeString shortStandard;
469 UnicodeString longStandard;
471 shortFormat.format(daylightSavingDate, shortDayLight);
472 content = getJStringFromUnicodeString(env, shortDayLight);
473 env->SetObjectArrayElement(shortDlTimeArray, i, content);
474 env->DeleteLocalRef(content);
476 shortFormat.format(standardDate, shortStandard);
477 content = getJStringFromUnicodeString(env, shortStandard);
478 env->SetObjectArrayElement(shortStdTimeArray, i, content);
479 env->DeleteLocalRef(content);
481 longFormat.format (daylightSavingDate, longDayLight);
482 content = getJStringFromUnicodeString(env, longDayLight);
483 env->SetObjectArrayElement(longDlTimeArray, i, content);
484 env->DeleteLocalRef(content);
486 longFormat.format (standardDate, longStandard);
487 content = getJStringFromUnicodeString(env, longStandard);
488 env->SetObjectArrayElement(longStdTimeArray, i, content);
489 env->DeleteLocalRef(content);
497 static jstring getDisplayTimeZoneNative(JNIEnv* env, jclass clazz,
498 jstring zoneID, jboolean isDST, jint style, jstring localeID) {
500 // Build TimeZone object
501 const jchar* idChars = env->GetStringChars(zoneID, NULL);
502 jint idLength = env->GetStringLength(zoneID);
503 UnicodeString idString((UChar*)idChars, idLength);
504 TimeZone* zone = TimeZone::createTimeZone(idString);
505 env->ReleaseStringChars(zoneID, idChars);
507 // Build Locale object (can we rely on zero termination of JNI result?)
508 const char* localeChars = env->GetStringUTFChars(localeID, NULL);
509 jint localeLength = env->GetStringLength(localeID);
510 Locale locale = Locale::createFromName(localeChars);
512 // Try to get the display name of the TimeZone according to the Locale
513 UnicodeString buffer;
514 zone->getDisplayName((UBool)isDST, (style == 0 ? TimeZone::SHORT : TimeZone::LONG), locale, buffer);
515 const UChar* tempChars = buffer.getBuffer();
516 int tempLength = buffer.length();
517 jstring result = env->NewString((jchar*)tempChars, tempLength);
518 env->ReleaseStringUTFChars(localeID, localeChars);
520 // Clean up everything
526 static void getDayInitVector(JNIEnv *env, UResourceBundle *gregorian, int *values) {
528 UErrorCode status = U_ZERO_ERROR;
530 // get the First day of week and the minimal days in first week numbers
531 UResourceBundle *gregorianElems = ures_getByKey(gregorian, "DateTimeElements", NULL, &status);
532 if(U_FAILURE(status)) {
538 result = ures_getIntVector(gregorianElems, &intVectSize, &status);
539 if(U_FAILURE(status)) {
540 ures_close(gregorianElems);
544 if(intVectSize == 2) {
545 values[0] = result[0];
546 values[1] = result[1];
549 ures_close(gregorianElems);
553 static jobjectArray getAmPmMarkers(JNIEnv *env, UResourceBundle *gregorian) {
555 jobjectArray amPmMarkers;
558 UErrorCode status = U_ZERO_ERROR;
560 UResourceBundle *gregorianElems;
562 gregorianElems = ures_getByKey(gregorian, "AmPmMarkers", NULL, &status);
563 if(U_FAILURE(status)) {
567 int lengthAm, lengthPm;
569 ures_resetIterator(gregorianElems);
571 const jchar* am = ures_getStringByIndex(gregorianElems, 0, &lengthAm, &status);
572 const jchar* pm = ures_getStringByIndex(gregorianElems, 1, &lengthPm, &status);
574 if(U_FAILURE(status)) {
575 ures_close(gregorianElems);
579 amPmMarkers = env->NewObjectArray(2, string_class, NULL);
580 amU = env->NewString(am, lengthAm);
581 env->SetObjectArrayElement(amPmMarkers, 0, amU);
582 env->DeleteLocalRef(amU);
583 pmU = env->NewString(pm, lengthPm);
584 env->SetObjectArrayElement(amPmMarkers, 1, pmU);
585 env->DeleteLocalRef(pmU);
586 ures_close(gregorianElems);
591 static jobjectArray getEras(JNIEnv* env, UResourceBundle *gregorian) {
597 UErrorCode status = U_ZERO_ERROR;
599 UResourceBundle *gregorianElems;
600 UResourceBundle *eraElems;
602 gregorianElems = ures_getByKey(gregorian, "eras", NULL, &status);
603 if(U_FAILURE(status)) {
607 eraElems = ures_getByKey(gregorianElems, "abbreviated", NULL, &status);
608 if(U_FAILURE(status)) {
609 ures_close(gregorianElems);
615 int eraCount = ures_getSize(eraElems);
616 eras = env->NewObjectArray(eraCount, string_class, NULL);
618 ures_resetIterator(eraElems);
619 for(int i = 0; i < eraCount; i++) {
620 era = ures_getStringByIndex(eraElems, i, &eraLength, &status);
621 if(U_FAILURE(status)) {
622 ures_close(gregorianElems);
623 ures_close(eraElems);
626 eraU = env->NewString(era, eraLength);
627 env->SetObjectArrayElement(eras, i, eraU);
628 env->DeleteLocalRef(eraU);
630 ures_close(eraElems);
631 ures_close(gregorianElems);
636 static jobjectArray getMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
638 UErrorCode status = U_ZERO_ERROR;
643 UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
644 if(U_FAILURE(status)) {
648 UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
649 if(U_FAILURE(status)) {
650 ures_close(gregorianElems);
654 UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "wide", NULL, &status);
655 if(U_FAILURE(status)) {
656 ures_close(monthNameElems);
657 ures_close(gregorianElems);
662 ures_resetIterator(monthNameElemsFormat);
663 int monthCount = ures_getSize(monthNameElemsFormat);
664 jobjectArray months = env->NewObjectArray(monthCount + 1, string_class, NULL);
665 for(int i = 0; i < monthCount; i++) {
666 month = ures_getStringByIndex(monthNameElemsFormat, i, &monthNameLength, &status);
667 if(U_FAILURE(status)) {
668 ures_close(monthNameElemsFormat);
669 ures_close(monthNameElems);
670 ures_close(gregorianElems);
673 monthU = env->NewString(month, monthNameLength);
674 env->SetObjectArrayElement(months, i, monthU);
675 env->DeleteLocalRef(monthU);
678 monthU = env->NewStringUTF("");
679 env->SetObjectArrayElement(months, monthCount, monthU);
680 env->DeleteLocalRef(monthU);
682 ures_close(monthNameElemsFormat);
683 ures_close(monthNameElems);
684 ures_close(gregorianElems);
688 static jobjectArray getShortMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
690 UErrorCode status = U_ZERO_ERROR;
692 const jchar* shortMonth;
695 UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
696 if(U_FAILURE(status)) {
700 UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
701 if(U_FAILURE(status)) {
702 ures_close(gregorianElems);
706 UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "abbreviated", NULL, &status);
707 if(U_FAILURE(status)) {
708 ures_close(monthNameElems);
709 ures_close(gregorianElems);
713 int shortMonthNameLength;
714 ures_resetIterator(monthNameElemsFormat);
715 int shortMonthCount = ures_getSize(monthNameElemsFormat);
716 // the array length is +1 because the harmony locales had an empty string at the end of their month name array
717 jobjectArray shortMonths = env->NewObjectArray(shortMonthCount + 1, string_class, NULL);
718 for(int i = 0; i < shortMonthCount; i++) {
719 shortMonth = ures_getStringByIndex(monthNameElemsFormat, i, &shortMonthNameLength, &status);
720 if(U_FAILURE(status)) {
721 ures_close(monthNameElemsFormat);
722 ures_close(monthNameElems);
723 ures_close(gregorianElems);
726 shortMonthU = env->NewString(shortMonth, shortMonthNameLength);
727 env->SetObjectArrayElement(shortMonths, i, shortMonthU);
728 env->DeleteLocalRef(shortMonthU);
731 shortMonthU = env->NewStringUTF("");
732 env->SetObjectArrayElement(shortMonths, shortMonthCount, shortMonthU);
733 env->DeleteLocalRef(shortMonthU);
735 ures_close(monthNameElemsFormat);
736 ures_close(monthNameElems);
737 ures_close(gregorianElems);
741 static jobjectArray getWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
743 UErrorCode status = U_ZERO_ERROR;
748 UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
749 if(U_FAILURE(status)) {
753 UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
754 if(U_FAILURE(status)) {
755 ures_close(gregorianElems);
759 UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "wide", NULL, &status);
760 if(U_FAILURE(status)) {
761 ures_close(dayNameElems);
762 ures_close(gregorianElems);
767 ures_resetIterator(dayNameElemsFormat);
768 int dayCount = ures_getSize(dayNameElemsFormat);
769 jobjectArray weekdays = env->NewObjectArray(dayCount + 1, string_class, NULL);
770 // first entry in the weekdays array is an empty string
771 env->SetObjectArrayElement(weekdays, 0, env->NewStringUTF(""));
772 for(int i = 0; i < dayCount; i++) {
773 day = ures_getStringByIndex(dayNameElemsFormat, i, &dayNameLength, &status);
774 if(U_FAILURE(status)) {
775 ures_close(dayNameElemsFormat);
776 ures_close(dayNameElems);
777 ures_close(gregorianElems);
780 dayU = env->NewString(day, dayNameLength);
781 env->SetObjectArrayElement(weekdays, i + 1, dayU);
782 env->DeleteLocalRef(dayU);
785 ures_close(dayNameElemsFormat);
786 ures_close(dayNameElems);
787 ures_close(gregorianElems);
792 static jobjectArray getShortWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
794 UErrorCode status = U_ZERO_ERROR;
796 const jchar* shortDay;
799 UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
800 if(U_FAILURE(status)) {
804 UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
805 if(U_FAILURE(status)) {
806 ures_close(gregorianElems);
810 UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "abbreviated", NULL, &status);
811 if(U_FAILURE(status)) {
812 ures_close(dayNameElems);
813 ures_close(gregorianElems);
817 int shortDayNameLength;
818 ures_resetIterator(dayNameElemsFormat);
819 int shortDayCount = ures_getSize(dayNameElemsFormat);
820 jobjectArray shortWeekdays = env->NewObjectArray(shortDayCount + 1, string_class, NULL);
821 env->SetObjectArrayElement(shortWeekdays, 0, env->NewStringUTF(""));
822 for(int i = 0; i < shortDayCount; i++) {
823 shortDay = ures_getStringByIndex(dayNameElemsFormat, i, &shortDayNameLength, &status);
824 if(U_FAILURE(status)) {
825 ures_close(dayNameElemsFormat);
826 ures_close(dayNameElems);
827 ures_close(gregorianElems);
830 shortDayU = env->NewString(shortDay, shortDayNameLength);
831 env->SetObjectArrayElement(shortWeekdays, i + 1, shortDayU);
832 env->DeleteLocalRef(shortDayU);
835 ures_close(dayNameElemsFormat);
836 ures_close(dayNameElems);
837 ures_close(gregorianElems);
838 return shortWeekdays;
841 static jstring getDecimalPatternChars(JNIEnv *env, UResourceBundle *rootElems) {
843 UErrorCode status = U_ZERO_ERROR;
845 int zeroL, digitL, decSepL, groupL, listL, percentL, permillL, expL, currSepL, minusL;
850 const jchar* zero = ures_getStringByIndex(rootElems, 4, &zeroL, &status);
852 const jchar* digit = ures_getStringByIndex(rootElems, 5, &digitL, &status);
854 const jchar* decSep = ures_getStringByIndex(rootElems, 0, &decSepL, &status);
856 const jchar* group = ures_getStringByIndex(rootElems, 1, &groupL, &status);
858 const jchar* list = ures_getStringByIndex(rootElems, 2, &listL, &status);
860 const jchar* percent = ures_getStringByIndex(rootElems, 3, &percentL, &status);
862 const jchar* permill = ures_getStringByIndex(rootElems, 8, &permillL, &status);
864 const jchar* exp = ures_getStringByIndex(rootElems, 7, &expL, &status);
866 const jchar* currSep = ures_getStringByIndex(rootElems, 0, &currSepL, &status);
868 const jchar* minus = ures_getStringByIndex(rootElems, 6, &minusL, &status);
870 if(U_FAILURE(status)) {
875 patternChars = (jchar *) malloc(11 * sizeof(jchar));
879 u_strncat(patternChars, zero, 1);
880 u_strncat(patternChars, digit, 1);
881 u_strncat(patternChars, decSep, 1);
882 u_strncat(patternChars, group, 1);
883 u_strncat(patternChars, list, 1);
884 u_strncat(patternChars, percent, 1);
885 u_strncat(patternChars, permill, 1);
886 u_strncat(patternChars, exp, 1);
887 u_strncat(patternChars, currSep, 1);
888 u_strncat(patternChars, minus, 1);
890 jstring decimalPatternChars = env->NewString(patternChars, 10);
894 return decimalPatternChars;
897 static jstring getIntCurrencyCode(JNIEnv *env, jclass clazz, jstring locale) {
899 const char *locStr = env->GetStringUTFChars(locale, NULL);
900 char country[3] = {0,0,0};
902 // getting the 2 character country name
903 if(strlen(locStr) < 5) {
904 env->ReleaseStringUTFChars(locale, locStr);
907 if(locStr[3] < 'A' || locStr[3] > 'Z' || locStr[4] < 'A' || locStr[4] > 'Z') {
908 env->ReleaseStringUTFChars(locale, locStr);
911 country[0] = locStr[3];
912 country[1] = locStr[4];
914 env->ReleaseStringUTFChars(locale, locStr);
916 return getCurrencyCodeNative(env, clazz, env->NewStringUTF(country));
919 static jstring getCurrencySymbol(JNIEnv *env, jclass clazz, jstring locale, jstring intCurrencySymbol) {
921 jstring result = getCurrencySymbolNative(env, clazz, locale, intCurrencySymbol);
922 if(result == intCurrencySymbol) {
929 static jobjectArray getContentImpl(JNIEnv* env, jclass clazz,
930 jstring locale, jboolean needsTZ) {
932 UErrorCode status = U_ZERO_ERROR;
934 const char *loc = env->GetStringUTFChars(locale, NULL);
935 UResourceBundle *root = ures_openU(NULL, loc, &status);
937 env->ReleaseStringUTFChars(locale, loc);
938 if(U_FAILURE(status)) {
939 LOGI("Error getting resources");
940 status = U_ZERO_ERROR;
946 jclass obj_class = env->FindClass("java/lang/Object");
947 jclass integer_class = env->FindClass("java/lang/Integer");
948 jmethodID integerInit = env->GetMethodID(integer_class, "<init>", "(I)V");
951 jobject firstDayOfWeek = NULL;
952 jobject minimalDaysInFirstWeek = NULL;
953 jobjectArray amPmMarkers = NULL;
954 jobjectArray eras = NULL;
955 jstring localPatternChars = NULL;
956 jobjectArray weekdays = NULL;
957 jobjectArray shortWeekdays = NULL;
958 jobjectArray months = NULL;
959 jobjectArray shortMonths = NULL;
960 jstring time_SHORT = NULL;
961 jstring time_MEDIUM = NULL;
962 jstring time_LONG = NULL;
963 jstring time_FULL = NULL;
964 jstring date_SHORT = NULL;
965 jstring date_MEDIUM = NULL;
966 jstring date_LONG = NULL;
967 jstring date_FULL = NULL;
968 jstring decimalPatternChars = NULL;
970 jstring infinity = NULL;
971 jstring currencySymbol = NULL;
972 jstring intCurrencySymbol = NULL;
973 jstring numberPattern = NULL;
974 jstring integerPattern = NULL;
975 jstring currencyPattern = NULL;
976 jstring percentPattern = NULL;
977 jobjectArray zones = NULL;
981 int firstDayVals[2] = {-1, -1};
983 const jchar* nan = (const jchar *)NULL;
984 const jchar* inf = (const jchar *)NULL;
988 UResourceBundle *gregorian;
989 UResourceBundle *gregorianElems;
990 UResourceBundle *rootElems;
995 // get the resources needed
996 rootElems = ures_getByKey(root, "calendar", NULL, &status);
997 if(U_FAILURE(status)) {
1001 gregorian = ures_getByKey(rootElems, "gregorian", NULL, &status);
1002 if(U_FAILURE(status)) {
1003 ures_close(rootElems);
1009 // adding the first day of week and minimal days in first week values
1010 getDayInitVector(env, gregorian, firstDayVals);
1011 if((firstDayVals[0] != -1) && (firstDayVals[1] != -1)) {
1012 firstDayOfWeek = env->NewObject(integer_class, integerInit, firstDayVals[0]);
1013 minimalDaysInFirstWeek = env->NewObject(integer_class, integerInit, firstDayVals[1]);
1014 // adding First_Day and Minimal_Days integer to the result
1019 // adding ampm string array to the result");
1020 amPmMarkers = getAmPmMarkers(env, gregorian);
1021 if(amPmMarkers != NULL) {
1026 // adding eras string array to the result
1027 eras = getEras(env, gregorian);
1033 // local pattern chars are initially always the same
1034 localPatternChars = env->NewStringUTF("GyMdkHmsSEDFwWahKzZ");
1035 // adding local pattern chars string to the result
1039 // adding month names string array to the result
1040 months = getMonthNames(env, gregorian);
1041 if(months != NULL) {
1046 // adding short month names string array to the result
1047 shortMonths = getShortMonthNames(env, gregorian);
1048 if(shortMonths != NULL) {
1053 // adding day names string array to the result
1054 weekdays = getWeekdayNames(env, gregorian);
1055 if(weekdays != NULL) {
1060 // adding short day names string array to the result
1061 shortWeekdays = getShortWeekdayNames(env, gregorian);
1062 if(shortWeekdays != NULL) {
1066 const UChar *pattern;
1067 jchar check[2] = {0, 0};
1068 u_uastrcpy(check, "v");
1069 jchar replacement[2] = {0, 0};
1070 u_uastrcpy(replacement, "z");
1075 // adding date and time format patterns to the result
1076 gregorianElems = ures_getByKey(gregorian, "DateTimePatterns", NULL, &status);
1077 if(U_FAILURE(status)) {
1078 status = U_ZERO_ERROR;
1082 pattern = ures_getStringByIndex(gregorianElems, 0, &patternLength, &status);
1083 // there are some patterns in icu that use the pattern character 'v'
1084 // java doesn't accept this, so it gets replaced by 'z' which has
1085 // about the same result as 'v', the timezone name.
1086 // 'v' -> "PT", 'z' -> "PST", v is the generic timezone and z the standard tz
1087 // "vvvv" -> "Pacific Time", "zzzz" -> "Pacific Standard Time"
1088 patternCopy = (jchar *) malloc((patternLength + 1) * sizeof(jchar));
1089 u_strcpy(patternCopy, pattern);
1090 if(U_FAILURE(status)) {
1092 status = U_ZERO_ERROR;
1095 while((pos = u_strchr(patternCopy, check[0])) != NULL) {
1096 u_memset(pos, replacement[0], 1);
1098 time_FULL = env->NewString(patternCopy, patternLength);
1102 pattern = ures_getStringByIndex(gregorianElems, 1, &patternLength, &status);
1103 if(U_FAILURE(status)) {
1104 status = U_ZERO_ERROR;
1107 time_LONG = env->NewString(pattern, patternLength);
1110 pattern = ures_getStringByIndex(gregorianElems, 2, &patternLength, &status);
1111 if(U_FAILURE(status)) {
1112 status = U_ZERO_ERROR;
1115 time_MEDIUM = env->NewString(pattern, patternLength);
1118 pattern = ures_getStringByIndex(gregorianElems, 3, &patternLength, &status);
1119 if(U_FAILURE(status)) {
1120 status = U_ZERO_ERROR;
1123 time_SHORT = env->NewString(pattern, patternLength);
1126 pattern = ures_getStringByIndex(gregorianElems, 4, &patternLength, &status);
1127 if(U_FAILURE(status)) {
1128 status = U_ZERO_ERROR;
1131 date_FULL = env->NewString(pattern, patternLength);
1134 pattern = ures_getStringByIndex(gregorianElems, 5, &patternLength, &status);
1135 if(U_FAILURE(status)) {
1136 status = U_ZERO_ERROR;
1139 date_LONG = env->NewString(pattern, patternLength);
1142 pattern = ures_getStringByIndex(gregorianElems, 6, &patternLength, &status);
1143 if(U_FAILURE(status)) {
1144 status = U_ZERO_ERROR;
1147 date_MEDIUM = env->NewString(pattern, patternLength);
1150 pattern = ures_getStringByIndex(gregorianElems, 7, &patternLength, &status);
1151 if(U_FAILURE(status)) {
1152 status = U_ZERO_ERROR;
1155 date_SHORT = env->NewString(pattern, patternLength);
1161 if(gregorianElems != NULL) {
1162 ures_close(gregorianElems);
1164 ures_close(gregorian);
1165 ures_close(rootElems);
1168 rootElems = ures_getByKey(root, "NumberElements", NULL, &status);
1169 if(U_FAILURE(status)) {
1170 status = U_ZERO_ERROR;
1173 if(ures_getSize(rootElems) >= 11) {
1175 // adding decimal pattern chars to the result
1176 decimalPatternChars = getDecimalPatternChars(env, rootElems);
1177 if(decimalPatternChars != NULL) {
1181 // adding NaN pattern char to the result
1182 nan = ures_getStringByIndex(rootElems, 10, &nanL, &status);
1183 if(U_SUCCESS(status)) {
1184 naN = env->NewString(nan, nanL);
1187 status = U_ZERO_ERROR;
1189 // adding infinity pattern char to the result
1190 inf = ures_getStringByIndex(rootElems, 9, &infL, &status);
1191 if(U_SUCCESS(status)) {
1192 infinity = env->NewString(inf, infL);
1195 status = U_ZERO_ERROR;
1198 ures_close(rootElems);
1201 // adding intl currency code to result
1202 intCurrencySymbol = getIntCurrencyCode(env, clazz, locale);
1203 if(intCurrencySymbol != NULL) {
1204 // adding currency symbol to result
1205 currencySymbol = getCurrencySymbol(env, clazz, locale, intCurrencySymbol);
1207 intCurrencySymbol = env->NewStringUTF("XXX");
1209 if(currencySymbol == NULL) {
1210 currencySymbol = env->NewStringUTF("\u00a4");
1215 // adding number format patterns to the result
1221 rootElems = ures_getByKey(root, "NumberPatterns", NULL, &status);
1222 if(U_FAILURE(status)) {
1223 status = U_ZERO_ERROR;
1227 numOfEntries = ures_getSize(rootElems);
1228 if(numOfEntries < 3) {
1229 ures_close(rootElems);
1234 pattern = ures_getStringByIndex(rootElems, 0, &patternLength, &status);
1235 if(U_FAILURE(status)) {
1236 status = U_ZERO_ERROR;
1237 ures_close(rootElems);
1240 numberPattern = env->NewString(pattern, patternLength);
1243 // integer pattern derived from number pattern
1244 // We need to convert a C string literal to a UChar string for u_strcspn.
1245 static const char c_decSep[] = ".";
1246 UChar decSep[sizeof(c_decSep)];
1247 u_charsToUChars(c_decSep, decSep, sizeof(c_decSep));
1248 decSepOffset = u_strcspn(pattern, decSep);
1249 tmpPattern = (jchar *) malloc((decSepOffset + 1) * sizeof(jchar));
1250 u_strncpy(tmpPattern, pattern, decSepOffset);
1251 integerPattern = env->NewString(tmpPattern, decSepOffset);
1256 pattern = ures_getStringByIndex(rootElems, 1, &patternLength, &status);
1257 if(U_FAILURE(status)) {
1258 status = U_ZERO_ERROR;
1259 ures_close(rootElems);
1262 currencyPattern = env->NewString(pattern, patternLength);
1266 pattern = ures_getStringByIndex(rootElems, 2, &patternLength, &status);
1267 if(U_FAILURE(status)) {
1268 status = U_ZERO_ERROR;
1269 ures_close(rootElems);
1272 percentPattern = env->NewString(pattern, patternLength);
1275 ures_close(rootElems);
1282 if(needsTZ == JNI_TRUE) {
1283 counter++; //add empty timezone
1288 // collect all content and put it into an array
1289 result = env->NewObjectArray(counter, obj_class, NULL);
1293 if(needsTZ == JNI_TRUE) {
1294 addObject(env, result, "timezones", NULL, index++);
1296 if(firstDayOfWeek != NULL && index < counter) {
1297 addObject(env, result, "First_Day", firstDayOfWeek, index++);
1299 if(minimalDaysInFirstWeek != NULL && index < counter) {
1300 addObject(env, result, "Minimal_Days", minimalDaysInFirstWeek, index++);
1302 if(amPmMarkers != NULL && index < counter) {
1303 addObject(env, result, "ampm", amPmMarkers, index++);
1305 if(eras != NULL && index < counter) {
1306 addObject(env, result, "eras", eras, index++);
1308 if(localPatternChars != NULL && index < counter) {
1309 addObject(env, result, "LocalPatternChars", localPatternChars, index++);
1311 if(weekdays != NULL && index < counter) {
1312 addObject(env, result, "weekdays", weekdays, index++);
1314 if(shortWeekdays != NULL && index < counter) {
1315 addObject(env, result, "shortWeekdays", shortWeekdays, index++);
1317 if(months != NULL && index < counter) {
1318 addObject(env, result, "months", months, index++);
1320 if(shortMonths != NULL && index < counter) {
1321 addObject(env, result, "shortMonths", shortMonths, index++);
1323 if(time_SHORT != NULL && index < counter) {
1324 addObject(env, result, "Time_SHORT", time_SHORT, index++);
1326 if(time_MEDIUM != NULL && index < counter) {
1327 addObject(env, result, "Time_MEDIUM", time_MEDIUM, index++);
1329 if(time_LONG != NULL && index < counter) {
1330 addObject(env, result, "Time_LONG", time_LONG, index++);
1332 if(time_FULL != NULL && index < counter) {
1333 addObject(env, result, "Time_FULL", time_FULL, index++);
1335 if(date_SHORT != NULL && index < counter) {
1336 addObject(env, result, "Date_SHORT", date_SHORT, index++);
1338 if(date_MEDIUM != NULL && index < counter) {
1339 addObject(env, result, "Date_MEDIUM", date_MEDIUM, index++);
1341 if(date_LONG != NULL && index < counter) {
1342 addObject(env, result, "Date_LONG", date_LONG, index++);
1344 if(date_FULL != NULL && index < counter) {
1345 addObject(env, result, "Date_FULL", date_FULL, index++);
1347 if(decimalPatternChars != NULL && index < counter) {
1348 addObject(env, result, "DecimalPatternChars", decimalPatternChars, index++);
1350 if(naN != NULL && index < counter) {
1351 addObject(env, result, "NaN", naN, index++);
1353 if(infinity != NULL && index < counter) {
1354 addObject(env, result, "Infinity", infinity, index++);
1356 if(currencySymbol != NULL && index < counter) {
1357 addObject(env, result, "CurrencySymbol", currencySymbol, index++);
1359 if(intCurrencySymbol != NULL && index < counter) {
1360 addObject(env, result, "IntCurrencySymbol", intCurrencySymbol, index++);
1362 if(numberPattern != NULL && index < counter) {
1363 addObject(env, result, "Number", numberPattern, index++);
1365 if(integerPattern != NULL && index < counter) {
1366 addObject(env, result, "Integer", integerPattern, index++);
1368 if(currencyPattern != NULL && index < counter) {
1369 addObject(env, result, "Currency", currencyPattern, index++);
1371 if(percentPattern != NULL && index < counter) {
1372 addObject(env, result, "Percent", percentPattern, index++);
1379 static JNINativeMethod gMethods[] = {
1380 /* name, signature, funcPtr */
1381 {"getFractionDigitsNative", "(Ljava/lang/String;)I",
1382 (void*) getFractionDigitsNative},
1383 {"getCurrencyCodeNative", "(Ljava/lang/String;)Ljava/lang/String;",
1384 (void*) getCurrencyCodeNative},
1385 {"getCurrencySymbolNative", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
1386 (void*) getCurrencySymbolNative},
1387 {"getDisplayCountryNative",
1388 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
1389 (void*) getDisplayCountryNative},
1390 {"getDisplayLanguageNative",
1391 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
1392 (void*) getDisplayLanguageNative},
1393 {"getDisplayVariantNative",
1394 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
1395 (void*) getDisplayVariantNative},
1396 {"getISO3CountryNative",
1397 "(Ljava/lang/String;)Ljava/lang/String;",
1398 (void*) getISO3CountryNative},
1399 {"getISO3LanguageNative",
1400 "(Ljava/lang/String;)Ljava/lang/String;",
1401 (void*) getISO3LanguageNative},
1402 {"getISOCountriesNative", "()[Ljava/lang/String;",
1403 (void*) getISOCountriesNative},
1404 {"getISOLanguagesNative", "()[Ljava/lang/String;",
1405 (void*) getISOLanguagesNative},
1406 {"getAvailableLocalesNative", "()[Ljava/lang/String;",
1407 (void*) getAvailableLocalesNative},
1408 {"getTimeZonesNative",
1409 "([[Ljava/lang/String;Ljava/lang/String;)V",
1410 (void*) getTimeZonesNative},
1411 {"getDisplayTimeZoneNative",
1412 "(Ljava/lang/String;ZILjava/lang/String;)Ljava/lang/String;",
1413 (void*) getDisplayTimeZoneNative},
1415 "(Ljava/lang/String;Z)[[Ljava/lang/Object;",
1416 (void*) getContentImpl},
1419 int register_com_ibm_icu4jni_util_Resources(JNIEnv* env) {
1421 // initializing String
1423 jclass stringclass = env->FindClass("java/lang/String");
1425 if(stringclass == NULL) {
1426 LOGE("Can't find java/lang/String");
1427 jniThrowException(env, "java/lang/ClassNotFoundException", "java.lang.String");
1431 string_class = (jclass) env->NewGlobalRef(stringclass);
1433 return jniRegisterNativeMethods(env,
1434 "com/ibm/icu4jni/util/Resources", gMethods,