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#include "JNIHelp.h"
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>
36#include <stdlib.h>
37#include <string.h>
38#include <time.h>
39#include <sys/time.h>
40
41jclass string_class;
42
43static UBool icuError(JNIEnv *env, UErrorCode errorcode)
44{
45  const char   *emsg      = u_errorName(errorcode);
46        jclass  exception;
47
48  if (U_FAILURE(errorcode)) {
49    switch (errorcode) {
50      case U_ILLEGAL_ARGUMENT_ERROR :
51        exception = env->FindClass("java/lang/IllegalArgumentException");
52        break;
53      case U_INDEX_OUTOFBOUNDS_ERROR :
54      case U_BUFFER_OVERFLOW_ERROR :
55        exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
56        break;
57      case U_UNSUPPORTED_ERROR :
58        exception = env->FindClass("java/lang/UnsupportedOperationException");
59        break;
60      default :
61        exception = env->FindClass("java/lang/RuntimeException");
62    }
63
64    return (env->ThrowNew(exception, emsg) != 0);
65  }
66  return 0;
67}
68
69static 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);
73    return result;
74}
75
76static jstring getJStringFromUnicodeString(JNIEnv *env, UnicodeString string) {
77
78    UErrorCode status = U_ZERO_ERROR;
79
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)) {
84        free(res);
85        LOGI("Error getting string for getJStringFromUnicodeString");
86        status = U_ZERO_ERROR;
87        return NULL;
88    }
89    jstring result = env->NewString(res, stringLength);
90    free(res);
91    return result;
92}
93
94static 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);
103}
104
105static jint getFractionDigitsNative(JNIEnv* env, jclass clazz,
106        jstring currencyCode) {
107    // LOGI("ENTER getFractionDigitsNative");
108
109    UErrorCode status = U_ZERO_ERROR;
110
111    NumberFormat *fmt = NumberFormat::createCurrencyInstance(status);
112    if(U_FAILURE(status)) {
113        return -1;
114    }
115
116    const jchar *cCode = env->GetStringChars(currencyCode, NULL);
117    fmt->setCurrency(cCode, status);
118    env->ReleaseStringChars(currencyCode, cCode);
119    if(U_FAILURE(status)) {
120        return -1;
121    }
122
123    // for CurrencyFormats the minimum and maximum fraction digits are the same.
124    int result = fmt->getMinimumFractionDigits();
125    delete(fmt);
126    return result;
127}
128
129static jstring getCurrencyCodeNative(JNIEnv* env, jclass clazz,
130        jstring key) {
131    // LOGI("ENTER getCurrencyCodeNative");
132
133    UErrorCode status = U_ZERO_ERROR;
134
135    UResourceBundle *supplData = ures_openDirect(NULL, "supplementalData", &status);
136    if(U_FAILURE(status)) {
137        return NULL;
138    }
139
140    UResourceBundle *currencyMap = ures_getByKey(supplData, "CurrencyMap", NULL, &status);
141    if(U_FAILURE(status)) {
142        ures_close(supplData);
143        return NULL;
144    }
145
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);
152        return NULL;
153    }
154
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");
161    }
162
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);
171        return NULL;
172    }
173    status = U_ZERO_ERROR;
174    ures_close(currencyTo);
175
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");
184    }
185
186    int length;
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");
195    }
196
197    ures_close(currencyId);
198    ures_close(currencyElem);
199    ures_close(currency);
200    ures_close(currencyMap);
201    ures_close(supplData);
202
203    if(length == 0) {
204        return env->NewStringUTF("None");
205    }
206    return env->NewString(id, length);
207}
208
209static jstring getCurrencySymbolNative(JNIEnv* env, jclass clazz,
210        jstring locale, jstring currencyCode) {
211    // LOGI("ENTER getCurrencySymbolNative");
212
213    UErrorCode status = U_ZERO_ERROR;
214
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)) {
219        return NULL;
220    }
221
222    UResourceBundle *rootElems = ures_getByKey(root, "Currencies", NULL, &status);
223    if(U_FAILURE(status)) {
224        ures_close(root);
225        return NULL;
226    }
227
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);
233        ures_close(root);
234        return NULL;
235    }
236
237    int currSymbL;
238    const jchar *currSymbU = ures_getStringByIndex(currencyElems, 0, &currSymbL, &status);
239    if(U_FAILURE(status)) {
240        ures_close(currencyElems);
241        ures_close(rootElems);
242        ures_close(root);
243        return NULL;
244    }
245
246    ures_close(currencyElems);
247    ures_close(rootElems);
248    ures_close(root);
249
250    if(currSymbL == 0) {
251        return NULL;
252    }
253    return env->NewString(currSymbU, currSymbL);
254}
255
256static jstring getDisplayCountryNative(JNIEnv* env, jclass clazz,
257        jstring targetLocale, jstring locale) {
258    // LOGI("ENTER getDisplayCountryNative");
259
260    UErrorCode status = U_ZERO_ERROR;
261
262    Locale loc = getLocale(env, locale);
263    Locale targetLoc = getLocale(env, targetLocale);
264
265    UnicodeString string;
266    targetLoc.getDisplayCountry(loc, string);
267
268    jstring result = getJStringFromUnicodeString(env, string);
269
270    return result;
271}
272
273static jstring getDisplayLanguageNative(JNIEnv* env, jclass clazz,
274        jstring targetLocale, jstring locale) {
275    // LOGI("ENTER getDisplayLanguageNative");
276
277    Locale loc = getLocale(env, locale);
278    Locale targetLoc = getLocale(env, targetLocale);
279
280    UnicodeString string;
281    targetLoc.getDisplayLanguage(loc, string);
282
283    jstring result = getJStringFromUnicodeString(env, string);
284
285    return result;
286}
287
288static jstring getDisplayVariantNative(JNIEnv* env, jclass clazz,
289        jstring targetLocale, jstring locale) {
290    // LOGI("ENTER getDisplayVariantNative");
291
292    Locale loc = getLocale(env, locale);
293    Locale targetLoc = getLocale(env, targetLocale);
294
295    UnicodeString string;
296    targetLoc.getDisplayVariant(loc, string);
297
298    jstring result = getJStringFromUnicodeString(env, string);
299
300    return result;
301}
302
303static jstring getISO3CountryNative(JNIEnv* env, jclass clazz, jstring locale) {
304    // LOGI("ENTER getISO3CountryNative");
305
306    Locale loc = getLocale(env, locale);
307
308    const char *string = loc.getISO3Country();
309
310    jstring result = env->NewStringUTF(string);
311
312    return result;
313}
314
315static jstring getISO3LanguageNative(JNIEnv* env, jclass clazz, jstring locale) {
316    // LOGI("ENTER getISO3LanguageNative");
317
318    Locale loc = getLocale(env, locale);
319
320    const char *string = loc.getISO3Language();
321
322    jstring result = env->NewStringUTF(string);
323
324    return result;
325}
326
327static jobjectArray getISOCountriesNative(JNIEnv* env, jclass clazz) {
328    // LOGI("ENTER getISOCountriesNative");
329
330    const char* const* strings = Locale::getISOCountries();
331
332    int count = 0;
333    while(strings[count] != NULL) {
334        count++;
335    }
336
337    jobjectArray result = env->NewObjectArray(count, string_class, NULL);
338
339    jstring res;
340    for(int i = 0; i < count; i++) {
341        res = env->NewStringUTF(strings[i]);
342        env->SetObjectArrayElement(result, i, res);
343        env->DeleteLocalRef(res);
344    }
345    return result;
346}
347
348static jobjectArray getISOLanguagesNative(JNIEnv* env, jclass clazz) {
349    // LOGI("ENTER getISOLanguagesNative");
350
351    const char* const* strings = Locale::getISOLanguages();
352
353    const char *string = strings[0];
354
355    int count = 0;
356    while(strings[count] != NULL) {
357        count++;
358    }
359
360    jobjectArray result = env->NewObjectArray(count, string_class, NULL);
361
362    jstring res;
363    for(int i = 0; i < count; i++) {
364        res = env->NewStringUTF(strings[i]);
365        env->SetObjectArrayElement(result, i, res);
366        env->DeleteLocalRef(res);
367    }
368    return result;
369}
370
371static jobjectArray getAvailableLocalesNative(JNIEnv* env, jclass clazz) {
372    // LOGI("ENTER getAvailableLocalesNative");
373
374    int count = uloc_countAvailable();
375
376    jobjectArray result = env->NewObjectArray(count, string_class, NULL);
377
378    jstring res;
379    const char * string;
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);
385    }
386
387    return result;
388}
389
390static void getTimeZonesNative(JNIEnv* env, jclass clazz,
391        jobjectArray outerArray, jstring locale) {
392    // LOGI("ENTER getTimeZonesNative");
393
394    UErrorCode status = U_ZERO_ERROR;
395
396    jobjectArray zoneIdArray;
397    jobjectArray longStdTimeArray;
398    jobjectArray shortStdTimeArray;
399    jobjectArray longDlTimeArray;
400    jobjectArray shortDlTimeArray;
401
402    jstring content;
403    jstring strObj;
404    const jchar *res;
405    UnicodeString resU;
406    jint length;
407    const UnicodeString *zoneID;
408    DateFormat *df;
409
410    UnicodeString longPattern("zzzz","");
411    UnicodeString shortPattern("z","");
412
413    Locale loc = getLocale(env, locale);
414
415    SimpleDateFormat longFormat(longPattern, loc, status);
416    SimpleDateFormat shortFormat(shortPattern, loc, status);
417
418
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);
424
425    int count = env->GetArrayLength(zoneIdArray);
426
427    TimeZone* zones[count];
428
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);
438    }
439
440    // 15th January 2008
441    UDate date1 = 1203105600000.0;
442    // 15th July 2008
443    UDate date2 = 1218826800000.0;
444
445    for (int i = 0; i < count; i++) {
446           TimeZone *tz = zones[i];
447           longFormat.setTimeZone(*tz);
448           shortFormat.setTimeZone(*tz);
449
450           int32_t daylightOffset;
451           int32_t rawOffset;
452           UDate standardDate;
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,
458               // swap them.
459               standardDate = date2;
460               daylightSavingDate = date1;
461           } else {
462               standardDate = date1;
463               daylightSavingDate = date2;
464           }
465
466           UnicodeString shortDayLight;
467           UnicodeString longDayLight;
468           UnicodeString shortStandard;
469           UnicodeString longStandard;
470
471           shortFormat.format(daylightSavingDate, shortDayLight);
472           content = getJStringFromUnicodeString(env, shortDayLight);
473           env->SetObjectArrayElement(shortDlTimeArray, i, content);
474           env->DeleteLocalRef(content);
475
476           shortFormat.format(standardDate, shortStandard);
477           content = getJStringFromUnicodeString(env, shortStandard);
478           env->SetObjectArrayElement(shortStdTimeArray, i, content);
479           env->DeleteLocalRef(content);
480
481           longFormat.format (daylightSavingDate, longDayLight);
482           content = getJStringFromUnicodeString(env, longDayLight);
483           env->SetObjectArrayElement(longDlTimeArray, i, content);
484           env->DeleteLocalRef(content);
485
486           longFormat.format (standardDate, longStandard);
487           content = getJStringFromUnicodeString(env, longStandard);
488           env->SetObjectArrayElement(longStdTimeArray, i, content);
489           env->DeleteLocalRef(content);
490           delete(tz);
491    }
492}
493
494
495
496
497static jstring getDisplayTimeZoneNative(JNIEnv* env, jclass clazz,
498        jstring zoneID, jboolean isDST, jint style, jstring localeID) {
499
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);
506
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);
511
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);
519
520    // Clean up everything
521    delete(zone);
522
523    return result;
524}
525
526static void getDayInitVector(JNIEnv *env, UResourceBundle *gregorian, int *values) {
527
528    UErrorCode status = U_ZERO_ERROR;
529
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)) {
533        return;
534    }
535
536    int intVectSize;
537    const int *result;
538    result = ures_getIntVector(gregorianElems, &intVectSize, &status);
539    if(U_FAILURE(status)) {
540        ures_close(gregorianElems);
541        return;
542    }
543
544    if(intVectSize == 2) {
545        values[0] = result[0];
546        values[1] = result[1];
547    }
548
549    ures_close(gregorianElems);
550
551}
552
553static jobjectArray getAmPmMarkers(JNIEnv *env, UResourceBundle *gregorian) {
554
555    jobjectArray amPmMarkers;
556    jstring pmU, amU;
557
558    UErrorCode status = U_ZERO_ERROR;
559
560    UResourceBundle *gregorianElems;
561
562    gregorianElems = ures_getByKey(gregorian, "AmPmMarkers", NULL, &status);
563    if(U_FAILURE(status)) {
564        return NULL;
565    }
566
567    int lengthAm, lengthPm;
568
569    ures_resetIterator(gregorianElems);
570
571    const jchar* am = ures_getStringByIndex(gregorianElems, 0, &lengthAm, &status);
572    const jchar* pm = ures_getStringByIndex(gregorianElems, 1, &lengthPm, &status);
573
574    if(U_FAILURE(status)) {
575        ures_close(gregorianElems);
576        return NULL;
577    }
578
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);
587
588    return amPmMarkers;
589}
590
591static jobjectArray getEras(JNIEnv* env, UResourceBundle *gregorian) {
592
593    jobjectArray eras;
594    jstring eraU;
595    const jchar* era;
596
597    UErrorCode status = U_ZERO_ERROR;
598
599    UResourceBundle *gregorianElems;
600    UResourceBundle *eraElems;
601
602    gregorianElems = ures_getByKey(gregorian, "eras", NULL, &status);
603    if(U_FAILURE(status)) {
604        return NULL;
605    }
606
607    eraElems = ures_getByKey(gregorianElems, "abbreviated", NULL, &status);
608    if(U_FAILURE(status)) {
609        ures_close(gregorianElems);
610        return NULL;
611    }
612
613    int eraLength;
614
615    int eraCount = ures_getSize(eraElems);
616    eras = env->NewObjectArray(eraCount, string_class, NULL);
617
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);
624            return NULL;
625        }
626        eraU = env->NewString(era, eraLength);
627        env->SetObjectArrayElement(eras, i, eraU);
628        env->DeleteLocalRef(eraU);
629    }
630    ures_close(eraElems);
631    ures_close(gregorianElems);
632
633    return eras;
634}
635
636static jobjectArray getMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
637
638    UErrorCode status = U_ZERO_ERROR;
639
640    const jchar* month;
641    jstring monthU;
642
643    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
644    if(U_FAILURE(status)) {
645        return NULL;
646    }
647
648    UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
649    if(U_FAILURE(status)) {
650        ures_close(gregorianElems);
651        return NULL;
652    }
653
654    UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "wide", NULL, &status);
655    if(U_FAILURE(status)) {
656        ures_close(monthNameElems);
657        ures_close(gregorianElems);
658        return NULL;
659    }
660
661    int monthNameLength;
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);
671            return NULL;
672        }
673        monthU = env->NewString(month, monthNameLength);
674        env->SetObjectArrayElement(months, i, monthU);
675        env->DeleteLocalRef(monthU);
676    }
677
678    monthU = env->NewStringUTF("");
679    env->SetObjectArrayElement(months, monthCount, monthU);
680    env->DeleteLocalRef(monthU);
681
682    ures_close(monthNameElemsFormat);
683    ures_close(monthNameElems);
684    ures_close(gregorianElems);
685    return months;
686}
687
688static jobjectArray getShortMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
689
690    UErrorCode status = U_ZERO_ERROR;
691
692    const jchar* shortMonth;
693    jstring shortMonthU;
694
695    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
696    if(U_FAILURE(status)) {
697        return NULL;
698    }
699
700    UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
701    if(U_FAILURE(status)) {
702        ures_close(gregorianElems);
703        return NULL;
704    }
705
706    UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "abbreviated", NULL, &status);
707    if(U_FAILURE(status)) {
708        ures_close(monthNameElems);
709        ures_close(gregorianElems);
710        return NULL;
711    }
712
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);
724            return NULL;
725        }
726        shortMonthU = env->NewString(shortMonth, shortMonthNameLength);
727        env->SetObjectArrayElement(shortMonths, i, shortMonthU);
728        env->DeleteLocalRef(shortMonthU);
729    }
730
731    shortMonthU = env->NewStringUTF("");
732    env->SetObjectArrayElement(shortMonths, shortMonthCount, shortMonthU);
733    env->DeleteLocalRef(shortMonthU);
734
735    ures_close(monthNameElemsFormat);
736    ures_close(monthNameElems);
737    ures_close(gregorianElems);
738    return shortMonths;
739}
740
741static jobjectArray getWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
742
743    UErrorCode status = U_ZERO_ERROR;
744
745    const jchar* day;
746    jstring dayU;
747
748    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
749    if(U_FAILURE(status)) {
750        return NULL;
751    }
752
753    UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
754    if(U_FAILURE(status)) {
755        ures_close(gregorianElems);
756        return NULL;
757    }
758
759    UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "wide", NULL, &status);
760    if(U_FAILURE(status)) {
761        ures_close(dayNameElems);
762        ures_close(gregorianElems);
763        return NULL;
764    }
765
766    int dayNameLength;
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);
778            return NULL;
779        }
780        dayU = env->NewString(day, dayNameLength);
781        env->SetObjectArrayElement(weekdays, i + 1, dayU);
782        env->DeleteLocalRef(dayU);
783    }
784
785    ures_close(dayNameElemsFormat);
786    ures_close(dayNameElems);
787    ures_close(gregorianElems);
788    return weekdays;
789
790}
791
792static jobjectArray getShortWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
793
794    UErrorCode status = U_ZERO_ERROR;
795
796    const jchar* shortDay;
797    jstring shortDayU;
798
799    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
800    if(U_FAILURE(status)) {
801        return NULL;
802    }
803
804    UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
805    if(U_FAILURE(status)) {
806        ures_close(gregorianElems);
807        return NULL;
808    }
809
810    UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "abbreviated", NULL, &status);
811    if(U_FAILURE(status)) {
812        ures_close(dayNameElems);
813        ures_close(gregorianElems);
814        return NULL;
815    }
816
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);
828            return NULL;
829        }
830        shortDayU = env->NewString(shortDay, shortDayNameLength);
831        env->SetObjectArrayElement(shortWeekdays, i + 1, shortDayU);
832        env->DeleteLocalRef(shortDayU);
833    }
834
835    ures_close(dayNameElemsFormat);
836    ures_close(dayNameElems);
837    ures_close(gregorianElems);
838    return shortWeekdays;
839}
840
841static jstring getDecimalPatternChars(JNIEnv *env, UResourceBundle *rootElems) {
842
843    UErrorCode status = U_ZERO_ERROR;
844
845    int zeroL, digitL, decSepL, groupL, listL, percentL, permillL, expL, currSepL, minusL;
846    int patternLength;
847
848    jchar *patternChars;
849
850    const jchar* zero = ures_getStringByIndex(rootElems, 4, &zeroL, &status);
851
852    const jchar* digit = ures_getStringByIndex(rootElems, 5, &digitL, &status);
853
854    const jchar* decSep = ures_getStringByIndex(rootElems, 0, &decSepL, &status);
855
856    const jchar* group = ures_getStringByIndex(rootElems, 1, &groupL, &status);
857
858    const jchar* list = ures_getStringByIndex(rootElems, 2, &listL, &status);
859
860    const jchar* percent = ures_getStringByIndex(rootElems, 3, &percentL, &status);
861
862    const jchar* permill = ures_getStringByIndex(rootElems, 8, &permillL, &status);
863
864    const jchar* exp = ures_getStringByIndex(rootElems, 7, &expL, &status);
865
866    const jchar* currSep = ures_getStringByIndex(rootElems, 0, &currSepL, &status);
867
868    const jchar* minus = ures_getStringByIndex(rootElems, 6, &minusL, &status);
869
870    if(U_FAILURE(status)) {
871        return NULL;
872    }
873
874
875    patternChars = (jchar *) malloc(11 * sizeof(jchar));
876
877    patternChars[0] = 0;
878
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);
889
890    jstring decimalPatternChars = env->NewString(patternChars, 10);
891
892    free(patternChars);
893
894    return decimalPatternChars;
895}
896
897static jstring getIntCurrencyCode(JNIEnv *env, jclass clazz, jstring locale) {
898
899    const char *locStr = env->GetStringUTFChars(locale, NULL);
900    char country[3] = {0,0,0};
901
902    // getting the 2 character country name
903    if(strlen(locStr) < 5) {
904        env->ReleaseStringUTFChars(locale, locStr);
905        return NULL;
906    }
907    if(locStr[3] < 'A' || locStr[3] > 'Z' || locStr[4] < 'A' || locStr[4] > 'Z') {
908        env->ReleaseStringUTFChars(locale, locStr);
909        return NULL;
910    }
911    country[0] = locStr[3];
912    country[1] = locStr[4];
913
914    env->ReleaseStringUTFChars(locale, locStr);
915
916    return getCurrencyCodeNative(env, clazz, env->NewStringUTF(country));
917}
918
919static jstring getCurrencySymbol(JNIEnv *env, jclass clazz, jstring locale, jstring intCurrencySymbol) {
920
921    jstring result = getCurrencySymbolNative(env, clazz, locale, intCurrencySymbol);
922    if(result == intCurrencySymbol) {
923        return NULL;
924    }
925    return result;
926
927}
928
929static jobjectArray getContentImpl(JNIEnv* env, jclass clazz,
930        jstring locale, jboolean needsTZ) {
931
932    UErrorCode status = U_ZERO_ERROR;
933
934    const char *loc = env->GetStringUTFChars(locale, NULL);
935    UResourceBundle *root = ures_openU(NULL, loc, &status);
936
937    env->ReleaseStringUTFChars(locale, loc);
938    if(U_FAILURE(status)) {
939        LOGI("Error getting resources");
940        status = U_ZERO_ERROR;
941        return NULL;
942    }
943
944
945
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");
949    jobjectArray result;
950
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;
969    jstring naN = 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;
978
979    int counter = 0;
980
981    int firstDayVals[2] = {-1, -1};
982
983    const jchar* nan = (const jchar *)NULL;
984    const jchar* inf = (const jchar *)NULL;
985    int nanL, infL;
986
987
988    UResourceBundle *gregorian;
989    UResourceBundle *gregorianElems;
990    UResourceBundle *rootElems;
991
992
993
994
995    // get the resources needed
996    rootElems = ures_getByKey(root, "calendar", NULL, &status);
997    if(U_FAILURE(status)) {
998        return NULL;
999    }
1000
1001    gregorian = ures_getByKey(rootElems, "gregorian", NULL, &status);
1002    if(U_FAILURE(status)) {
1003        ures_close(rootElems);
1004        return NULL;
1005    }
1006
1007
1008
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
1015        counter += 2;
1016    }
1017
1018
1019    // adding ampm string array to the result");
1020    amPmMarkers = getAmPmMarkers(env, gregorian);
1021    if(amPmMarkers != NULL) {
1022        counter++;
1023    }
1024
1025
1026    // adding eras string array to the result
1027    eras = getEras(env, gregorian);
1028    if(eras != NULL) {
1029        counter++;
1030    }
1031
1032
1033    // local pattern chars are initially always the same
1034    localPatternChars = env->NewStringUTF("GyMdkHmsSEDFwWahKzZ");
1035    // adding local pattern chars string to the result
1036    counter++;
1037
1038
1039    // adding month names string array to the result
1040    months = getMonthNames(env, gregorian);
1041    if(months != NULL) {
1042        counter++;
1043    }
1044
1045
1046    // adding short month names string array to the result
1047    shortMonths = getShortMonthNames(env, gregorian);
1048    if(shortMonths != NULL) {
1049        counter++;
1050    }
1051
1052
1053    // adding day names string array to the result
1054    weekdays = getWeekdayNames(env, gregorian);
1055    if(weekdays != NULL) {
1056        counter++;
1057    }
1058
1059
1060    // adding short day names string array to the result
1061    shortWeekdays = getShortWeekdayNames(env, gregorian);
1062    if(shortWeekdays != NULL) {
1063        counter++;
1064    }
1065
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");
1071    jchar *pos;
1072    jchar *patternCopy;
1073    int patternLength;
1074
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;
1079        goto endOfCalendar;
1080    }
1081
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)) {
1091        free(patternCopy);
1092        status = U_ZERO_ERROR;
1093        goto endOfCalendar;
1094    }
1095    while((pos = u_strchr(patternCopy, check[0])) != NULL) {
1096        u_memset(pos, replacement[0], 1);
1097    }
1098    time_FULL = env->NewString(patternCopy, patternLength);
1099    free(patternCopy);
1100    counter++;
1101
1102    pattern = ures_getStringByIndex(gregorianElems, 1, &patternLength, &status);
1103    if(U_FAILURE(status)) {
1104        status = U_ZERO_ERROR;
1105        goto endOfCalendar;
1106    }
1107    time_LONG = env->NewString(pattern, patternLength);
1108    counter++;
1109
1110    pattern = ures_getStringByIndex(gregorianElems, 2, &patternLength, &status);
1111    if(U_FAILURE(status)) {
1112        status = U_ZERO_ERROR;
1113        goto endOfCalendar;
1114    }
1115    time_MEDIUM = env->NewString(pattern, patternLength);
1116    counter++;
1117
1118    pattern = ures_getStringByIndex(gregorianElems, 3, &patternLength, &status);
1119    if(U_FAILURE(status)) {
1120        status = U_ZERO_ERROR;
1121        goto endOfCalendar;
1122    }
1123    time_SHORT = env->NewString(pattern, patternLength);
1124    counter++;
1125
1126    pattern = ures_getStringByIndex(gregorianElems, 4, &patternLength, &status);
1127    if(U_FAILURE(status)) {
1128        status = U_ZERO_ERROR;
1129        goto endOfCalendar;
1130    }
1131    date_FULL = env->NewString(pattern, patternLength);
1132    counter++;
1133
1134    pattern = ures_getStringByIndex(gregorianElems, 5, &patternLength, &status);
1135    if(U_FAILURE(status)) {
1136        status = U_ZERO_ERROR;
1137        goto endOfCalendar;
1138    }
1139    date_LONG = env->NewString(pattern, patternLength);
1140    counter++;
1141
1142    pattern = ures_getStringByIndex(gregorianElems, 6, &patternLength, &status);
1143    if(U_FAILURE(status)) {
1144        status = U_ZERO_ERROR;
1145        goto endOfCalendar;
1146    }
1147    date_MEDIUM = env->NewString(pattern, patternLength);
1148    counter++;
1149
1150    pattern = ures_getStringByIndex(gregorianElems, 7, &patternLength, &status);
1151    if(U_FAILURE(status)) {
1152        status = U_ZERO_ERROR;
1153        goto endOfCalendar;
1154    }
1155    date_SHORT = env->NewString(pattern, patternLength);
1156    counter++;
1157
1158
1159endOfCalendar:
1160
1161    if(gregorianElems != NULL) {
1162        ures_close(gregorianElems);
1163    }
1164    ures_close(gregorian);
1165    ures_close(rootElems);
1166
1167
1168    rootElems = ures_getByKey(root, "NumberElements", NULL, &status);
1169    if(U_FAILURE(status)) {
1170        status = U_ZERO_ERROR;
1171    }
1172
1173    if(ures_getSize(rootElems) >= 11) {
1174
1175        // adding decimal pattern chars to the result
1176        decimalPatternChars = getDecimalPatternChars(env, rootElems);
1177        if(decimalPatternChars != NULL) {
1178            counter++;
1179        }
1180
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);
1185            counter++;
1186        }
1187        status = U_ZERO_ERROR;
1188
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);
1193            counter++;
1194        }
1195        status = U_ZERO_ERROR;
1196    }
1197
1198    ures_close(rootElems);
1199
1200
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);
1206    } else {
1207        intCurrencySymbol = env->NewStringUTF("XXX");
1208    }
1209    if(currencySymbol == NULL) {
1210        currencySymbol = env->NewStringUTF("\u00a4");
1211    }
1212    counter += 2;
1213
1214
1215    // adding number format patterns to the result
1216    int numOfEntries;
1217    int decSepOffset;
1218    NumberFormat *nf;
1219    jchar *tmpPattern;
1220
1221    rootElems = ures_getByKey(root, "NumberPatterns", NULL, &status);
1222    if(U_FAILURE(status)) {
1223        status = U_ZERO_ERROR;
1224        goto zones;
1225    }
1226
1227    numOfEntries = ures_getSize(rootElems);
1228    if(numOfEntries < 3) {
1229        ures_close(rootElems);
1230        goto zones;
1231    }
1232
1233    // number pattern
1234    pattern = ures_getStringByIndex(rootElems, 0, &patternLength, &status);
1235    if(U_FAILURE(status)) {
1236        status = U_ZERO_ERROR;
1237        ures_close(rootElems);
1238        goto zones;
1239    }
1240    numberPattern = env->NewString(pattern, patternLength);
1241    counter++;
1242
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);
1252    free(tmpPattern);
1253    counter++;
1254
1255    // currency pattern
1256    pattern = ures_getStringByIndex(rootElems, 1, &patternLength, &status);
1257    if(U_FAILURE(status)) {
1258        status = U_ZERO_ERROR;
1259        ures_close(rootElems);
1260        goto zones;
1261    }
1262    currencyPattern = env->NewString(pattern, patternLength);
1263    counter++;
1264
1265    // percent pattern
1266    pattern = ures_getStringByIndex(rootElems, 2, &patternLength, &status);
1267    if(U_FAILURE(status)) {
1268        status = U_ZERO_ERROR;
1269        ures_close(rootElems);
1270        goto zones;
1271    }
1272    percentPattern = env->NewString(pattern, patternLength);
1273    counter++;
1274
1275    ures_close(rootElems);
1276
1277zones:
1278
1279    ures_close(root);
1280
1281
1282    if(needsTZ == JNI_TRUE) {
1283        counter++; //add empty timezone
1284    }
1285
1286
1287
1288    // collect all content and put it into an array
1289    result = env->NewObjectArray(counter, obj_class, NULL);
1290
1291    int index = 0;
1292
1293    if(needsTZ == JNI_TRUE) {
1294        addObject(env, result, "timezones", NULL, index++);
1295    }
1296    if(firstDayOfWeek != NULL && index < counter) {
1297        addObject(env, result, "First_Day", firstDayOfWeek, index++);
1298    }
1299    if(minimalDaysInFirstWeek != NULL && index < counter) {
1300        addObject(env, result, "Minimal_Days", minimalDaysInFirstWeek, index++);
1301    }
1302    if(amPmMarkers != NULL && index < counter) {
1303        addObject(env, result, "ampm", amPmMarkers, index++);
1304    }
1305    if(eras != NULL && index < counter) {
1306        addObject(env, result, "eras", eras, index++);
1307    }
1308    if(localPatternChars != NULL && index < counter) {
1309        addObject(env, result, "LocalPatternChars", localPatternChars, index++);
1310    }
1311    if(weekdays != NULL && index < counter) {
1312        addObject(env, result, "weekdays", weekdays, index++);
1313    }
1314    if(shortWeekdays != NULL && index < counter) {
1315        addObject(env, result, "shortWeekdays", shortWeekdays, index++);
1316    }
1317    if(months != NULL && index < counter) {
1318        addObject(env, result, "months", months, index++);
1319    }
1320    if(shortMonths != NULL && index < counter) {
1321        addObject(env, result, "shortMonths", shortMonths, index++);
1322    }
1323    if(time_SHORT != NULL && index < counter) {
1324        addObject(env, result, "Time_SHORT", time_SHORT, index++);
1325    }
1326    if(time_MEDIUM != NULL && index < counter) {
1327        addObject(env, result, "Time_MEDIUM", time_MEDIUM, index++);
1328    }
1329    if(time_LONG != NULL && index < counter) {
1330        addObject(env, result, "Time_LONG", time_LONG, index++);
1331    }
1332    if(time_FULL != NULL && index < counter) {
1333        addObject(env, result, "Time_FULL", time_FULL, index++);
1334    }
1335    if(date_SHORT != NULL && index < counter) {
1336        addObject(env, result, "Date_SHORT", date_SHORT, index++);
1337    }
1338    if(date_MEDIUM != NULL && index < counter) {
1339        addObject(env, result, "Date_MEDIUM", date_MEDIUM, index++);
1340    }
1341    if(date_LONG != NULL && index < counter) {
1342        addObject(env, result, "Date_LONG", date_LONG, index++);
1343    }
1344    if(date_FULL != NULL && index < counter) {
1345        addObject(env, result, "Date_FULL", date_FULL, index++);
1346    }
1347    if(decimalPatternChars != NULL && index < counter) {
1348        addObject(env, result, "DecimalPatternChars", decimalPatternChars, index++);
1349    }
1350    if(naN != NULL && index < counter) {
1351        addObject(env, result, "NaN", naN, index++);
1352    }
1353    if(infinity != NULL && index < counter) {
1354        addObject(env, result, "Infinity", infinity, index++);
1355    }
1356    if(currencySymbol != NULL && index < counter) {
1357        addObject(env, result, "CurrencySymbol", currencySymbol, index++);
1358    }
1359    if(intCurrencySymbol != NULL && index < counter) {
1360        addObject(env, result, "IntCurrencySymbol", intCurrencySymbol, index++);
1361    }
1362    if(numberPattern != NULL && index < counter) {
1363        addObject(env, result, "Number", numberPattern, index++);
1364    }
1365    if(integerPattern != NULL && index < counter) {
1366        addObject(env, result, "Integer", integerPattern, index++);
1367    }
1368    if(currencyPattern != NULL && index < counter) {
1369        addObject(env, result, "Currency", currencyPattern, index++);
1370    }
1371    if(percentPattern != NULL && index < counter) {
1372        addObject(env, result, "Percent", percentPattern, index++);
1373    }
1374
1375    return result;
1376
1377}
1378
1379static 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},
1414    {"getContentImpl",
1415            "(Ljava/lang/String;Z)[[Ljava/lang/Object;",
1416            (void*) getContentImpl},
1417};
1418
1419int register_com_ibm_icu4jni_util_Resources(JNIEnv* env) {
1420
1421    // initializing String
1422
1423    jclass stringclass = env->FindClass("java/lang/String");
1424
1425    if(stringclass == NULL) {
1426        LOGE("Can't find java/lang/String");
1427        jniThrowException(env, "java/lang/ClassNotFoundException", "java.lang.String");
1428        return -1;
1429    }
1430
1431    string_class = (jclass) env->NewGlobalRef(stringclass);
1432
1433    return jniRegisterNativeMethods(env,
1434            "com/ibm/icu4jni/util/Resources", gMethods,
1435            NELEM(gMethods));
1436}
1437