Path: blob/master/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c
67769 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 = NULL;362WCHAR * pattern;363364langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);365CHECK_NULL_RETURN(langtag, NULL);366pattern = getNumberPattern(langtag, numberStyle);367if (!IS_NULL(pattern)) {368ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern));369free(pattern);370}371(*env)->ReleaseStringChars(env, jlangtag, langtag);372return ret;373}374375/*376* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl377* Method: isNativeDigit378* Signature: (Ljava/lang/String;)Z379*/380JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_isNativeDigit381(JNIEnv *env, jclass cls, jstring jlangtag) {382DWORD num;383int got;384const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);385CHECK_NULL_RETURN(langtag, JNI_FALSE);386got = getLocaleInfoWrapper(langtag,387LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,388(LPWSTR)&num, sizeof(num));389(*env)->ReleaseStringChars(env, jlangtag, langtag);390391return got && num == 2; // 2: native digit substitution392}393394/*395* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl396* Method: getCurrencySymbol397* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;398*/399JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol400(JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) {401WCHAR buf[BUFLEN];402int got;403const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);404CHECK_NULL_RETURN(langtag, currencySymbol);405got = getLocaleInfoWrapper(langtag, LOCALE_SCURRENCY, buf, BUFLEN);406(*env)->ReleaseStringChars(env, jlangtag, langtag);407408if (got) {409return (*env)->NewString(env, buf, (jsize)wcslen(buf));410} else {411return currencySymbol;412}413}414415/*416* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl417* Method: getDecimalSeparator418* Signature: (Ljava/lang/String;C)C419*/420JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator421(JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) {422WCHAR buf[BUFLEN];423int got;424const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);425CHECK_NULL_RETURN(langtag, decimalSeparator);426got = getLocaleInfoWrapper(langtag, LOCALE_SDECIMAL, buf, BUFLEN);427(*env)->ReleaseStringChars(env, jlangtag, langtag);428429if (got) {430return buf[0];431} else {432return decimalSeparator;433}434}435436/*437* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl438* Method: getGroupingSeparator439* Signature: (Ljava/lang/String;C)C440*/441JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator442(JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) {443WCHAR buf[BUFLEN];444int got;445const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);446CHECK_NULL_RETURN(langtag, groupingSeparator);447got = getLocaleInfoWrapper(langtag, LOCALE_STHOUSAND, buf, BUFLEN);448(*env)->ReleaseStringChars(env, jlangtag, langtag);449450if (got) {451return buf[0];452} else {453return groupingSeparator;454}455}456457/*458* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl459* Method: getInfinity460* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;461*/462JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity463(JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) {464WCHAR buf[BUFLEN];465int got;466const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);467CHECK_NULL_RETURN(langtag, infinity);468got = getLocaleInfoWrapper(langtag, LOCALE_SPOSINFINITY, buf, BUFLEN);469(*env)->ReleaseStringChars(env, jlangtag, langtag);470471if (got) {472return (*env)->NewString(env, buf, (jsize)wcslen(buf));473} else {474return infinity;475}476}477478/*479* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl480* Method: getInternationalCurrencySymbol481* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;482*/483JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol484(JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) {485WCHAR buf[BUFLEN];486int got;487const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);488CHECK_NULL_RETURN(langtag, internationalCurrencySymbol);489got = getLocaleInfoWrapper(langtag, LOCALE_SINTLSYMBOL, buf, BUFLEN);490(*env)->ReleaseStringChars(env, jlangtag, langtag);491492if (got) {493return (*env)->NewString(env, buf, (jsize)wcslen(buf));494} else {495return internationalCurrencySymbol;496}497}498499/*500* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl501* Method: getMinusSign502* Signature: (Ljava/lang/String;C)C503*/504JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign505(JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) {506WCHAR buf[BUFLEN];507int got;508const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);509CHECK_NULL_RETURN(langtag, minusSign);510got = getLocaleInfoWrapper(langtag, LOCALE_SNEGATIVESIGN, buf, BUFLEN);511(*env)->ReleaseStringChars(env, jlangtag, langtag);512513if (got) {514return buf[0];515} else {516return minusSign;517}518}519520/*521* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl522* Method: getMonetaryDecimalSeparator523* Signature: (Ljava/lang/String;C)C524*/525JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator526(JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) {527WCHAR buf[BUFLEN];528int got;529const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);530CHECK_NULL_RETURN(langtag, monetaryDecimalSeparator);531got = getLocaleInfoWrapper(langtag, LOCALE_SMONDECIMALSEP, buf, BUFLEN);532(*env)->ReleaseStringChars(env, jlangtag, langtag);533534if (got) {535return buf[0];536} else {537return monetaryDecimalSeparator;538}539}540541/*542* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl543* Method: getNaN544* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;545*/546JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN547(JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) {548WCHAR buf[BUFLEN];549int got;550const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);551CHECK_NULL_RETURN(langtag, nan);552got = getLocaleInfoWrapper(langtag, LOCALE_SNAN, buf, BUFLEN);553(*env)->ReleaseStringChars(env, jlangtag, langtag);554555if (got) {556return (*env)->NewString(env, buf, (jsize)wcslen(buf));557} else {558return nan;559}560}561562/*563* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl564* Method: getPercent565* Signature: (Ljava/lang/String;C)C566*/567JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent568(JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) {569WCHAR buf[BUFLEN];570int got;571const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);572CHECK_NULL_RETURN(langtag, percent);573got = getLocaleInfoWrapper(langtag, LOCALE_SPERCENT, buf, BUFLEN);574(*env)->ReleaseStringChars(env, jlangtag, langtag);575576if (got) {577return buf[0];578} else {579return percent;580}581}582583/*584* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl585* Method: getPerMill586* Signature: (Ljava/lang/String;C)C587*/588JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill589(JNIEnv *env, jclass cls, jstring jlangtag, jchar perMill) {590WCHAR buf[BUFLEN];591const jchar *langtag;592int got;593langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);594CHECK_NULL_RETURN(langtag, perMill);595got = getLocaleInfoWrapper(langtag, LOCALE_SPERMILLE, buf, BUFLEN);596597(*env)->ReleaseStringChars(env, jlangtag, langtag);598599if (got) {600return buf[0];601} else {602return perMill;603}604}605606/*607* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl608* Method: getZeroDigit609* Signature: (Ljava/lang/String;C)C610*/611JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit612(JNIEnv *env, jclass cls, jstring jlangtag, jchar zeroDigit) {613WCHAR buf[BUFLEN];614const jchar *langtag;615int got;616langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);617CHECK_NULL_RETURN(langtag, zeroDigit);618got = getLocaleInfoWrapper(langtag, LOCALE_SNATIVEDIGITS, buf, BUFLEN);619620(*env)->ReleaseStringChars(env, jlangtag, langtag);621622if (got) {623return buf[0];624} else {625return zeroDigit;626}627}628629/*630* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl631* Method: getCalendarDataValue632* Signature: (Ljava/lang/String;I)I633*/634JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDataValue635(JNIEnv *env, jclass cls, jstring jlangtag, jint type) {636DWORD num;637const jchar *langtag;638int got = 0;639640langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);641CHECK_NULL_RETURN(langtag, -1);642switch (type) {643case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:644got = getLocaleInfoWrapper(langtag,645LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER,646(LPWSTR)&num, sizeof(num));647break;648case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTWEEKOFYEAR:649got = getLocaleInfoWrapper(langtag,650LOCALE_IFIRSTWEEKOFYEAR | LOCALE_RETURN_NUMBER,651(LPWSTR)&num, sizeof(num));652break;653}654655(*env)->ReleaseStringChars(env, jlangtag, langtag);656657if (got) {658return num;659} else {660return -1;661}662}663664/*665* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl666* Method: getCalendarDisplayStrings667* Signature: (Ljava/lang/String;III)[Ljava/lang/String;668*/669JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDisplayStrings670(JNIEnv *env, jclass cls, jstring jlangtag, jint calid, jint field, jint style) {671jobjectArray ret = NULL;672CALTYPE * pCalType = NULL;673674switch (field) {675case CALENDAR_FIELD_ERA:676return getErasImpl(env, jlangtag, calid, style, NULL);677678case CALENDAR_FIELD_AM_PM:679ret = (*env)->NewObjectArray(env, AMPMTYPES,680(*env)->FindClass(env, "java/lang/String"), NULL);681if (ret != NULL) {682replaceCalendarArrayElems(env, jlangtag, calid, ret, ampmType,6830, AMPMTYPES, style, FALSE);684}685return ret;686687case CALENDAR_FIELD_DAY_OF_WEEK:688ret = (*env)->NewObjectArray(env, DOWTYPES,689(*env)->FindClass(env, "java/lang/String"), NULL);690if (ret != NULL) {691if (style & CALENDAR_STYLE_SHORT_MASK) {692pCalType = sWDaysType;693} else {694pCalType = wDaysType;695}696697replaceCalendarArrayElems(env, jlangtag, calid, ret, pCalType,6980, DOWTYPES, style, TRUE);699}700return ret;701702case CALENDAR_FIELD_MONTH:703ret = (*env)->NewObjectArray(env, MONTHTYPES,704(*env)->FindClass(env, "java/lang/String"), NULL);705if (ret != NULL) {706if (style & CALENDAR_STYLE_SHORT_MASK) {707pCalType = sMonthsType;708} else {709pCalType = monthsType;710}711712replaceCalendarArrayElems(env, jlangtag, calid, ret, pCalType,7130, MONTHTYPES, style, TRUE);714}715return ret;716717default:718// not supported719return NULL;720}721}722723/*724* Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl725* Method: getDisplayString726* Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;727*/728JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString729(JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring jvalue) {730LCTYPE lcType;731jstring jStr;732const jchar * pjChar;733WCHAR buf[BUFLEN];734int got = 0;735736switch (type) {737case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_NAME:738lcType = LOCALE_SNATIVECURRNAME;739jStr = jlangtag;740break;741case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:742lcType = LOCALE_SCURRENCY;743jStr = jlangtag;744break;745case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:746lcType = LOCALE_SLOCALIZEDLANGUAGENAME;747jStr = jvalue;748break;749case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:750lcType = LOCALE_SLOCALIZEDCOUNTRYNAME;751jStr = jvalue;752break;753default:754return NULL;755}756757pjChar = (*env)->GetStringChars(env, jStr, JNI_FALSE);758CHECK_NULL_RETURN(pjChar, NULL);759got = getLocaleInfoWrapper(pjChar, lcType, buf, BUFLEN);760(*env)->ReleaseStringChars(env, jStr, pjChar);761762if (got) {763return (*env)->NewString(env, buf, (jsize)wcslen(buf));764} else {765return NULL;766}767}768769int getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen) {770if (pGetLocaleInfoEx) {771if (wcscmp(L"und", (LPWSTR)langtag) == 0) {772// defaults to "en"773return pGetLocaleInfoEx(L"en", type, data, buflen);774} else {775return pGetLocaleInfoEx((LPWSTR)langtag, type, data, buflen);776}777} else {778// If we ever wanted to support WinXP, we will need extra module from779// MS...780// return GetLocaleInfo(DownlevelLocaleNameToLCID(langtag, 0), type, data, buflen);781return 0;782}783}784785int getCalendarInfoWrapper(const jchar *langtag, CALID id, LPCWSTR reserved, CALTYPE type, LPWSTR data, int buflen, LPDWORD val) {786if (pGetCalendarInfoEx) {787if (wcscmp(L"und", (LPWSTR)langtag) == 0) {788// defaults to "en"789return pGetCalendarInfoEx(L"en", id, reserved, type, data, buflen, val);790} else {791return pGetCalendarInfoEx((LPWSTR)langtag, id, reserved, type, data, buflen, val);792}793} else {794// If we ever wanted to support WinXP, we will need extra module from795// MS...796// return GetCalendarInfo(DownlevelLocaleNameToLCID(langtag, 0), ...);797return 0;798}799}800801jint getCalendarID(const jchar *langtag) {802DWORD type = -1;803int got = getLocaleInfoWrapper(langtag,804LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER,805(LPWSTR)&type, sizeof(type));806807if (got) {808switch (type) {809case CAL_GREGORIAN:810case CAL_GREGORIAN_US:811case CAL_JAPAN:812case CAL_TAIWAN:813case CAL_HIJRI:814case CAL_THAI:815case CAL_GREGORIAN_ME_FRENCH:816case CAL_GREGORIAN_ARABIC:817case CAL_GREGORIAN_XLIT_ENGLISH:818case CAL_GREGORIAN_XLIT_FRENCH:819case CAL_UMALQURA:820break;821822default:823// non-supported calendars return -1824type = -1;825break;826}827}828829return type;830}831832void replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jint calid, jobjectArray jarray, DWORD* pTypes, int offset, int length, int style, BOOL bCal) {833WCHAR name[BUFLEN];834const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);835jstring tmp_string;836CALTYPE isGenitive;837838CHECK_NULL(langtag);839840if (calid < 0) {841calid = getCalendarID(langtag);842}843844if (calid != -1) {845int i;846847if (!(style & CALENDAR_STYLE_STANDALONE_MASK)) {848isGenitive = CAL_RETURN_GENITIVE_NAMES;849}850851for (i = 0; i < length; i++) {852if (bCal && getCalendarInfoWrapper(langtag, calid, NULL,853pTypes[i] | isGenitive, name, BUFLEN, NULL) != 0 ||854getLocaleInfoWrapper(langtag, pTypes[i] | isGenitive, name, BUFLEN) != 0) {855tmp_string = (*env)->NewString(env, name, (jsize)wcslen(name));856if (tmp_string != NULL) {857(*env)->SetObjectArrayElement(env, jarray, i + offset, tmp_string);858}859}860}861}862863(*env)->ReleaseStringChars(env, jlangtag, langtag);864}865866WCHAR * getNumberPattern(const jchar * langtag, const jint numberStyle) {867WCHAR ret[BUFLEN];868WCHAR number[BUFLEN];869WCHAR fix[BUFLEN];870871getFixPart(langtag, numberStyle, TRUE, TRUE, ret); // "+"872getNumberPart(langtag, numberStyle, number);873wcscat_s(ret, BUFLEN-wcslen(ret), number); // "+12.34"874getFixPart(langtag, numberStyle, TRUE, FALSE, fix);875wcscat_s(ret, BUFLEN-wcslen(ret), fix); // "+12.34$"876wcscat_s(ret, BUFLEN-wcslen(ret), L";"); // "+12.34$;"877getFixPart(langtag, numberStyle, FALSE, TRUE, fix);878wcscat_s(ret, BUFLEN-wcslen(ret), fix); // "+12.34$;("879wcscat_s(ret, BUFLEN-wcslen(ret), number); // "+12.34$;(12.34"880getFixPart(langtag, numberStyle, FALSE, FALSE, fix);881wcscat_s(ret, BUFLEN-wcslen(ret), fix); // "+12.34$;(12.34$)"882883return _wcsdup(ret);884}885886void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number) {887DWORD digits = 0;888DWORD leadingZero = 0;889WCHAR grouping[BUFLEN];890int groupingLen;891WCHAR fractionPattern[BUFLEN];892WCHAR * integerPattern = number;893WCHAR * pDest;894895// Get info from Windows896switch (numberStyle) {897case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:898getLocaleInfoWrapper(langtag,899LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER,900(LPWSTR)&digits, sizeof(digits));901break;902903case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:904break;905906case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:907case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:908default:909getLocaleInfoWrapper(langtag,910LOCALE_IDIGITS | LOCALE_RETURN_NUMBER,911(LPWSTR)&digits, sizeof(digits));912break;913}914915getLocaleInfoWrapper(langtag,916LOCALE_ILZERO | LOCALE_RETURN_NUMBER,917(LPWSTR)&leadingZero, sizeof(leadingZero));918groupingLen = getLocaleInfoWrapper(langtag, LOCALE_SGROUPING, grouping, BUFLEN);919920// fraction pattern921if (digits > 0) {922int i;923for(i = digits; i > 0; i--) {924fractionPattern[i] = L'#';925}926fractionPattern[0] = L'.';927fractionPattern[digits+1] = L'\0';928} else {929fractionPattern[0] = L'\0';930}931932// integer pattern933pDest = integerPattern;934if (groupingLen > 0) {935int cur = groupingLen - 1;// subtracting null terminator936while (--cur >= 0) {937int repnum;938939if (grouping[cur] == L';') {940continue;941}942943repnum = grouping[cur] - 0x30;944if (repnum > 0) {945*pDest++ = L'#';946*pDest++ = L',';947while(--repnum > 0) {948*pDest++ = L'#';949}950}951}952}953954if (leadingZero != 0) {955*pDest++ = L'0';956} else {957*pDest++ = L'#';958}959*pDest = L'\0';960961wcscat_s(integerPattern, BUFLEN, fractionPattern);962}963964void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret) {965DWORD pattern = 0;966int style = numberStyle;967int got = 0;968969if (positive) {970if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {971got = getLocaleInfoWrapper(langtag,972LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER,973(LPWSTR)&pattern, sizeof(pattern));974} else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {975got = getLocaleInfoWrapper(langtag,976LOCALE_IPOSITIVEPERCENT | LOCALE_RETURN_NUMBER,977(LPWSTR)&pattern, sizeof(pattern));978}979} else {980if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {981got = getLocaleInfoWrapper(langtag,982LOCALE_INEGCURR | LOCALE_RETURN_NUMBER,983(LPWSTR)&pattern, sizeof(pattern));984} else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {985got = getLocaleInfoWrapper(langtag,986LOCALE_INEGATIVEPERCENT | LOCALE_RETURN_NUMBER,987(LPWSTR)&pattern, sizeof(pattern));988} else {989got = getLocaleInfoWrapper(langtag,990LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER,991(LPWSTR)&pattern, sizeof(pattern));992}993}994995if (numberStyle == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER) {996style = sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER;997}998999wcscpy(ret, fixes[!prefix][!positive][style][pattern]);1000}10011002int enumCalendarInfoWrapper(const jchar *langtag, CALID calid, CALTYPE type, LPWSTR buf, int buflen) {1003if (pEnumCalendarInfoExEx) {1004if (wcscmp(L"und", (LPWSTR)langtag) == 0) {1005// defaults to "en"1006return pEnumCalendarInfoExEx(&EnumCalendarInfoProc, L"en",1007calid, NULL, type, (LPARAM)buf);1008} else {1009return pEnumCalendarInfoExEx(&EnumCalendarInfoProc, langtag,1010calid, NULL, type, (LPARAM)buf);1011}1012} else {1013return 0;1014}1015}10161017BOOL CALLBACK EnumCalendarInfoProc(LPWSTR lpCalInfoStr, CALID calid, LPWSTR lpReserved, LPARAM lParam) {1018wcscat_s((LPWSTR)lParam, BUFLEN, lpCalInfoStr);1019wcscat_s((LPWSTR)lParam, BUFLEN, L",");1020return TRUE;1021}10221023jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint calid, jint style, jobjectArray eras) {1024const jchar * langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);1025WCHAR buf[BUFLEN];1026jobjectArray ret = eras;1027CALTYPE type;10281029CHECK_NULL_RETURN(langtag, ret);10301031buf[0] = '\0';1032if (style & CALENDAR_STYLE_SHORT_MASK) {1033type = CAL_SABBREVERASTRING;1034} else {1035type = CAL_SERASTRING;1036}10371038if (calid < 0) {1039calid = getCalendarID(langtag);1040}10411042if (calid != -1 && enumCalendarInfoWrapper(langtag, calid, type, buf, BUFLEN)) {1043// format in buf: "era0,era1,era2," where era0 is the current one1044int eraCount;1045LPWSTR current;1046jsize array_length;10471048for(eraCount = 0, current = buf; *current != '\0'; current++) {1049if (*current == L',') {1050eraCount ++;1051}1052}10531054if (eras != NULL) {1055array_length = (*env)->GetArrayLength(env, eras);1056} else {1057// +1 for the "before" era, e.g., BC, which Windows does not return.1058array_length = (jsize)eraCount + 1;1059ret = (*env)->NewObjectArray(env, array_length,1060(*env)->FindClass(env, "java/lang/String"), NULL);1061}10621063if (ret != NULL) {1064int eraIndex;1065LPWSTR era;10661067for(eraIndex = 0, era = current = buf; eraIndex < eraCount; era = current, eraIndex++) {1068while (*current != L',') {1069current++;1070}1071*current++ = '\0';10721073if (eraCount - eraIndex < array_length &&1074*era != '\0') {1075(*env)->SetObjectArrayElement(env, ret,1076(jsize)(eraCount - eraIndex),1077(*env)->NewString(env, era, (jsize)wcslen(era)));1078}1079}10801081// Hack for the Japanese Imperial Calendar to insert Gregorian era for1082// "Before Meiji"1083if (calid == CAL_JAPAN) {1084buf[0] = '\0';1085if (enumCalendarInfoWrapper(langtag, CAL_GREGORIAN, type, buf, BUFLEN)) {1086jsize len = (jsize)wcslen(buf);1087buf[--len] = '\0'; // remove the last ','1088(*env)->SetObjectArrayElement(env, ret, 0, (*env)->NewString(env, buf, len));1089}1090}1091}1092}10931094(*env)->ReleaseStringChars(env, jlangtag, langtag);1095return ret;1096}109710981099