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