1/*
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include "sun_util_locale_provider_HostLocaleProviderAdapterImpl.h"
27#include "jni_util.h"
28#include <CoreFoundation/CoreFoundation.h>
29#include <stdio.h>
30
31#define BUFLEN 256
32
33static CFDateFormatterStyle convertDateFormatterStyle(jint javaStyle);
34static CFNumberFormatterStyle convertNumberFormatterStyle(jint javaStyle);
35static void copyArrayElements(JNIEnv *env, CFArrayRef cfarray, jobjectArray jarray, CFIndex sindex, int dindex, int count);
36static jstring getNumberSymbolString(JNIEnv *env, jstring jlangtag, jstring jdefault, CFStringRef type);
37static jchar getNumberSymbolChar(JNIEnv *env, jstring jlangtag, jchar jdefault, CFStringRef type);
38
39// from java_props_macosx.c
40extern char * getMacOSXLocale(int cat);
41extern char * getPosixLocale(int cat);
42
43/*
44 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
45 * Method:    getDefaultLocale
46 * Signature: (I)Ljava/lang/String;
47 */
48JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDefaultLocale
49  (JNIEnv *env, jclass cls, jint cat) {
50    char * localeString = NULL;
51    int posixCat;
52    jstring ret = NULL;
53
54    switch (cat) {
55        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_DISPLAY:
56            posixCat = LC_MESSAGES;
57            break;
58        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_FORMAT:
59        default:
60            posixCat = LC_CTYPE;
61            break;
62    }
63
64    localeString = getMacOSXLocale(posixCat);
65    if (localeString == NULL) {
66        localeString = getPosixLocale(posixCat);
67        if (localeString == NULL) {
68            JNU_ThrowOutOfMemoryError(env, NULL);
69            return NULL;
70        }
71    }
72    ret = (*env)->NewStringUTF(env, localeString);
73    free(localeString);
74
75    return ret;
76}
77
78/*
79 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
80 * Method:    getDateTimePatternNative
81 * Signature: (IILjava/lang/String;)Ljava/lang/String;
82 */
83JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePatternNative
84  (JNIEnv *env, jclass cls, jint dateStyle, jint timeStyle, jstring jlangtag) {
85    jstring ret = NULL;
86    CFLocaleRef cflocale = CFLocaleCopyCurrent();
87
88    if (cflocale != NULL) {
89        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
90                                                  cflocale,
91                                                  convertDateFormatterStyle(dateStyle),
92                                                  convertDateFormatterStyle(timeStyle));
93        if (df != NULL) {
94            char buf[BUFLEN];
95            CFStringRef formatStr = CFDateFormatterGetFormat(df);
96            CFStringGetCString(formatStr, buf, BUFLEN, kCFStringEncodingUTF8);
97            ret = (*env)->NewStringUTF(env, buf);
98            CFRelease(df);
99        }
100        CFRelease(cflocale);
101    }
102
103    return ret;
104}
105
106/*
107 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
108 * Method:    getCalendarID
109 * Signature: (Ljava/lang/String;)Ljava/lang/String;
110 */
111JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarID
112  (JNIEnv *env, jclass cls, jstring jlangtag) {
113    jstring ret = NULL;
114    CFLocaleRef cflocale = CFLocaleCopyCurrent();
115
116    if (cflocale != NULL) {
117        char buf[BUFLEN];
118        CFTypeRef calid = CFLocaleGetValue(cflocale, kCFLocaleCalendarIdentifier);
119        CFStringGetCString((CFStringRef)calid, buf, BUFLEN, kCFStringEncodingUTF8);
120        ret = (*env)->NewStringUTF(env, buf);
121        CFRelease(cflocale);
122    }
123
124    return ret;
125}
126
127/*
128 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
129 * Method:    getAmPmStrings
130 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
131 */
132JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings
133  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray ampms) {
134    CFLocaleRef cflocale = CFLocaleCopyCurrent();
135    jstring tmp_string;
136    if (cflocale != NULL) {
137        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
138                                                  cflocale,
139                                                  kCFDateFormatterFullStyle,
140                                                  kCFDateFormatterFullStyle);
141        if (df != NULL) {
142            char buf[BUFLEN];
143            CFStringRef amStr = CFDateFormatterCopyProperty(df, kCFDateFormatterAMSymbol);
144            if (amStr != NULL) {
145                CFStringGetCString(amStr, buf, BUFLEN, kCFStringEncodingUTF8);
146                CFRelease(amStr);
147                tmp_string = (*env)->NewStringUTF(env, buf);
148                if (tmp_string != NULL) {
149                    (*env)->SetObjectArrayElement(env, ampms, 0, tmp_string);
150                }
151            }
152            if (!(*env)->ExceptionCheck(env)){
153                CFStringRef pmStr = CFDateFormatterCopyProperty(df, kCFDateFormatterPMSymbol);
154                if (pmStr != NULL) {
155                    CFStringGetCString(pmStr, buf, BUFLEN, kCFStringEncodingUTF8);
156                    CFRelease(pmStr);
157                    tmp_string = (*env)->NewStringUTF(env, buf);
158                    if (tmp_string != NULL) {
159                        (*env)->SetObjectArrayElement(env, ampms, 1, tmp_string);
160                    }
161                }
162            }
163            CFRelease(df);
164        }
165        CFRelease(cflocale);
166    }
167
168    return ampms;
169}
170
171/*
172 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
173 * Method:    getEras
174 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
175 */
176JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras
177  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray eras) {
178    CFLocaleRef cflocale = CFLocaleCopyCurrent();
179    if (cflocale != NULL) {
180        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
181                                                  cflocale,
182                                                  kCFDateFormatterFullStyle,
183                                                  kCFDateFormatterFullStyle);
184        if (df != NULL) {
185            CFArrayRef cferas = CFDateFormatterCopyProperty(df, kCFDateFormatterEraSymbols);
186            if (cferas != NULL) {
187                copyArrayElements(env, cferas, eras, 0, 0, CFArrayGetCount(cferas));
188                CFRelease(cferas);
189            }
190            CFRelease(df);
191        }
192        CFRelease(cflocale);
193    }
194
195    return eras;
196}
197
198/*
199 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
200 * Method:    getMonths
201 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
202 */
203JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonths
204  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray months) {
205    CFLocaleRef cflocale = CFLocaleCopyCurrent();
206    if (cflocale != NULL) {
207        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
208                                                  cflocale,
209                                                  kCFDateFormatterFullStyle,
210                                                  kCFDateFormatterFullStyle);
211        if (df != NULL) {
212            CFArrayRef cfmonths = CFDateFormatterCopyProperty(df, kCFDateFormatterMonthSymbols);
213            if (cfmonths != NULL) {
214                copyArrayElements(env, cfmonths, months, 0, 0, CFArrayGetCount(cfmonths));
215                CFRelease(cfmonths);
216            }
217            CFRelease(df);
218        }
219        CFRelease(cflocale);
220    }
221
222    return months;
223}
224
225/*
226 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
227 * Method:    getShortMonths
228 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
229 */
230JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortMonths
231  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray smonths) {
232    CFLocaleRef cflocale = CFLocaleCopyCurrent();
233    if (cflocale != NULL) {
234        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
235                                                  cflocale,
236                                                  kCFDateFormatterFullStyle,
237                                                  kCFDateFormatterFullStyle);
238        if (df != NULL) {
239            CFArrayRef cfsmonths = CFDateFormatterCopyProperty(df, kCFDateFormatterShortMonthSymbols);
240            if (cfsmonths != NULL) {
241                copyArrayElements(env, cfsmonths, smonths, 0, 0, CFArrayGetCount(cfsmonths));
242                CFRelease(cfsmonths);
243            }
244            CFRelease(df);
245        }
246        CFRelease(cflocale);
247    }
248
249    return smonths;
250}
251
252/*
253 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
254 * Method:    getWeekdays
255 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
256 */
257JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays
258  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {
259    CFLocaleRef cflocale = CFLocaleCopyCurrent();
260    if (cflocale != NULL) {
261        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
262                                                  cflocale,
263                                                  kCFDateFormatterFullStyle,
264                                                  kCFDateFormatterFullStyle);
265        if (df != NULL) {
266            CFArrayRef cfwdays = CFDateFormatterCopyProperty(df, kCFDateFormatterWeekdaySymbols);
267            if (cfwdays != NULL) {
268                copyArrayElements(env, cfwdays, wdays, 0, 1, CFArrayGetCount(cfwdays));
269                CFRelease(cfwdays);
270            }
271            CFRelease(df);
272        }
273        CFRelease(cflocale);
274    }
275
276    return wdays;
277}
278
279/*
280 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
281 * Method:    getShortWeekdays
282 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
283 */
284JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortWeekdays
285  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray swdays) {
286    CFLocaleRef cflocale = CFLocaleCopyCurrent();
287    if (cflocale != NULL) {
288        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
289                                                  cflocale,
290                                                  kCFDateFormatterFullStyle,
291                                                  kCFDateFormatterFullStyle);
292        if (df != NULL) {
293            CFArrayRef cfswdays = CFDateFormatterCopyProperty(df, kCFDateFormatterShortWeekdaySymbols);
294            if (cfswdays != NULL) {
295                copyArrayElements(env, cfswdays, swdays, 0, 1, CFArrayGetCount(cfswdays));
296                CFRelease(cfswdays);
297            }
298            CFRelease(df);
299        }
300        CFRelease(cflocale);
301    }
302
303    return swdays;
304}
305
306/*
307 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
308 * Method:    getNumberPatternNative
309 * Signature: (ILjava/lang/String;)Ljava/lang/String;
310 */
311JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPatternNative
312  (JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) {
313    jstring ret = NULL;
314    CFLocaleRef cflocale = CFLocaleCopyCurrent();
315    if (cflocale != NULL) {
316        CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
317                                                  cflocale,
318                                                  convertNumberFormatterStyle(numberStyle));
319        if (nf != NULL) {
320            char buf[BUFLEN];
321            CFStringRef formatStr = CFNumberFormatterGetFormat(nf);
322            CFStringGetCString(formatStr, buf, BUFLEN, kCFStringEncodingUTF8);
323            ret = (*env)->NewStringUTF(env, buf);
324            CFRelease(nf);
325        }
326        CFRelease(cflocale);
327    }
328
329    return ret;
330}
331
332/*
333 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
334 * Method:    getCurrencySymbol
335 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
336 */
337JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol
338  (JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) {
339    return getNumberSymbolString(env, jlangtag, currencySymbol, kCFNumberFormatterCurrencySymbol);
340}
341
342/*
343 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
344 * Method:    getDecimalSeparator
345 * Signature: (Ljava/lang/String;C)C
346 */
347JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator
348  (JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) {
349    return getNumberSymbolChar(env, jlangtag, decimalSeparator, kCFNumberFormatterDecimalSeparator);
350}
351
352/*
353 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
354 * Method:    getGroupingSeparator
355 * Signature: (Ljava/lang/String;C)C
356 */
357JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator
358  (JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) {
359    return getNumberSymbolChar(env, jlangtag, groupingSeparator, kCFNumberFormatterGroupingSeparator);
360}
361
362/*
363 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
364 * Method:    getInfinity
365 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
366 */
367JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity
368  (JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) {
369    return getNumberSymbolString(env, jlangtag, infinity, kCFNumberFormatterInfinitySymbol);
370}
371
372/*
373 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
374 * Method:    getInternationalCurrencySymbol
375 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
376 */
377JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol
378  (JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) {
379    return getNumberSymbolString(env, jlangtag, internationalCurrencySymbol, kCFNumberFormatterInternationalCurrencySymbol);
380}
381
382/*
383 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
384 * Method:    getMinusSign
385 * Signature: (Ljava/lang/String;C)C
386 */
387JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign
388  (JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) {
389    return getNumberSymbolChar(env, jlangtag, minusSign, kCFNumberFormatterMinusSign);
390}
391
392/*
393 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
394 * Method:    getMonetaryDecimalSeparator
395 * Signature: (Ljava/lang/String;C)C
396 */
397JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator
398  (JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) {
399    return getNumberSymbolChar(env, jlangtag, monetaryDecimalSeparator, kCFNumberFormatterCurrencyDecimalSeparator);
400}
401
402/*
403 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
404 * Method:    getNaN
405 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
406 */
407JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN
408  (JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) {
409    return getNumberSymbolString(env, jlangtag, nan, kCFNumberFormatterNaNSymbol);
410}
411
412/*
413 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
414 * Method:    getPercent
415 * Signature: (Ljava/lang/String;C)C
416 */
417JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent
418  (JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) {
419    return getNumberSymbolChar(env, jlangtag, percent, kCFNumberFormatterPercentSymbol);
420}
421
422/*
423 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
424 * Method:    getPerMill
425 * Signature: (Ljava/lang/String;C)C
426 */
427JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill
428  (JNIEnv *env, jclass cls, jstring jlangtag, jchar perMill) {
429    return getNumberSymbolChar(env, jlangtag, perMill, kCFNumberFormatterPerMillSymbol);
430}
431
432/*
433 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
434 * Method:    getZeroDigit
435 * Signature: (Ljava/lang/String;C)C
436 */
437JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit
438  (JNIEnv *env, jclass cls, jstring jlangtag, jchar zeroDigit) {
439    // The following code *should* work, but not for some reason :o
440    //
441    //return getNumberSymbolChar(env, jlangtag, zeroDigit, kCFNumberFormatterZeroSymbol);
442    //
443    // so here is a workaround.
444    jchar ret = zeroDigit;
445    CFLocaleRef cflocale = CFLocaleCopyCurrent();
446
447    if (cflocale != NULL) {
448        CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
449                                                  cflocale,
450                                                  kCFNumberFormatterNoStyle);
451        if (nf != NULL) {
452            int zero = 0;
453            CFStringRef str = CFNumberFormatterCreateStringWithValue(kCFAllocatorDefault,
454                              nf, kCFNumberIntType, &zero);
455            if (str != NULL) {
456                if (CFStringGetLength(str) > 0) {
457                    ret = CFStringGetCharacterAtIndex(str, 0);
458                }
459                CFRelease(str);
460            }
461
462            CFRelease(nf);
463        }
464
465        CFRelease(cflocale);
466    }
467
468    return ret;
469}
470
471/*
472 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
473 * Method:    getExponentSeparator
474 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
475 */
476JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getExponentSeparator
477  (JNIEnv *env, jclass cls, jstring jlangtag, jstring exponent) {
478    return getNumberSymbolString(env, jlangtag, exponent, kCFNumberFormatterExponentSymbol);
479}
480
481/*
482 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
483 * Method:    getCalendarInt
484 * Signature: (Ljava/lang/String;I)I
485 */
486JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarInt
487  (JNIEnv *env, jclass cls, jstring jlangtag, jint type) {
488    jint ret = 0;
489    CFCalendarRef cfcal = CFCalendarCopyCurrent();
490
491    if (cfcal != NULL) {
492        switch (type) {
493            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:
494                ret = CFCalendarGetFirstWeekday(cfcal);
495                break;
496            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_MINIMALDAYSINFIRSTWEEK:
497                ret = CFCalendarGetMinimumDaysInFirstWeek(cfcal);
498                break;
499            default:
500                ret = 0;
501        }
502
503        CFRelease(cfcal);
504    }
505
506    return ret;
507}
508
509/*
510 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
511 * Method:    getDisplayString
512 * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
513 */
514JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString
515  (JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring value) {
516    jstring ret = NULL;
517
518    const char *clangtag = (*env)->GetStringUTFChars(env, jlangtag, 0);
519    if (clangtag != NULL) {
520        const char *cvalue = (*env)->GetStringUTFChars(env, value, 0);
521        if (cvalue != NULL) {
522            CFStringRef cflangtag =
523                CFStringCreateWithCString(kCFAllocatorDefault, clangtag, kCFStringEncodingUTF8);
524            if (cflangtag != NULL) {
525                CFLocaleRef cflocale = CFLocaleCreate(kCFAllocatorDefault, cflangtag);
526                if (cflocale != NULL) {
527                    CFStringRef cfvalue =
528                        CFStringCreateWithCString(kCFAllocatorDefault, cvalue, kCFStringEncodingUTF8);
529                    if (cfvalue != NULL) {
530                        CFStringRef str = NULL;
531                        switch (type) {
532                            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:
533                                str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleLanguageCode, cfvalue);
534                                break;
535                            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_SCRIPT:
536                                str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleScriptCode, cfvalue);
537                                break;
538                            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:
539                                str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCountryCode, cfvalue);
540                                break;
541                            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_VARIANT:
542                                str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleVariantCode, cfvalue);
543                                break;
544                            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_CODE:
545                                str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCurrencyCode, cfvalue);
546                                break;
547                            case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:
548                                str = CFLocaleCopyDisplayNameForPropertyValue(cflocale, kCFLocaleCurrencySymbol, cfvalue);
549                                break;
550                        }
551                        if (str != NULL) {
552                            char buf[BUFLEN];
553                            CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
554                            CFRelease(str);
555                            ret = (*env)->NewStringUTF(env, buf);
556                        }
557                        CFRelease(cfvalue);
558                    }
559                    CFRelease(cflocale);
560                }
561                CFRelease(cflangtag);
562            }
563            (*env)->ReleaseStringUTFChars(env, value, cvalue);
564        }
565        (*env)->ReleaseStringUTFChars(env, jlangtag, clangtag);
566    }
567
568    return ret;
569}
570
571/*
572 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
573 * Method:    getTimeZoneDisplayString
574 * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
575 */
576JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getTimeZoneDisplayString
577  (JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring tzid) {
578    jstring ret = NULL;
579
580    const char *clangtag = (*env)->GetStringUTFChars(env, jlangtag, 0);
581    if (clangtag != NULL) {
582        const char *ctzid = (*env)->GetStringUTFChars(env, tzid, 0);
583        if (ctzid != NULL) {
584            CFStringRef cflangtag =
585                CFStringCreateWithCString(kCFAllocatorDefault, clangtag, kCFStringEncodingUTF8);
586            if (cflangtag != NULL) {
587                CFLocaleRef cflocale = CFLocaleCreate(kCFAllocatorDefault, cflangtag);
588                if (cflocale != NULL) {
589                    CFStringRef cftzid =
590                        CFStringCreateWithCString(kCFAllocatorDefault, ctzid, kCFStringEncodingUTF8);
591                    if (cftzid != NULL) {
592                        CFTimeZoneRef cftz = CFTimeZoneCreateWithName(kCFAllocatorDefault, cftzid, false);
593                        if (cftz != NULL) {
594                            CFStringRef str = NULL;
595                            switch (type) {
596                                case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_SHORT_STANDARD:
597                                    str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleShortStandard, cflocale);
598                                    break;
599                                case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_SHORT_DST:
600                                    str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleShortDaylightSaving, cflocale);
601                                    break;
602                                case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_LONG_STANDARD:
603                                    str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleStandard, cflocale);
604                                    break;
605                                case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_TZ_LONG_DST:
606                                    str = CFTimeZoneCopyLocalizedName(cftz, kCFTimeZoneNameStyleDaylightSaving, cflocale);
607                                    break;
608                            }
609                            if (str != NULL) {
610                                char buf[BUFLEN];
611                                CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
612                                CFRelease(str);
613                                ret = (*env)->NewStringUTF(env, buf);
614                            }
615                            CFRelease(cftz);
616                        }
617                        CFRelease(cftzid);
618                    }
619                    CFRelease(cflocale);
620                }
621                CFRelease(cflangtag);
622            }
623            (*env)->ReleaseStringUTFChars(env, tzid, ctzid);
624        }
625        (*env)->ReleaseStringUTFChars(env, jlangtag, clangtag);
626    }
627
628    return ret;
629}
630
631static CFDateFormatterStyle convertDateFormatterStyle(jint javaStyle) {
632    switch (javaStyle) {
633        case 0: // FULL
634            return kCFDateFormatterFullStyle;
635        case 1: // LONG
636            return kCFDateFormatterLongStyle;
637        case 2: // MEDIUM
638            return kCFDateFormatterMediumStyle;
639        case 3: // LONG
640            return kCFDateFormatterShortStyle;
641        case -1: // No style
642        default:
643            return kCFDateFormatterNoStyle;
644    }
645}
646
647static CFNumberFormatterStyle convertNumberFormatterStyle(jint javaStyle) {
648    switch (javaStyle) {
649        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:
650            return kCFNumberFormatterCurrencyStyle;
651        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:
652            return kCFNumberFormatterDecimalStyle;
653        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:
654            return kCFNumberFormatterDecimalStyle;
655        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:
656            return kCFNumberFormatterPercentStyle;
657        default:
658            return kCFNumberFormatterNoStyle;
659    }
660}
661
662static void copyArrayElements(JNIEnv *env, CFArrayRef cfarray, jobjectArray jarray, CFIndex sindex, int dindex, int count) {
663    char buf[BUFLEN];
664    jstring tmp_string;
665
666    for (; count > 0; sindex++, dindex++, count--) {
667        CFStringGetCString(CFArrayGetValueAtIndex(cfarray, sindex), buf, BUFLEN, kCFStringEncodingUTF8);
668        tmp_string = (*env)->NewStringUTF(env, buf);
669        if (tmp_string != NULL) {
670            (*env)->SetObjectArrayElement(env, jarray, dindex, tmp_string);
671        } else {
672            break;
673        }
674    }
675}
676
677static jstring getNumberSymbolString(JNIEnv *env, jstring jlangtag, jstring jdefault, CFStringRef type) {
678    char buf[BUFLEN];
679    jstring ret = jdefault;
680    CFLocaleRef cflocale = CFLocaleCopyCurrent();
681
682    if (cflocale != NULL) {
683        CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
684                                                  cflocale,
685                                                  kCFNumberFormatterNoStyle);
686        if (nf != NULL) {
687            CFStringRef str = CFNumberFormatterCopyProperty(nf, type);
688            if (str != NULL) {
689                CFStringGetCString(str, buf, BUFLEN, kCFStringEncodingUTF8);
690                CFRelease(str);
691                ret = (*env)->NewStringUTF(env, buf);
692            }
693
694            CFRelease(nf);
695        }
696
697        CFRelease(cflocale);
698    }
699
700    return ret;
701}
702
703static jchar getNumberSymbolChar(JNIEnv *env, jstring jlangtag, jchar jdefault, CFStringRef type) {
704    jchar ret = jdefault;
705    CFLocaleRef cflocale = CFLocaleCopyCurrent();
706
707    if (cflocale != NULL) {
708        CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorDefault,
709                                                  cflocale,
710                                                  kCFNumberFormatterNoStyle);
711        if (nf != NULL) {
712            CFStringRef str = CFNumberFormatterCopyProperty(nf, type);
713            if (str != NULL) {
714                if (CFStringGetLength(str) > 0) {
715                    ret = CFStringGetCharacterAtIndex(str, 0);
716                }
717                CFRelease(str);
718            }
719
720            CFRelease(nf);
721        }
722
723        CFRelease(cflocale);
724    }
725
726    return ret;
727}
728