HostLocaleProviderAdapter_md.c revision 10444:f08705540498
155682Smarkm/*
272445Sassar * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
355682Smarkm * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
455682Smarkm *
555682Smarkm * This code is free software; you can redistribute it and/or modify it
655682Smarkm * under the terms of the GNU General Public License version 2 only, as
755682Smarkm * published by the Free Software Foundation.  Oracle designates this
855682Smarkm * particular file as subject to the "Classpath" exception as provided
955682Smarkm * by Oracle in the LICENSE file that accompanied this code.
1055682Smarkm *
1155682Smarkm * This code is distributed in the hope that it will be useful, but WITHOUT
1255682Smarkm * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1355682Smarkm * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1455682Smarkm * version 2 for more details (a copy is included in the LICENSE file that
1555682Smarkm * accompanied this code).
1655682Smarkm *
1755682Smarkm * You should have received a copy of the GNU General Public License version
1855682Smarkm * 2 along with this work; if not, write to the Free Software Foundation,
1955682Smarkm * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2055682Smarkm *
2155682Smarkm * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2255682Smarkm * or visit www.oracle.com if you need additional information or have any
2355682Smarkm * questions.
2455682Smarkm */
2555682Smarkm
2655682Smarkm#include "sun_util_locale_provider_HostLocaleProviderAdapterImpl.h"
2755682Smarkm#include "jni_util.h"
2855682Smarkm#include <windows.h>
2955682Smarkm#include <gdefs.h>
3055682Smarkm#include <stdlib.h>
3155682Smarkm
3255682Smarkm#define BUFLEN 256
3355682Smarkm
3455682Smarkm// global variables
3555682Smarkmtypedef int (WINAPI *PGLIE)(const jchar *, LCTYPE, LPWSTR, int);
3655682Smarkmtypedef int (WINAPI *PGCIE)(const jchar *, CALID, LPCWSTR, CALTYPE, LPWSTR, int, LPDWORD);
3755682SmarkmPGLIE pGetLocaleInfoEx;
3855682SmarkmPGCIE pGetCalendarInfoEx;
39178825SdfrBOOL initialized = FALSE;
4055682Smarkm
4155682Smarkm// prototypes
4255682Smarkmint getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen);
4355682Smarkmint getCalendarInfoWrapper(const jchar *langtag, CALID id, LPCWSTR reserved, CALTYPE type, LPWSTR data, int buflen, LPDWORD val);
4455682Smarkmjint getCalendarID(const jchar *langtag);
4572445Sassarvoid replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jobjectArray jarray,
4655682Smarkm                       CALTYPE* pCalTypes, int offset, int length);
4755682SmarkmWCHAR * getNumberPattern(const jchar * langtag, const jint numberStyle);
4855682Smarkmvoid getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number);
4955682Smarkmvoid getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret);
5055682Smarkm
5155682Smarkm// from java_props_md.c
5255682Smarkmextern __declspec(dllexport) const char * getJavaIDFromLangID(LANGID langID);
5355682Smarkm
5455682SmarkmCALTYPE monthsType[] = {
5555682Smarkm    CAL_SMONTHNAME1,
5655682Smarkm    CAL_SMONTHNAME2,
5755682Smarkm    CAL_SMONTHNAME3,
5855682Smarkm    CAL_SMONTHNAME4,
5955682Smarkm    CAL_SMONTHNAME5,
6055682Smarkm    CAL_SMONTHNAME6,
6155682Smarkm    CAL_SMONTHNAME7,
6255682Smarkm    CAL_SMONTHNAME8,
6355682Smarkm    CAL_SMONTHNAME9,
6455682Smarkm    CAL_SMONTHNAME10,
6555682Smarkm    CAL_SMONTHNAME11,
6655682Smarkm    CAL_SMONTHNAME12,
6755682Smarkm    CAL_SMONTHNAME13,
6855682Smarkm};
6972445Sassar
7055682SmarkmCALTYPE sMonthsType[] = {
7155682Smarkm    CAL_SABBREVMONTHNAME1,
7255682Smarkm    CAL_SABBREVMONTHNAME2,
7355682Smarkm    CAL_SABBREVMONTHNAME3,
7455682Smarkm    CAL_SABBREVMONTHNAME4,
7555682Smarkm    CAL_SABBREVMONTHNAME5,
7655682Smarkm    CAL_SABBREVMONTHNAME6,
7755682Smarkm    CAL_SABBREVMONTHNAME7,
7855682Smarkm    CAL_SABBREVMONTHNAME8,
7955682Smarkm    CAL_SABBREVMONTHNAME9,
8055682Smarkm    CAL_SABBREVMONTHNAME10,
8155682Smarkm    CAL_SABBREVMONTHNAME11,
8255682Smarkm    CAL_SABBREVMONTHNAME12,
8355682Smarkm    CAL_SABBREVMONTHNAME13,
8455682Smarkm};
8555682Smarkm
8655682SmarkmCALTYPE wDaysType[] = {
8755682Smarkm    CAL_SDAYNAME7,
8855682Smarkm    CAL_SDAYNAME1,
8955682Smarkm    CAL_SDAYNAME2,
9055682Smarkm    CAL_SDAYNAME3,
9155682Smarkm    CAL_SDAYNAME4,
9255682Smarkm    CAL_SDAYNAME5,
9355682Smarkm    CAL_SDAYNAME6,
9455682Smarkm};
9555682Smarkm
9655682SmarkmCALTYPE sWDaysType[] = {
9755682Smarkm    CAL_SABBREVDAYNAME7,
9855682Smarkm    CAL_SABBREVDAYNAME1,
9955682Smarkm    CAL_SABBREVDAYNAME2,
10055682Smarkm    CAL_SABBREVDAYNAME3,
10155682Smarkm    CAL_SABBREVDAYNAME4,
10255682Smarkm    CAL_SABBREVDAYNAME5,
10355682Smarkm    CAL_SABBREVDAYNAME6,
10455682Smarkm};
10555682Smarkm
10655682SmarkmWCHAR * fixes[2][2][3][16] =
10755682Smarkm{
10855682Smarkm    { //prefix
10955682Smarkm        { //positive
11055682Smarkm            { // number
11155682Smarkm                L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
11255682Smarkm            },
11355682Smarkm            { // currency
11455682Smarkm                L"\xA4", L"", L"\xA4 ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
11555682Smarkm            },
11655682Smarkm            { // percent
11755682Smarkm                L"", L"", L"%", L"% ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
11855682Smarkm            }
119178825Sdfr        },
120178825Sdfr        { // negative
121178825Sdfr            { // number
12255682Smarkm                L"(", L"-", L"- ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
123178825Sdfr            },
124178825Sdfr            { //currency
125178825Sdfr                L"(\xA4", L"-\xA4", L"\xA4-", L"\xA4", L"(", L"-", L"", L"", L"-", L"-\xA4 ", L"", L"\xA4 ", L"\xA4 -", L"", L"(\xA4 ", L"("
12655682Smarkm            },
12755682Smarkm            { // percent
12855682Smarkm                L"-", L"-", L"-%", L"%-", L"%", L"", L"", L"-% ", L"", L"% ", L"% -", L"", L"", L"", L"", L"",
12955682Smarkm            }
130178825Sdfr        }
13155682Smarkm    },
13255682Smarkm    { // suffix
13355682Smarkm        { //positive
13455682Smarkm            { // number
13555682Smarkm                L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L""
13655682Smarkm            },
13755682Smarkm            { // currency
13855682Smarkm                L"", L"\xA4 ", L"", L" \xA4", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
13955682Smarkm            },
14055682Smarkm            { // percent
14155682Smarkm                L" %", L"%", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
14255682Smarkm            }
14355682Smarkm        },
14455682Smarkm        { // negative
14555682Smarkm            { // number
14655682Smarkm                L")", L"", L" ", L"-", L" -", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
14755682Smarkm            },
14855682Smarkm            { //currency
14955682Smarkm                L")", L"", L"", L"-", L"\xA4)", L"\xA4", L"-\xA4", L"\xA4-", L" \xA4", L"", L" \xA4-", L"-", L"", L"- \xA4", L")", L" \xA4)"
15055682Smarkm            },
15155682Smarkm            { // percent
15255682Smarkm                L" %", L"%", L"", L"", L"-", L"-%", L"%-", L"", L" %-", L"-", L"", L"- %", L"", L"", L"", L"",
15355682Smarkm            }
15455682Smarkm        }
15555682Smarkm    }
15655682Smarkm};
15755682Smarkm
15855682Smarkm/*
15955682Smarkm * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
16055682Smarkm * Method:    initialize
16155682Smarkm * Signature: ()Z
16255682Smarkm */
16355682SmarkmJNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_initialize
16455682Smarkm  (JNIEnv *env, jclass cls) {
16555682Smarkm    if (!initialized) {
16655682Smarkm        pGetLocaleInfoEx = (PGLIE)GetProcAddress(
16755682Smarkm            GetModuleHandle("kernel32.dll"),
16855682Smarkm            "GetLocaleInfoEx");
16955682Smarkm        pGetCalendarInfoEx = (PGCIE)GetProcAddress(
17055682Smarkm            GetModuleHandle("kernel32.dll"),
17155682Smarkm            "GetCalendarInfoEx");
17255682Smarkm        initialized =TRUE;
17355682Smarkm    }
17455682Smarkm
17555682Smarkm    return pGetLocaleInfoEx != NULL &&
17655682Smarkm           pGetCalendarInfoEx != NULL;
17755682Smarkm}
17855682Smarkm
17955682Smarkm/*
18055682Smarkm * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
18155682Smarkm * Method:    getDefaultLocale
18255682Smarkm * Signature: (I)Ljava/lang/String;
18355682Smarkm */
18455682SmarkmJNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDefaultLocale
18555682Smarkm  (JNIEnv *env, jclass cls, jint cat) {
18655682Smarkm    char * localeString = NULL;
18755682Smarkm    LANGID langid;
18855682Smarkm    jstring ret;
18955682Smarkm
19055682Smarkm    switch (cat) {
19155682Smarkm        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_DISPLAY:
19255682Smarkm            langid = LANGIDFROMLCID(GetUserDefaultUILanguage());
19355682Smarkm            break;
19455682Smarkm        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_FORMAT:
19555682Smarkm        default:
19655682Smarkm            langid = LANGIDFROMLCID(GetUserDefaultLCID());
19755682Smarkm            break;
19855682Smarkm    }
19955682Smarkm
20055682Smarkm    localeString = (char *)getJavaIDFromLangID(langid);
20155682Smarkm    if (localeString != NULL) {
20255682Smarkm        ret = (*env)->NewStringUTF(env, localeString);
20355682Smarkm        free(localeString);
20455682Smarkm    } else {
20555682Smarkm        JNU_ThrowOutOfMemoryError(env, "memory allocation error");
20655682Smarkm        ret = NULL;
20755682Smarkm    }
20855682Smarkm    return ret;
20955682Smarkm}
21055682Smarkm
21155682Smarkm/*
21255682Smarkm * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
21355682Smarkm * Method:    getDateTimePattern
21455682Smarkm * Signature: (IILjava/lang/String;)Ljava/lang/String;
21555682Smarkm */
21655682SmarkmJNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePattern
21755682Smarkm  (JNIEnv *env, jclass cls, jint dateStyle, jint timeStyle, jstring jlangtag) {
21855682Smarkm    WCHAR pattern[BUFLEN];
21955682Smarkm    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
22055682Smarkm    CHECK_NULL_RETURN(langtag, NULL);
22155682Smarkm
22255682Smarkm    pattern[0] = L'\0';
22355682Smarkm
22455682Smarkm    if (dateStyle == 0 || dateStyle == 1) {
22555682Smarkm        getLocaleInfoWrapper(langtag, LOCALE_SLONGDATE, pattern, BUFLEN);
22655682Smarkm    } else if (dateStyle == 2 || dateStyle == 3) {
22755682Smarkm        getLocaleInfoWrapper(langtag, LOCALE_SSHORTDATE, pattern, BUFLEN);
22855682Smarkm    }
22955682Smarkm
23055682Smarkm    if (timeStyle == 0 || timeStyle == 1) {
23155682Smarkm        getLocaleInfoWrapper(langtag, LOCALE_STIMEFORMAT, pattern, BUFLEN);
23255682Smarkm    } else if (timeStyle == 2 || timeStyle == 3) {
23355682Smarkm        getLocaleInfoWrapper(langtag, LOCALE_SSHORTTIME, pattern, BUFLEN);
23455682Smarkm    }
23555682Smarkm
23655682Smarkm    (*env)->ReleaseStringChars(env, jlangtag, langtag);
23755682Smarkm
23855682Smarkm    return (*env)->NewString(env, pattern, (jsize)wcslen(pattern));
23955682Smarkm}
24055682Smarkm
24155682Smarkm/*
24255682Smarkm * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
24355682Smarkm * Method:    getCalendarID
24455682Smarkm * Signature: (Ljava/lang/String;)I
24555682Smarkm */
24655682SmarkmJNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarID
24755682Smarkm  (JNIEnv *env, jclass cls, jstring jlangtag) {
248    const jchar *langtag;
249    jint ret;
250    langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
251    CHECK_NULL_RETURN(langtag, 0);
252    ret = getCalendarID(langtag);
253    (*env)->ReleaseStringChars(env, jlangtag, langtag);
254    return ret;
255}
256
257/*
258 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
259 * Method:    getAmPmStrings
260 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
261 */
262JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings
263  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray ampms) {
264    WCHAR buf[BUFLEN];
265    const jchar *langtag;
266    jstring tmp_string;
267
268    // AM
269    int got;
270    langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
271    CHECK_NULL_RETURN(langtag, NULL);
272    got = getLocaleInfoWrapper(langtag, LOCALE_S1159, buf, BUFLEN);
273    if (got) {
274        tmp_string = (*env)->NewString(env, buf, (jsize)wcslen(buf));
275        if (tmp_string != NULL) {
276            (*env)->SetObjectArrayElement(env, ampms, 0, tmp_string);
277        }
278    }
279
280    if (!(*env)->ExceptionCheck(env)){
281        // PM
282        got = getLocaleInfoWrapper(langtag, LOCALE_S2359, buf, BUFLEN);
283        if (got) {
284            tmp_string = (*env)->NewString(env, buf, (jsize)wcslen(buf));
285            if (tmp_string != NULL) {
286                (*env)->SetObjectArrayElement(env, ampms, 1, tmp_string);
287            }
288        }
289    }
290
291    (*env)->ReleaseStringChars(env, jlangtag, langtag);
292
293    return ampms;
294}
295
296/*
297 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
298 * Method:    getEras
299 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
300 */
301JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras
302  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray eras) {
303    WCHAR ad[BUFLEN];
304    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
305    jstring tmp_string;
306    CHECK_NULL_RETURN(langtag, eras);
307
308    getCalendarInfoWrapper(langtag, getCalendarID(langtag), NULL,
309                      CAL_SERASTRING, ad, BUFLEN, NULL);
310
311    // Windows does not provide B.C. era.
312    tmp_string = (*env)->NewString(env, ad, (jsize)wcslen(ad));
313    if (tmp_string != NULL) {
314        (*env)->SetObjectArrayElement(env, eras, 1, tmp_string);
315    }
316
317    (*env)->ReleaseStringChars(env, jlangtag, langtag);
318
319    return eras;
320}
321
322/*
323 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
324 * Method:    getMonths
325 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
326 */
327JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonths
328  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray months) {
329    replaceCalendarArrayElems(env, jlangtag, months, monthsType,
330                      0, sizeof(monthsType)/sizeof(CALTYPE));
331    return months;
332}
333
334/*
335 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
336 * Method:    getShortMonths
337 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
338 */
339JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortMonths
340  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray smonths) {
341    replaceCalendarArrayElems(env, jlangtag, smonths, sMonthsType,
342                      0, sizeof(sMonthsType)/sizeof(CALTYPE));
343    return smonths;
344}
345
346/*
347 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
348 * Method:    getWeekdays
349 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
350 */
351JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays
352  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {
353    replaceCalendarArrayElems(env, jlangtag, wdays, wDaysType,
354                      1, sizeof(wDaysType)/sizeof(CALTYPE));
355    return wdays;
356}
357
358/*
359 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
360 * Method:    getShortWeekdays
361 * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
362 */
363JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortWeekdays
364  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray swdays) {
365    replaceCalendarArrayElems(env, jlangtag, swdays, sWDaysType,
366                      1, sizeof(sWDaysType)/sizeof(CALTYPE));
367    return swdays;
368}
369
370/*
371 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
372 * Method:    getNumberPattern
373 * Signature: (ILjava/lang/String;)Ljava/lang/String;
374 */
375JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPattern
376  (JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) {
377    const jchar *langtag;
378    jstring ret;
379    WCHAR * pattern;
380
381    langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
382    CHECK_NULL_RETURN(langtag, NULL);
383    pattern = getNumberPattern(langtag, numberStyle);
384    CHECK_NULL_RETURN(pattern, NULL);
385
386    (*env)->ReleaseStringChars(env, jlangtag, langtag);
387    ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern));
388    free(pattern);
389
390    return ret;
391}
392
393/*
394 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
395 * Method:    isNativeDigit
396 * Signature: (Ljava/lang/String;)Z
397 */
398JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_isNativeDigit
399  (JNIEnv *env, jclass cls, jstring jlangtag) {
400    DWORD num;
401    int got;
402    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
403    CHECK_NULL_RETURN(langtag, JNI_FALSE);
404    got = getLocaleInfoWrapper(langtag,
405        LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
406        (LPWSTR)&num, sizeof(num));
407    (*env)->ReleaseStringChars(env, jlangtag, langtag);
408
409    return got && num == 2; // 2: native digit substitution
410}
411
412/*
413 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
414 * Method:    getCurrencySymbol
415 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
416 */
417JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol
418  (JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) {
419    WCHAR buf[BUFLEN];
420    int got;
421    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
422    CHECK_NULL_RETURN(langtag, currencySymbol);
423    got = getLocaleInfoWrapper(langtag, LOCALE_SCURRENCY, buf, BUFLEN);
424    (*env)->ReleaseStringChars(env, jlangtag, langtag);
425
426    if (got) {
427        return (*env)->NewString(env, buf, (jsize)wcslen(buf));
428    } else {
429        return currencySymbol;
430    }
431}
432
433/*
434 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
435 * Method:    getDecimalSeparator
436 * Signature: (Ljava/lang/String;C)C
437 */
438JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator
439  (JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) {
440    WCHAR buf[BUFLEN];
441    int got;
442    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
443    CHECK_NULL_RETURN(langtag, decimalSeparator);
444    got = getLocaleInfoWrapper(langtag, LOCALE_SDECIMAL, buf, BUFLEN);
445    (*env)->ReleaseStringChars(env, jlangtag, langtag);
446
447    if (got) {
448        return buf[0];
449    } else {
450        return decimalSeparator;
451    }
452}
453
454/*
455 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
456 * Method:    getGroupingSeparator
457 * Signature: (Ljava/lang/String;C)C
458 */
459JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator
460  (JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) {
461    WCHAR buf[BUFLEN];
462    int got;
463    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
464    CHECK_NULL_RETURN(langtag, groupingSeparator);
465    got = getLocaleInfoWrapper(langtag, LOCALE_STHOUSAND, buf, BUFLEN);
466    (*env)->ReleaseStringChars(env, jlangtag, langtag);
467
468    if (got) {
469        return buf[0];
470    } else {
471        return groupingSeparator;
472    }
473}
474
475/*
476 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
477 * Method:    getInfinity
478 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
479 */
480JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity
481  (JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) {
482    WCHAR buf[BUFLEN];
483    int got;
484    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
485    CHECK_NULL_RETURN(langtag, infinity);
486    got = getLocaleInfoWrapper(langtag, LOCALE_SPOSINFINITY, buf, BUFLEN);
487    (*env)->ReleaseStringChars(env, jlangtag, langtag);
488
489    if (got) {
490        return (*env)->NewString(env, buf, (jsize)wcslen(buf));
491    } else {
492        return infinity;
493    }
494}
495
496/*
497 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
498 * Method:    getInternationalCurrencySymbol
499 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
500 */
501JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol
502  (JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) {
503    WCHAR buf[BUFLEN];
504    int got;
505    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
506    CHECK_NULL_RETURN(langtag, internationalCurrencySymbol);
507    got = getLocaleInfoWrapper(langtag, LOCALE_SINTLSYMBOL, buf, BUFLEN);
508    (*env)->ReleaseStringChars(env, jlangtag, langtag);
509
510    if (got) {
511        return (*env)->NewString(env, buf, (jsize)wcslen(buf));
512    } else {
513        return internationalCurrencySymbol;
514    }
515}
516
517/*
518 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
519 * Method:    getMinusSign
520 * Signature: (Ljava/lang/String;C)C
521 */
522JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign
523  (JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) {
524    WCHAR buf[BUFLEN];
525    int got;
526    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
527    CHECK_NULL_RETURN(langtag, minusSign);
528    got = getLocaleInfoWrapper(langtag, LOCALE_SNEGATIVESIGN, buf, BUFLEN);
529    (*env)->ReleaseStringChars(env, jlangtag, langtag);
530
531    if (got) {
532        return buf[0];
533    } else {
534        return minusSign;
535    }
536}
537
538/*
539 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
540 * Method:    getMonetaryDecimalSeparator
541 * Signature: (Ljava/lang/String;C)C
542 */
543JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator
544  (JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) {
545    WCHAR buf[BUFLEN];
546    int got;
547    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
548    CHECK_NULL_RETURN(langtag, monetaryDecimalSeparator);
549    got = getLocaleInfoWrapper(langtag, LOCALE_SMONDECIMALSEP, buf, BUFLEN);
550    (*env)->ReleaseStringChars(env, jlangtag, langtag);
551
552    if (got) {
553        return buf[0];
554    } else {
555        return monetaryDecimalSeparator;
556    }
557}
558
559/*
560 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
561 * Method:    getNaN
562 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
563 */
564JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN
565  (JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) {
566    WCHAR buf[BUFLEN];
567    int got;
568    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
569    CHECK_NULL_RETURN(langtag, nan);
570    got = getLocaleInfoWrapper(langtag, LOCALE_SNAN, buf, BUFLEN);
571    (*env)->ReleaseStringChars(env, jlangtag, langtag);
572
573    if (got) {
574        return (*env)->NewString(env, buf, (jsize)wcslen(buf));
575    } else {
576        return nan;
577    }
578}
579
580/*
581 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
582 * Method:    getPercent
583 * Signature: (Ljava/lang/String;C)C
584 */
585JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent
586  (JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) {
587    WCHAR buf[BUFLEN];
588    int got;
589    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
590    CHECK_NULL_RETURN(langtag, percent);
591    got = getLocaleInfoWrapper(langtag, LOCALE_SPERCENT, buf, BUFLEN);
592    (*env)->ReleaseStringChars(env, jlangtag, langtag);
593
594    if (got) {
595        return buf[0];
596    } else {
597        return percent;
598    }
599}
600
601/*
602 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
603 * Method:    getPerMill
604 * Signature: (Ljava/lang/String;C)C
605 */
606JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill
607  (JNIEnv *env, jclass cls, jstring jlangtag, jchar perMill) {
608    WCHAR buf[BUFLEN];
609    const jchar *langtag;
610    int got;
611    langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
612    CHECK_NULL_RETURN(langtag, perMill);
613    got = getLocaleInfoWrapper(langtag, LOCALE_SPERMILLE, buf, BUFLEN);
614
615    (*env)->ReleaseStringChars(env, jlangtag, langtag);
616
617    if (got) {
618        return buf[0];
619    } else {
620        return perMill;
621    }
622}
623
624/*
625 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
626 * Method:    getZeroDigit
627 * Signature: (Ljava/lang/String;C)C
628 */
629JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit
630  (JNIEnv *env, jclass cls, jstring jlangtag, jchar zeroDigit) {
631    WCHAR buf[BUFLEN];
632    const jchar *langtag;
633    int got;
634    langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
635    CHECK_NULL_RETURN(langtag, zeroDigit);
636    got = getLocaleInfoWrapper(langtag, LOCALE_SNATIVEDIGITS, buf, BUFLEN);
637
638    (*env)->ReleaseStringChars(env, jlangtag, langtag);
639
640    if (got) {
641        return buf[0];
642    } else {
643        return zeroDigit;
644    }
645}
646
647/*
648 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
649 * Method:    getCalendarDataValue
650 * Signature: (Ljava/lang/String;I)I
651 */
652JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDataValue
653  (JNIEnv *env, jclass cls, jstring jlangtag, jint type) {
654    DWORD num;
655    const jchar *langtag;
656    int got = 0;
657
658    langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
659    CHECK_NULL_RETURN(langtag, -1);
660    switch (type) {
661    case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:
662        got = getLocaleInfoWrapper(langtag,
663            LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER,
664            (LPWSTR)&num, sizeof(num));
665        break;
666    }
667
668    (*env)->ReleaseStringChars(env, jlangtag, langtag);
669
670    if (got) {
671        return num;
672    } else {
673        return -1;
674    }
675}
676
677/*
678 * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
679 * Method:    getDisplayString
680 * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
681 */
682JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString
683  (JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring jvalue) {
684    LCTYPE lcType;
685    jstring jStr;
686    const jchar * pjChar;
687    WCHAR buf[BUFLEN];
688    int got = 0;
689
690    switch (type) {
691        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_NAME:
692            lcType = LOCALE_SNATIVECURRNAME;
693            jStr = jlangtag;
694            break;
695        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:
696            lcType = LOCALE_SCURRENCY;
697            jStr = jlangtag;
698            break;
699        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:
700            lcType = LOCALE_SLOCALIZEDLANGUAGENAME;
701            jStr = jvalue;
702            break;
703        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:
704            lcType = LOCALE_SLOCALIZEDCOUNTRYNAME;
705            jStr = jvalue;
706            break;
707        default:
708            return NULL;
709    }
710
711    pjChar = (*env)->GetStringChars(env, jStr, JNI_FALSE);
712    CHECK_NULL_RETURN(pjChar, NULL);
713    got = getLocaleInfoWrapper(pjChar, lcType, buf, BUFLEN);
714    (*env)->ReleaseStringChars(env, jStr, pjChar);
715
716    if (got) {
717        return (*env)->NewString(env, buf, (jsize)wcslen(buf));
718    } else {
719        return NULL;
720    }
721}
722
723int getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen) {
724    if (pGetLocaleInfoEx) {
725        if (wcscmp(L"und", (LPWSTR)langtag) == 0) {
726            // defaults to "en"
727            return pGetLocaleInfoEx(L"en", type, data, buflen);
728        } else {
729            return pGetLocaleInfoEx((LPWSTR)langtag, type, data, buflen);
730        }
731    } else {
732        // If we ever wanted to support WinXP, we will need extra module from
733        // MS...
734        // return GetLocaleInfo(DownlevelLocaleNameToLCID(langtag, 0), type, data, buflen);
735        return 0;
736    }
737}
738
739int getCalendarInfoWrapper(const jchar *langtag, CALID id, LPCWSTR reserved, CALTYPE type, LPWSTR data, int buflen, LPDWORD val) {
740    if (pGetCalendarInfoEx) {
741        if (wcscmp(L"und", (LPWSTR)langtag) == 0) {
742            // defaults to "en"
743            return pGetCalendarInfoEx(L"en", id, reserved, type, data, buflen, val);
744        } else {
745            return pGetCalendarInfoEx((LPWSTR)langtag, id, reserved, type, data, buflen, val);
746        }
747    } else {
748        // If we ever wanted to support WinXP, we will need extra module from
749        // MS...
750        // return GetCalendarInfo(DownlevelLocaleNameToLCID(langtag, 0), ...);
751        return 0;
752    }
753}
754
755jint getCalendarID(const jchar *langtag) {
756    DWORD type;
757    int got = getLocaleInfoWrapper(langtag,
758        LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER,
759        (LPWSTR)&type, sizeof(type));
760
761    if (got) {
762        return type;
763    } else {
764        return 0;
765    }
766}
767
768void replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jobjectArray jarray, CALTYPE* pCalTypes, int offset, int length) {
769    WCHAR name[BUFLEN];
770    const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
771    int calid;
772    jstring tmp_string;
773
774    CHECK_NULL(langtag);
775    calid = getCalendarID(langtag);
776
777    if (calid != -1) {
778        int i;
779        for (i = 0; i < length; i++) {
780            getCalendarInfoWrapper(langtag, calid, NULL,
781                              pCalTypes[i], name, BUFLEN, NULL);
782            tmp_string = (*env)->NewString(env, name, (jsize)wcslen(name));
783            if (tmp_string != NULL) {
784                (*env)->SetObjectArrayElement(env, jarray, i + offset, tmp_string);
785            }
786        }
787    }
788
789    (*env)->ReleaseStringChars(env, jlangtag, langtag);
790}
791
792WCHAR * getNumberPattern(const jchar * langtag, const jint numberStyle) {
793    WCHAR ret[BUFLEN];
794    WCHAR number[BUFLEN];
795    WCHAR fix[BUFLEN];
796
797    getFixPart(langtag, numberStyle, TRUE, TRUE, ret); // "+"
798    getNumberPart(langtag, numberStyle, number);
799    wcscat_s(ret, BUFLEN-wcslen(ret), number);      // "+12.34"
800    getFixPart(langtag, numberStyle, TRUE, FALSE, fix);
801    wcscat_s(ret, BUFLEN-wcslen(ret), fix);         // "+12.34$"
802    wcscat_s(ret, BUFLEN-wcslen(ret), L";");        // "+12.34$;"
803    getFixPart(langtag, numberStyle, FALSE, TRUE, fix);
804    wcscat_s(ret, BUFLEN-wcslen(ret), fix);         // "+12.34$;("
805    wcscat_s(ret, BUFLEN-wcslen(ret), number);      // "+12.34$;(12.34"
806    getFixPart(langtag, numberStyle, FALSE, FALSE, fix);
807    wcscat_s(ret, BUFLEN-wcslen(ret), fix);         // "+12.34$;(12.34$)"
808
809    return _wcsdup(ret);
810}
811
812void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number) {
813    DWORD digits = 0;
814    DWORD leadingZero = 0;
815    WCHAR grouping[BUFLEN];
816    int groupingLen;
817    WCHAR fractionPattern[BUFLEN];
818    WCHAR * integerPattern = number;
819    WCHAR * pDest;
820
821    // Get info from Windows
822    switch (numberStyle) {
823        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:
824            getLocaleInfoWrapper(langtag,
825                LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER,
826                (LPWSTR)&digits, sizeof(digits));
827            break;
828
829        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:
830            break;
831
832        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:
833        case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:
834        default:
835            getLocaleInfoWrapper(langtag,
836                LOCALE_IDIGITS | LOCALE_RETURN_NUMBER,
837                (LPWSTR)&digits, sizeof(digits));
838            break;
839    }
840
841    getLocaleInfoWrapper(langtag,
842        LOCALE_ILZERO | LOCALE_RETURN_NUMBER,
843        (LPWSTR)&leadingZero, sizeof(leadingZero));
844    groupingLen = getLocaleInfoWrapper(langtag, LOCALE_SGROUPING, grouping, BUFLEN);
845
846    // fraction pattern
847    if (digits > 0) {
848        int i;
849        for(i = digits;  i > 0; i--) {
850            fractionPattern[i] = L'0';
851        }
852        fractionPattern[0] = L'.';
853        fractionPattern[digits+1] = L'\0';
854    } else {
855        fractionPattern[0] = L'\0';
856    }
857
858    // integer pattern
859    pDest = integerPattern;
860    if (groupingLen > 0) {
861        int cur = groupingLen - 1;// subtracting null terminator
862        while (--cur >= 0) {
863            int repnum;
864
865            if (grouping[cur] == L';') {
866                continue;
867            }
868
869            repnum = grouping[cur] - 0x30;
870            if (repnum > 0) {
871                *pDest++ = L'#';
872                *pDest++ = L',';
873                while(--repnum > 0) {
874                    *pDest++ = L'#';
875                }
876            }
877        }
878    }
879
880    if (leadingZero != 0) {
881        *pDest++ = L'0';
882    } else {
883        *pDest++ = L'#';
884    }
885    *pDest = L'\0';
886
887    wcscat_s(integerPattern, BUFLEN, fractionPattern);
888}
889
890void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret) {
891    DWORD pattern = 0;
892    int style = numberStyle;
893    int got = 0;
894
895    if (positive) {
896        if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {
897            got = getLocaleInfoWrapper(langtag,
898                LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER,
899                (LPWSTR)&pattern, sizeof(pattern));
900        } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {
901            got = getLocaleInfoWrapper(langtag,
902                LOCALE_IPOSITIVEPERCENT | LOCALE_RETURN_NUMBER,
903                (LPWSTR)&pattern, sizeof(pattern));
904        }
905    } else {
906        if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {
907            got = getLocaleInfoWrapper(langtag,
908                LOCALE_INEGCURR | LOCALE_RETURN_NUMBER,
909                (LPWSTR)&pattern, sizeof(pattern));
910        } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {
911            got = getLocaleInfoWrapper(langtag,
912                LOCALE_INEGATIVEPERCENT | LOCALE_RETURN_NUMBER,
913                (LPWSTR)&pattern, sizeof(pattern));
914        } else {
915            got = getLocaleInfoWrapper(langtag,
916                LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER,
917                (LPWSTR)&pattern, sizeof(pattern));
918        }
919    }
920
921    if (numberStyle == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER) {
922        style = sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER;
923    }
924
925    wcscpy(ret, fixes[!prefix][!positive][style][pattern]);
926}
927