Path: blob/master/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c
41119 views
/*1* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "sun_util_locale_provider_HostLocaleProviderAdapterImpl.h"26#include "jni_util.h"27#include <windows.h>28#include <gdefs.h>29#include <stdlib.h>3031#define BUFLEN 2563233// java.util.Calendar constants34#define CALENDAR_FIELD_ERA 0 // Calendar.ERA35#define CALENDAR_FIELD_MONTH 2 // Calendar.MONTH36#define CALENDAR_FIELD_DAY_OF_WEEK 7 // Calendar.DAY_OF_WEEK37#define CALENDAR_FIELD_AM_PM 9 // Calendar.AM_PM38#define CALENDAR_STYLE_SHORT_MASK 0x00000001 // Calendar.SHORT39#define CALENDAR_STYLE_STANDALONE_MASK 0x00008000 // Calendar.STANDALONE4041// global variables42typedef int (WINAPI *PGLIE)(const jchar *, LCTYPE, LPWSTR, int);43typedef int (WINAPI *PGCIE)(const jchar *, CALID, LPCWSTR, CALTYPE, LPWSTR, int, LPDWORD);44typedef int (WINAPI *PECIEE)(CALINFO_ENUMPROCEXEX, const jchar *, CALID, LPCWSTR, CALTYPE, LPARAM);45PGLIE pGetLocaleInfoEx;46PGCIE pGetCalendarInfoEx;47PECIEE pEnumCalendarInfoExEx;48BOOL initialized = FALSE;4950// prototypes51int getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen);52int getCalendarInfoWrapper(const jchar *langtag, CALID id, LPCWSTR reserved, CALTYPE type, LPWSTR data, int buflen, LPDWORD val);53jint getCalendarID(const jchar *langtag);54void replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jint calid, jobjectArray jarray, DWORD* pTypes, int offset, int length, int style, BOOL bCal);55WCHAR * getNumberPattern(const jchar * langtag, const jint numberStyle);56void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number);57void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret);58int enumCalendarInfoWrapper(const jchar * langtag, CALID calid, CALTYPE type, LPWSTR buf, int buflen);59BOOL CALLBACK EnumCalendarInfoProc(LPWSTR lpCalInfoStr, CALID calid, LPWSTR lpReserved, LPARAM lParam);60jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint calid, jint style, jobjectArray eras);6162// from java_props_md.c63extern __declspec(dllexport) const char * getJavaIDFromLangID(LANGID langID);6465CALTYPE monthsType[] = {66CAL_SMONTHNAME1,67CAL_SMONTHNAME2,68CAL_SMONTHNAME3,69CAL_SMONTHNAME4,70CAL_SMONTHNAME5,71CAL_SMONTHNAME6,72CAL_SMONTHNAME7,73CAL_SMONTHNAME8,74CAL_SMONTHNAME9,75CAL_SMONTHNAME10,76CAL_SMONTHNAME11,77CAL_SMONTHNAME12,78CAL_SMONTHNAME13,79};8081CALTYPE sMonthsType[] = {82CAL_SABBREVMONTHNAME1,83CAL_SABBREVMONTHNAME2,84CAL_SABBREVMONTHNAME3,85CAL_SABBREVMONTHNAME4,86CAL_SABBREVMONTHNAME5,87CAL_SABBREVMONTHNAME6,88CAL_SABBREVMONTHNAME7,89CAL_SABBREVMONTHNAME8,90CAL_SABBREVMONTHNAME9,91CAL_SABBREVMONTHNAME10,92CAL_SABBREVMONTHNAME11,93CAL_SABBREVMONTHNAME12,94CAL_SABBREVMONTHNAME13,95};9697#define MONTHTYPES (sizeof(monthsType) / sizeof(CALTYPE))9899CALTYPE wDaysType[] = {100CAL_SDAYNAME7,101CAL_SDAYNAME1,102CAL_SDAYNAME2,103CAL_SDAYNAME3,104CAL_SDAYNAME4,105CAL_SDAYNAME5,106CAL_SDAYNAME6,107};108109CALTYPE sWDaysType[] = {110CAL_SABBREVDAYNAME7,111CAL_SABBREVDAYNAME1,112CAL_SABBREVDAYNAME2,113CAL_SABBREVDAYNAME3,114CAL_SABBREVDAYNAME4,115CAL_SABBREVDAYNAME5,116CAL_SABBREVDAYNAME6,117};118119#define DOWTYPES (sizeof(wDaysType) / sizeof(CALTYPE))120121LCTYPE ampmType [] = {122LOCALE_SAM,123LOCALE_SPM,124};125126#define AMPMTYPES (sizeof(ampmType) / sizeof(LCTYPE))127128WCHAR * fixes[2][2][3][16] =129{130{ //prefix131{ //positive132{ // number133L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",134},135{ // currency136L"\xA4", L"", L"\xA4 ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",137},138{ // percent139L"", L"", L"%", L"% ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",140}141},142{ // negative143{ // number144L"(", L"-", L"- ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",145},146{ //currency147L"(\xA4", L"-\xA4", L"\xA4-", L"\xA4", L"(", L"-", L"", L"", L"-", L"-\xA4 ", L"", L"\xA4 ", L"\xA4 -", L"", L"(\xA4 ", L"("148},149{ // percent150L"-", L"-", L"-%", L"%-", L"%", L"", L"", L"-% ", L"", L"% ", L"% -", L"", L"", L"", L"", L"",151}152}153},154{ // suffix155{ //positive156{ // number157L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L""158},159{ // currency160L"", L"\xA4 ", L"", L" \xA4", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",161},162{ // percent163L" %", L"%", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",164}165},166{ // negative167{ // number168L")", L"", L" ", L"-", L" -", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",169},170{ //currency171L")", L"", L"", L"-", L"\xA4)", L"\xA4", L"-\xA4", L"\xA4-", L" \xA4", L"", L" \xA4-", L"-", L"", L"- \xA4", L")", L" \xA4)"172},173{ // percent174L" %", L"%", L"", L"", L"-", L"-%", L"%-", L"", L" %-", L"-", L"", L"- %", L"", L"", L"", L"",175}176}177}178};179180/*181* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl182* Method: initialize183* Signature: ()Z184*/185JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_initialize186(JNIEnv *env, jclass cls) {187if (!initialized) {188pGetLocaleInfoEx = (PGLIE)GetProcAddress(189GetModuleHandle("kernel32.dll"),190"GetLocaleInfoEx");191pGetCalendarInfoEx = (PGCIE)GetProcAddress(192GetModuleHandle("kernel32.dll"),193"GetCalendarInfoEx");194pEnumCalendarInfoExEx = (PECIEE)GetProcAddress(195GetModuleHandle("kernel32.dll"),196"EnumCalendarInfoExEx");197initialized =TRUE;198}199200return pGetLocaleInfoEx != NULL &&201pGetCalendarInfoEx != NULL &&202pEnumCalendarInfoExEx != NULL;203}204205/*206* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl207* Method: getDefaultLocale208* Signature: (I)Ljava/lang/String;209*/210JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDefaultLocale211(JNIEnv *env, jclass cls, jint cat) {212char * localeString = NULL;213LANGID langid;214jstring ret;215216switch (cat) {217case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_DISPLAY:218langid = LANGIDFROMLCID(GetUserDefaultUILanguage());219break;220case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_FORMAT:221default:222langid = LANGIDFROMLCID(GetUserDefaultLCID());223break;224}225226localeString = (char *)getJavaIDFromLangID(langid);227if (localeString != NULL) {228ret = (*env)->NewStringUTF(env, localeString);229free(localeString);230} else {231JNU_ThrowOutOfMemoryError(env, "memory allocation error");232ret = NULL;233}234return ret;235}236237/*238* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl239* Method: getDateTimePattern240* Signature: (IILjava/lang/String;)Ljava/lang/String;241*/242JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePattern243(JNIEnv *env, jclass cls, jint dateStyle, jint timeStyle, jstring jlangtag) {244WCHAR pattern[BUFLEN];245const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);246CHECK_NULL_RETURN(langtag, NULL);247248pattern[0] = L'\0';249250if (dateStyle == 0 || dateStyle == 1) {251getLocaleInfoWrapper(langtag, LOCALE_SLONGDATE, pattern, BUFLEN);252} else if (dateStyle == 2 || dateStyle == 3) {253getLocaleInfoWrapper(langtag, LOCALE_SSHORTDATE, pattern, BUFLEN);254}255256if (timeStyle == 0 || timeStyle == 1) {257getLocaleInfoWrapper(langtag, LOCALE_STIMEFORMAT, pattern, BUFLEN);258} else if (timeStyle == 2 || timeStyle == 3) {259getLocaleInfoWrapper(langtag, LOCALE_SSHORTTIME, pattern, BUFLEN);260}261262(*env)->ReleaseStringChars(env, jlangtag, langtag);263264return (*env)->NewString(env, pattern, (jsize)wcslen(pattern));265}266267/*268* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl269* Method: getCalendarID270* Signature: (Ljava/lang/String;)I271*/272JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarID273(JNIEnv *env, jclass cls, jstring jlangtag) {274const jchar *langtag;275jint ret;276langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);277CHECK_NULL_RETURN(langtag, 0);278ret = getCalendarID(langtag);279(*env)->ReleaseStringChars(env, jlangtag, langtag);280return ret;281}282283/*284* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl285* Method: getAmPmStrings286* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;287*/288JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings289(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray ampms) {290replaceCalendarArrayElems(env, jlangtag, -1, ampms, ampmType,2910, AMPMTYPES, 0, FALSE);292return ampms;293}294295/*296* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl297* Method: getEras298* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;299*/300JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras301(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray eras) {302return getErasImpl(env, jlangtag, -1, 0, eras);303}304305/*306* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl307* Method: getMonths308* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;309*/310JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonths311(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray months) {312replaceCalendarArrayElems(env, jlangtag, -1, months, monthsType,3130, MONTHTYPES, 0, TRUE);314return months;315}316317/*318* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl319* Method: getShortMonths320* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;321*/322JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortMonths323(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray smonths) {324replaceCalendarArrayElems(env, jlangtag, -1, smonths, sMonthsType,3250, MONTHTYPES, 0, TRUE);326return smonths;327}328329/*330* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl331* Method: getWeekdays332* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;333*/334JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays335(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {336replaceCalendarArrayElems(env, jlangtag, -1, wdays, wDaysType,3371, DOWTYPES, 0, TRUE);338return wdays;339}340341/*342* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl343* Method: getShortWeekdays344* Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;345*/346JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortWeekdays347(JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray swdays) {348replaceCalendarArrayElems(env, jlangtag, -1, swdays, sWDaysType,3491, DOWTYPES, 0, TRUE);350return swdays;351}352353/*354* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl355* Method: getNumberPattern356* Signature: (ILjava/lang/String;)Ljava/lang/String;357*/358JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPattern359(JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) {360const jchar *langtag;361jstring ret;362WCHAR * pattern;363364langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);365CHECK_NULL_RETURN(langtag, NULL);366pattern = getNumberPattern(langtag, numberStyle);367CHECK_NULL_RETURN(pattern, NULL);368369(*env)->ReleaseStringChars(env, jlangtag, langtag);370ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern));371free(pattern);372373return ret;374}375376/*377* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl378* Method: isNativeDigit379* Signature: (Ljava/lang/String;)Z380*/381JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_isNativeDigit382(JNIEnv *env, jclass cls, jstring jlangtag) {383DWORD num;384int got;385const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);386CHECK_NULL_RETURN(langtag, JNI_FALSE);387got = getLocaleInfoWrapper(langtag,388LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,389(LPWSTR)&num, sizeof(num));390(*env)->ReleaseStringChars(env, jlangtag, langtag);391392return got && num == 2; // 2: native digit substitution393}394395/*396* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl397* Method: getCurrencySymbol398* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;399*/400JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol401(JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) {402WCHAR buf[BUFLEN];403int got;404const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);405CHECK_NULL_RETURN(langtag, currencySymbol);406got = getLocaleInfoWrapper(langtag, LOCALE_SCURRENCY, buf, BUFLEN);407(*env)->ReleaseStringChars(env, jlangtag, langtag);408409if (got) {410return (*env)->NewString(env, buf, (jsize)wcslen(buf));411} else {412return currencySymbol;413}414}415416/*417* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl418* Method: getDecimalSeparator419* Signature: (Ljava/lang/String;C)C420*/421JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator422(JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) {423WCHAR buf[BUFLEN];424int got;425const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);426CHECK_NULL_RETURN(langtag, decimalSeparator);427got = getLocaleInfoWrapper(langtag, LOCALE_SDECIMAL, buf, BUFLEN);428(*env)->ReleaseStringChars(env, jlangtag, langtag);429430if (got) {431return buf[0];432} else {433return decimalSeparator;434}435}436437/*438* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl439* Method: getGroupingSeparator440* Signature: (Ljava/lang/String;C)C441*/442JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator443(JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) {444WCHAR buf[BUFLEN];445int got;446const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);447CHECK_NULL_RETURN(langtag, groupingSeparator);448got = getLocaleInfoWrapper(langtag, LOCALE_STHOUSAND, buf, BUFLEN);449(*env)->ReleaseStringChars(env, jlangtag, langtag);450451if (got) {452return buf[0];453} else {454return groupingSeparator;455}456}457458/*459* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl460* Method: getInfinity461* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;462*/463JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity464(JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) {465WCHAR buf[BUFLEN];466int got;467const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);468CHECK_NULL_RETURN(langtag, infinity);469got = getLocaleInfoWrapper(langtag, LOCALE_SPOSINFINITY, buf, BUFLEN);470(*env)->ReleaseStringChars(env, jlangtag, langtag);471472if (got) {473return (*env)->NewString(env, buf, (jsize)wcslen(buf));474} else {475return infinity;476}477}478479/*480* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl481* Method: getInternationalCurrencySymbol482* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;483*/484JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol485(JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) {486WCHAR buf[BUFLEN];487int got;488const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);489CHECK_NULL_RETURN(langtag, internationalCurrencySymbol);490got = getLocaleInfoWrapper(langtag, LOCALE_SINTLSYMBOL, buf, BUFLEN);491(*env)->ReleaseStringChars(env, jlangtag, langtag);492493if (got) {494return (*env)->NewString(env, buf, (jsize)wcslen(buf));495} else {496return internationalCurrencySymbol;497}498}499500/*501* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl502* Method: getMinusSign503* Signature: (Ljava/lang/String;C)C504*/505JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign506(JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) {507WCHAR buf[BUFLEN];508int got;509const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);510CHECK_NULL_RETURN(langtag, minusSign);511got = getLocaleInfoWrapper(langtag, LOCALE_SNEGATIVESIGN, buf, BUFLEN);512(*env)->ReleaseStringChars(env, jlangtag, langtag);513514if (got) {515return buf[0];516} else {517return minusSign;518}519}520521/*522* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl523* Method: getMonetaryDecimalSeparator524* Signature: (Ljava/lang/String;C)C525*/526JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator527(JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) {528WCHAR buf[BUFLEN];529int got;530const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);531CHECK_NULL_RETURN(langtag, monetaryDecimalSeparator);532got = getLocaleInfoWrapper(langtag, LOCALE_SMONDECIMALSEP, buf, BUFLEN);533(*env)->ReleaseStringChars(env, jlangtag, langtag);534535if (got) {536return buf[0];537} else {538return monetaryDecimalSeparator;539}540}541542/*543* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl544* Method: getNaN545* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;546*/547JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN548(JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) {549WCHAR buf[BUFLEN];550int got;551const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);552CHECK_NULL_RETURN(langtag, nan);553got = getLocaleInfoWrapper(langtag, LOCALE_SNAN, buf, BUFLEN);554(*env)->ReleaseStringChars(env, jlangtag, langtag);555556if (got) {557return (*env)->NewString(env, buf, (jsize)wcslen(buf));558} else {559return nan;560}561}562563/*564* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl565* Method: getPercent566* Signature: (Ljava/lang/String;C)C567*/568JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent569(JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) {570WCHAR buf[BUFLEN];571int got;572const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);573CHECK_NULL_RETURN(langtag, percent);574got = getLocaleInfoWrapper(langtag, LOCALE_SPERCENT, buf, BUFLEN);575(*env)->ReleaseStringChars(env, jlangtag, langtag);576577if (got) {578return buf[0];579} else {580return percent;581}582}583584/*585* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl586* Method: getPerMill587* Signature: (Ljava/lang/String;C)C588*/589JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill590(JNIEnv *env, jclass cls, jstring jlangtag, jchar perMill) {591WCHAR buf[BUFLEN];592const jchar *langtag;593int got;594langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);595CHECK_NULL_RETURN(langtag, perMill);596got = getLocaleInfoWrapper(langtag, LOCALE_SPERMILLE, buf, BUFLEN);597598(*env)->ReleaseStringChars(env, jlangtag, langtag);599600if (got) {601return buf[0];602} else {603return perMill;604}605}606607/*608* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl609* Method: getZeroDigit610* Signature: (Ljava/lang/String;C)C611*/612JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit613(JNIEnv *env, jclass cls, jstring jlangtag, jchar zeroDigit) {614WCHAR buf[BUFLEN];615const jchar *langtag;616int got;617langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);618CHECK_NULL_RETURN(langtag, zeroDigit);619got = getLocaleInfoWrapper(langtag, LOCALE_SNATIVEDIGITS, buf, BUFLEN);620621(*env)->ReleaseStringChars(env, jlangtag, langtag);622623if (got) {624return buf[0];625} else {626return zeroDigit;627}628}629630/*631* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl632* Method: getCalendarDataValue633* Signature: (Ljava/lang/String;I)I634*/635JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDataValue636(JNIEnv *env, jclass cls, jstring jlangtag, jint type) {637DWORD num;638const jchar *langtag;639int got = 0;640641langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);642CHECK_NULL_RETURN(langtag, -1);643switch (type) {644case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:645got = getLocaleInfoWrapper(langtag,646LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER,647(LPWSTR)&num, sizeof(num));648break;649case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTWEEKOFYEAR:650got = getLocaleInfoWrapper(langtag,651LOCALE_IFIRSTWEEKOFYEAR | LOCALE_RETURN_NUMBER,652(LPWSTR)&num, sizeof(num));653break;654}655656(*env)->ReleaseStringChars(env, jlangtag, langtag);657658if (got) {659return num;660} else {661return -1;662}663}664665/*666* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl667* Method: getCalendarDisplayStrings668* Signature: (Ljava/lang/String;III)[Ljava/lang/String;669*/670JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDisplayStrings671(JNIEnv *env, jclass cls, jstring jlangtag, jint calid, jint field, jint style) {672jobjectArray ret = NULL;673CALTYPE * pCalType = NULL;674675switch (field) {676case CALENDAR_FIELD_ERA:677return getErasImpl(env, jlangtag, calid, style, NULL);678679case CALENDAR_FIELD_AM_PM:680ret = (*env)->NewObjectArray(env, AMPMTYPES,681(*env)->FindClass(env, "java/lang/String"), NULL);682if (ret != NULL) {683replaceCalendarArrayElems(env, jlangtag, calid, ret, ampmType,6840, AMPMTYPES, style, FALSE);685}686return ret;687688case CALENDAR_FIELD_DAY_OF_WEEK:689ret = (*env)->NewObjectArray(env, DOWTYPES,690(*env)->FindClass(env, "java/lang/String"), NULL);691if (ret != NULL) {692if (style & CALENDAR_STYLE_SHORT_MASK) {693pCalType = sWDaysType;694} else {695pCalType = wDaysType;696}697698replaceCalendarArrayElems(env, jlangtag, calid, ret, pCalType,6990, DOWTYPES, style, TRUE);700}701return ret;702703case CALENDAR_FIELD_MONTH:704ret = (*env)->NewObjectArray(env, MONTHTYPES,705(*env)->FindClass(env, "java/lang/String"), NULL);706if (ret != NULL) {707if (style & CALENDAR_STYLE_SHORT_MASK) {708pCalType = sMonthsType;709} else {710pCalType = monthsType;711}712713replaceCalendarArrayElems(env, jlangtag, calid, ret, pCalType,7140, MONTHTYPES, style, TRUE);715}716return ret;717718default:719// not supported720return NULL;721}722}723724/*725* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl726* Method: getDisplayString727* Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;728*/729JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString730(JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring jvalue) {731LCTYPE lcType;732jstring jStr;733const jchar * pjChar;734WCHAR buf[BUFLEN];735int got = 0;736737switch (type) {738case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_NAME:739lcType = LOCALE_SNATIVECURRNAME;740jStr = jlangtag;741break;742case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:743lcType = LOCALE_SCURRENCY;744jStr = jlangtag;745break;746case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:747lcType = LOCALE_SLOCALIZEDLANGUAGENAME;748jStr = jvalue;749break;750case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:751lcType = LOCALE_SLOCALIZEDCOUNTRYNAME;752jStr = jvalue;753break;754default:755return NULL;756}757758pjChar = (*env)->GetStringChars(env, jStr, JNI_FALSE);759CHECK_NULL_RETURN(pjChar, NULL);760got = getLocaleInfoWrapper(pjChar, lcType, buf, BUFLEN);761(*env)->ReleaseStringChars(env, jStr, pjChar);762763if (got) {764return (*env)->NewString(env, buf, (jsize)wcslen(buf));765} else {766return NULL;767}768}769770int getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen) {771if (pGetLocaleInfoEx) {772if (wcscmp(L"und", (LPWSTR)langtag) == 0) {773// defaults to "en"774return pGetLocaleInfoEx(L"en", type, data, buflen);775} else {776return pGetLocaleInfoEx((LPWSTR)langtag, type, data, buflen);777}778} else {779// If we ever wanted to support WinXP, we will need extra module from780// MS...781// return GetLocaleInfo(DownlevelLocaleNameToLCID(langtag, 0), type, data, buflen);782return 0;783}784}785786int getCalendarInfoWrapper(const jchar *langtag, CALID id, LPCWSTR reserved, CALTYPE type, LPWSTR data, int buflen, LPDWORD val) {787if (pGetCalendarInfoEx) {788if (wcscmp(L"und", (LPWSTR)langtag) == 0) {789// defaults to "en"790return pGetCalendarInfoEx(L"en", id, reserved, type, data, buflen, val);791} else {792return pGetCalendarInfoEx((LPWSTR)langtag, id, reserved, type, data, buflen, val);793}794} else {795// If we ever wanted to support WinXP, we will need extra module from796// MS...797// return GetCalendarInfo(DownlevelLocaleNameToLCID(langtag, 0), ...);798return 0;799}800}801802jint getCalendarID(const jchar *langtag) {803DWORD type = -1;804int got = getLocaleInfoWrapper(langtag,805LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER,806(LPWSTR)&type, sizeof(type));807808if (got) {809switch (type) {810case CAL_GREGORIAN:811case CAL_GREGORIAN_US:812case CAL_JAPAN:813case CAL_TAIWAN:814case CAL_HIJRI:815case CAL_THAI:816case CAL_GREGORIAN_ME_FRENCH:817case CAL_GREGORIAN_ARABIC:818case CAL_GREGORIAN_XLIT_ENGLISH:819case CAL_GREGORIAN_XLIT_FRENCH:820case CAL_UMALQURA:821break;822823default:824// non-supported calendars return -1825type = -1;826break;827}828}829830return type;831}832833void replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jint calid, jobjectArray jarray, DWORD* pTypes, int offset, int length, int style, BOOL bCal) {834WCHAR name[BUFLEN];835const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);836jstring tmp_string;837CALTYPE isGenitive;838839CHECK_NULL(langtag);840841if (calid < 0) {842calid = getCalendarID(langtag);843}844845if (calid != -1) {846int i;847848if (!(style & CALENDAR_STYLE_STANDALONE_MASK)) {849isGenitive = CAL_RETURN_GENITIVE_NAMES;850}851852for (i = 0; i < length; i++) {853if (bCal && getCalendarInfoWrapper(langtag, calid, NULL,854pTypes[i] | isGenitive, name, BUFLEN, NULL) != 0 ||855getLocaleInfoWrapper(langtag, pTypes[i] | isGenitive, name, BUFLEN) != 0) {856tmp_string = (*env)->NewString(env, name, (jsize)wcslen(name));857if (tmp_string != NULL) {858(*env)->SetObjectArrayElement(env, jarray, i + offset, tmp_string);859}860}861}862}863864(*env)->ReleaseStringChars(env, jlangtag, langtag);865}866867WCHAR * getNumberPattern(const jchar * langtag, const jint numberStyle) {868WCHAR ret[BUFLEN];869WCHAR number[BUFLEN];870WCHAR fix[BUFLEN];871872getFixPart(langtag, numberStyle, TRUE, TRUE, ret); // "+"873getNumberPart(langtag, numberStyle, number);874wcscat_s(ret, BUFLEN-wcslen(ret), number); // "+12.34"875getFixPart(langtag, numberStyle, TRUE, FALSE, fix);876wcscat_s(ret, BUFLEN-wcslen(ret), fix); // "+12.34$"877wcscat_s(ret, BUFLEN-wcslen(ret), L";"); // "+12.34$;"878getFixPart(langtag, numberStyle, FALSE, TRUE, fix);879wcscat_s(ret, BUFLEN-wcslen(ret), fix); // "+12.34$;("880wcscat_s(ret, BUFLEN-wcslen(ret), number); // "+12.34$;(12.34"881getFixPart(langtag, numberStyle, FALSE, FALSE, fix);882wcscat_s(ret, BUFLEN-wcslen(ret), fix); // "+12.34$;(12.34$)"883884return _wcsdup(ret);885}886887void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number) {888DWORD digits = 0;889DWORD leadingZero = 0;890WCHAR grouping[BUFLEN];891int groupingLen;892WCHAR fractionPattern[BUFLEN];893WCHAR * integerPattern = number;894WCHAR * pDest;895896// Get info from Windows897switch (numberStyle) {898case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:899getLocaleInfoWrapper(langtag,900LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER,901(LPWSTR)&digits, sizeof(digits));902break;903904case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:905break;906907case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:908case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:909default:910getLocaleInfoWrapper(langtag,911LOCALE_IDIGITS | LOCALE_RETURN_NUMBER,912(LPWSTR)&digits, sizeof(digits));913break;914}915916getLocaleInfoWrapper(langtag,917LOCALE_ILZERO | LOCALE_RETURN_NUMBER,918(LPWSTR)&leadingZero, sizeof(leadingZero));919groupingLen = getLocaleInfoWrapper(langtag, LOCALE_SGROUPING, grouping, BUFLEN);920921// fraction pattern922if (digits > 0) {923int i;924for(i = digits; i > 0; i--) {925fractionPattern[i] = L'#';926}927fractionPattern[0] = L'.';928fractionPattern[digits+1] = L'\0';929} else {930fractionPattern[0] = L'\0';931}932933// integer pattern934pDest = integerPattern;935if (groupingLen > 0) {936int cur = groupingLen - 1;// subtracting null terminator937while (--cur >= 0) {938int repnum;939940if (grouping[cur] == L';') {941continue;942}943944repnum = grouping[cur] - 0x30;945if (repnum > 0) {946*pDest++ = L'#';947*pDest++ = L',';948while(--repnum > 0) {949*pDest++ = L'#';950}951}952}953}954955if (leadingZero != 0) {956*pDest++ = L'0';957} else {958*pDest++ = L'#';959}960*pDest = L'\0';961962wcscat_s(integerPattern, BUFLEN, fractionPattern);963}964965void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret) {966DWORD pattern = 0;967int style = numberStyle;968int got = 0;969970if (positive) {971if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {972got = getLocaleInfoWrapper(langtag,973LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER,974(LPWSTR)&pattern, sizeof(pattern));975} else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {976got = getLocaleInfoWrapper(langtag,977LOCALE_IPOSITIVEPERCENT | LOCALE_RETURN_NUMBER,978(LPWSTR)&pattern, sizeof(pattern));979}980} else {981if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {982got = getLocaleInfoWrapper(langtag,983LOCALE_INEGCURR | LOCALE_RETURN_NUMBER,984(LPWSTR)&pattern, sizeof(pattern));985} else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {986got = getLocaleInfoWrapper(langtag,987LOCALE_INEGATIVEPERCENT | LOCALE_RETURN_NUMBER,988(LPWSTR)&pattern, sizeof(pattern));989} else {990got = getLocaleInfoWrapper(langtag,991LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER,992(LPWSTR)&pattern, sizeof(pattern));993}994}995996if (numberStyle == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER) {997style = sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER;998}9991000wcscpy(ret, fixes[!prefix][!positive][style][pattern]);1001}10021003int enumCalendarInfoWrapper(const jchar *langtag, CALID calid, CALTYPE type, LPWSTR buf, int buflen) {1004if (pEnumCalendarInfoExEx) {1005if (wcscmp(L"und", (LPWSTR)langtag) == 0) {1006// defaults to "en"1007return pEnumCalendarInfoExEx(&EnumCalendarInfoProc, L"en",1008calid, NULL, type, (LPARAM)buf);1009} else {1010return pEnumCalendarInfoExEx(&EnumCalendarInfoProc, langtag,1011calid, NULL, type, (LPARAM)buf);1012}1013} else {1014return 0;1015}1016}10171018BOOL CALLBACK EnumCalendarInfoProc(LPWSTR lpCalInfoStr, CALID calid, LPWSTR lpReserved, LPARAM lParam) {1019wcscat_s((LPWSTR)lParam, BUFLEN, lpCalInfoStr);1020wcscat_s((LPWSTR)lParam, BUFLEN, L",");1021return TRUE;1022}10231024jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint calid, jint style, jobjectArray eras) {1025const jchar * langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);1026WCHAR buf[BUFLEN];1027jobjectArray ret = eras;1028CALTYPE type;10291030CHECK_NULL_RETURN(langtag, ret);10311032buf[0] = '\0';1033if (style & CALENDAR_STYLE_SHORT_MASK) {1034type = CAL_SABBREVERASTRING;1035} else {1036type = CAL_SERASTRING;1037}10381039if (calid < 0) {1040calid = getCalendarID(langtag);1041}10421043if (calid != -1 && enumCalendarInfoWrapper(langtag, calid, type, buf, BUFLEN)) {1044// format in buf: "era0,era1,era2," where era0 is the current one1045int eraCount;1046LPWSTR current;1047jsize array_length;10481049for(eraCount = 0, current = buf; *current != '\0'; current++) {1050if (*current == L',') {1051eraCount ++;1052}1053}10541055if (eras != NULL) {1056array_length = (*env)->GetArrayLength(env, eras);1057} else {1058// +1 for the "before" era, e.g., BC, which Windows does not return.1059array_length = (jsize)eraCount + 1;1060ret = (*env)->NewObjectArray(env, array_length,1061(*env)->FindClass(env, "java/lang/String"), NULL);1062}10631064if (ret != NULL) {1065int eraIndex;1066LPWSTR era;10671068for(eraIndex = 0, era = current = buf; eraIndex < eraCount; era = current, eraIndex++) {1069while (*current != L',') {1070current++;1071}1072*current++ = '\0';10731074if (eraCount - eraIndex < array_length &&1075*era != '\0') {1076(*env)->SetObjectArrayElement(env, ret,1077(jsize)(eraCount - eraIndex),1078(*env)->NewString(env, era, (jsize)wcslen(era)));1079}1080}10811082// Hack for the Japanese Imperial Calendar to insert Gregorian era for1083// "Before Meiji"1084if (calid == CAL_JAPAN) {1085buf[0] = '\0';1086if (enumCalendarInfoWrapper(langtag, CAL_GREGORIAN, type, buf, BUFLEN)) {1087jsize len = (jsize)wcslen(buf);1088buf[--len] = '\0'; // remove the last ','1089(*env)->SetObjectArrayElement(env, ret, 0, (*env)->NewString(env, buf, len));1090}1091}1092}1093}10941095(*env)->ReleaseStringChars(env, jlangtag, langtag);1096return ret;1097}109810991100