1 /*
2  * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "sun_util_locale_provider_HostLocaleProviderAdapterImpl.h"
27 #include "jni_util.h"
28 #include <windows.h>
29 #include <gdefs.h>
30 #include <stdlib.h>
31 
32 #define BUFLEN 256
33 
34 // java.util.Calendar constants
35 #define CALENDAR_FIELD_ERA              0           // Calendar.ERA
36 #define CALENDAR_FIELD_MONTH            2           // Calendar.MONTH
37 #define CALENDAR_FIELD_DAY_OF_WEEK      7           // Calendar.DAY_OF_WEEK
38 #define CALENDAR_FIELD_AM_PM            9           // Calendar.AM_PM
39 #define CALENDAR_STYLE_SHORT_MASK       0x00000001  // Calendar.SHORT
40 #define CALENDAR_STYLE_STANDALONE_MASK  0x00008000  // Calendar.STANDALONE
41 
42 // global variables
43 typedef int (WINAPI *PGLIE)(const jchar *, LCTYPE, LPWSTR, int);
44 typedef int (WINAPI *PGCIE)(const jchar *, CALID, LPCWSTR, CALTYPE, LPWSTR, int, LPDWORD);
45 typedef int (WINAPI *PECIEE)(CALINFO_ENUMPROCEXEX, const jchar *, CALID, LPCWSTR, CALTYPE, LPARAM);
46 PGLIE pGetLocaleInfoEx;
47 PGCIE pGetCalendarInfoEx;
48 PECIEE pEnumCalendarInfoExEx;
49 BOOL initialized = FALSE;
50 
51 // prototypes
52 int getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen);
53 int getCalendarInfoWrapper(const jchar *langtag, CALID id, LPCWSTR reserved, CALTYPE type, LPWSTR data, int buflen, LPDWORD val);
54 jint getCalendarID(const jchar *langtag);
55 void replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jint calid, jobjectArray jarray, DWORD* pTypes, int offset, int length, int style, BOOL bCal);
56 WCHAR * getNumberPattern(const jchar * langtag, const jint numberStyle);
57 void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number);
58 void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret);
59 int enumCalendarInfoWrapper(const jchar * langtag, CALID calid, CALTYPE type, LPWSTR buf, int buflen);
60 BOOL CALLBACK EnumCalendarInfoProc(LPWSTR lpCalInfoStr, CALID calid, LPWSTR lpReserved, LPARAM lParam);
61 jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint calid, jint style, jobjectArray eras);
62 
63 // from java_props_md.c
64 extern __declspec(dllexport) const char * getJavaIDFromLangID(LANGID langID);
65 
66 CALTYPE monthsType[] = {
67     CAL_SMONTHNAME1,
68     CAL_SMONTHNAME2,
69     CAL_SMONTHNAME3,
70     CAL_SMONTHNAME4,
71     CAL_SMONTHNAME5,
72     CAL_SMONTHNAME6,
73     CAL_SMONTHNAME7,
74     CAL_SMONTHNAME8,
75     CAL_SMONTHNAME9,
76     CAL_SMONTHNAME10,
77     CAL_SMONTHNAME11,
78     CAL_SMONTHNAME12,
79     CAL_SMONTHNAME13,
80 };
81 
82 CALTYPE sMonthsType[] = {
83     CAL_SABBREVMONTHNAME1,
84     CAL_SABBREVMONTHNAME2,
85     CAL_SABBREVMONTHNAME3,
86     CAL_SABBREVMONTHNAME4,
87     CAL_SABBREVMONTHNAME5,
88     CAL_SABBREVMONTHNAME6,
89     CAL_SABBREVMONTHNAME7,
90     CAL_SABBREVMONTHNAME8,
91     CAL_SABBREVMONTHNAME9,
92     CAL_SABBREVMONTHNAME10,
93     CAL_SABBREVMONTHNAME11,
94     CAL_SABBREVMONTHNAME12,
95     CAL_SABBREVMONTHNAME13,
96 };
97 
98 #define MONTHTYPES (sizeof(monthsType) / sizeof(CALTYPE))
99 
100 CALTYPE wDaysType[] = {
101     CAL_SDAYNAME7,
102     CAL_SDAYNAME1,
103     CAL_SDAYNAME2,
104     CAL_SDAYNAME3,
105     CAL_SDAYNAME4,
106     CAL_SDAYNAME5,
107     CAL_SDAYNAME6,
108 };
109 
110 CALTYPE sWDaysType[] = {
111     CAL_SABBREVDAYNAME7,
112     CAL_SABBREVDAYNAME1,
113     CAL_SABBREVDAYNAME2,
114     CAL_SABBREVDAYNAME3,
115     CAL_SABBREVDAYNAME4,
116     CAL_SABBREVDAYNAME5,
117     CAL_SABBREVDAYNAME6,
118 };
119 
120 #define DOWTYPES (sizeof(wDaysType) / sizeof(CALTYPE))
121 
122 LCTYPE ampmType [] = {
123     LOCALE_SAM,
124     LOCALE_SPM,
125 };
126 
127 #define AMPMTYPES (sizeof(ampmType) / sizeof(LCTYPE))
128 
129 WCHAR * fixes[2][2][3][16] =
130 {
131     { //prefix
132         { //positive
133             { // number
134                 L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
135             },
136             { // currency
137                 L"\xA4", L"", L"\xA4 ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
138             },
139             { // percent
140                 L"", L"", L"%", L"% ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
141             }
142         },
143         { // negative
144             { // number
145                 L"(", L"-", L"- ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
146             },
147             { //currency
148                 L"(\xA4", L"-\xA4", L"\xA4-", L"\xA4", L"(", L"-", L"", L"", L"-", L"-\xA4 ", L"", L"\xA4 ", L"\xA4 -", L"", L"(\xA4 ", L"("
149             },
150             { // percent
151                 L"-", L"-", L"-%", L"%-", L"%", L"", L"", L"-% ", L"", L"% ", L"% -", L"", L"", L"", L"", L"",
152             }
153         }
154     },
155     { // suffix
156         { //positive
157             { // number
158                 L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L""
159             },
160             { // currency
161                 L"", L"\xA4 ", L"", L" \xA4", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
162             },
163             { // percent
164                 L" %", L"%", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
165             }
166         },
167         { // negative
168             { // number
169                 L")", L"", L" ", L"-", L" -", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"",
170             },
171             { //currency
172                 L")", L"", L"", L"-", L"\xA4)", L"\xA4", L"-\xA4", L"\xA4-", L" \xA4", L"", L" \xA4-", L"-", L"", L"- \xA4", L")", L" \xA4)"
173             },
174             { // percent
175                 L" %", L"%", L"", L"", L"-", L"-%", L"%-", L"", L" %-", L"-", L"", L"- %", L"", L"", L"", L"",
176             }
177         }
178     }
179 };
180 
181 /*
182  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
183  * Method:    initialize
184  * Signature: ()Z
185  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_initialize(JNIEnv * env,jclass cls)186 JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_initialize
187   (JNIEnv *env, jclass cls) {
188     if (!initialized) {
189         pGetLocaleInfoEx = (PGLIE)GetProcAddress(
190             GetModuleHandle("kernel32.dll"),
191             "GetLocaleInfoEx");
192         pGetCalendarInfoEx = (PGCIE)GetProcAddress(
193             GetModuleHandle("kernel32.dll"),
194             "GetCalendarInfoEx");
195         pEnumCalendarInfoExEx = (PECIEE)GetProcAddress(
196             GetModuleHandle("kernel32.dll"),
197             "EnumCalendarInfoExEx");
198         initialized =TRUE;
199     }
200 
201     return pGetLocaleInfoEx != NULL &&
202            pGetCalendarInfoEx != NULL &&
203            pEnumCalendarInfoExEx != NULL;
204 }
205 
206 /*
207  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
208  * Method:    getDefaultLocale
209  * Signature: (I)Ljava/lang/String;
210  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDefaultLocale(JNIEnv * env,jclass cls,jint cat)211 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDefaultLocale
212   (JNIEnv *env, jclass cls, jint cat) {
213     char * localeString = NULL;
214     LANGID langid;
215     jstring ret;
216 
217     switch (cat) {
218         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_DISPLAY:
219             langid = LANGIDFROMLCID(GetUserDefaultUILanguage());
220             break;
221         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CAT_FORMAT:
222         default:
223             langid = LANGIDFROMLCID(GetUserDefaultLCID());
224             break;
225     }
226 
227     localeString = (char *)getJavaIDFromLangID(langid);
228     if (localeString != NULL) {
229         ret = (*env)->NewStringUTF(env, localeString);
230         free(localeString);
231     } else {
232         JNU_ThrowOutOfMemoryError(env, "memory allocation error");
233         ret = NULL;
234     }
235     return ret;
236 }
237 
238 /*
239  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
240  * Method:    getDateTimePattern
241  * Signature: (IILjava/lang/String;)Ljava/lang/String;
242  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePattern(JNIEnv * env,jclass cls,jint dateStyle,jint timeStyle,jstring jlangtag)243 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePattern
244   (JNIEnv *env, jclass cls, jint dateStyle, jint timeStyle, jstring jlangtag) {
245     WCHAR pattern[BUFLEN];
246     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
247     CHECK_NULL_RETURN(langtag, NULL);
248 
249     pattern[0] = L'\0';
250 
251     if (dateStyle == 0 || dateStyle == 1) {
252         getLocaleInfoWrapper(langtag, LOCALE_SLONGDATE, pattern, BUFLEN);
253     } else if (dateStyle == 2 || dateStyle == 3) {
254         getLocaleInfoWrapper(langtag, LOCALE_SSHORTDATE, pattern, BUFLEN);
255     }
256 
257     if (timeStyle == 0 || timeStyle == 1) {
258         getLocaleInfoWrapper(langtag, LOCALE_STIMEFORMAT, pattern, BUFLEN);
259     } else if (timeStyle == 2 || timeStyle == 3) {
260         getLocaleInfoWrapper(langtag, LOCALE_SSHORTTIME, pattern, BUFLEN);
261     }
262 
263     (*env)->ReleaseStringChars(env, jlangtag, langtag);
264 
265     return (*env)->NewString(env, pattern, (jsize)wcslen(pattern));
266 }
267 
268 /*
269  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
270  * Method:    getCalendarID
271  * Signature: (Ljava/lang/String;)I
272  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarID(JNIEnv * env,jclass cls,jstring jlangtag)273 JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarID
274   (JNIEnv *env, jclass cls, jstring jlangtag) {
275     const jchar *langtag;
276     jint ret;
277     langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
278     CHECK_NULL_RETURN(langtag, 0);
279     ret = getCalendarID(langtag);
280     (*env)->ReleaseStringChars(env, jlangtag, langtag);
281     return ret;
282 }
283 
284 /*
285  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
286  * Method:    getAmPmStrings
287  * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
288  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings(JNIEnv * env,jclass cls,jstring jlangtag,jobjectArray ampms)289 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings
290   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray ampms) {
291     replaceCalendarArrayElems(env, jlangtag, -1, ampms, ampmType,
292                           0, AMPMTYPES, 0, FALSE);
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  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras(JNIEnv * env,jclass cls,jstring jlangtag,jobjectArray eras)301 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras
302   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray eras) {
303     return getErasImpl(env, jlangtag, -1, 0, eras);
304 }
305 
306 /*
307  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
308  * Method:    getMonths
309  * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
310  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonths(JNIEnv * env,jclass cls,jstring jlangtag,jobjectArray months)311 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonths
312   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray months) {
313     replaceCalendarArrayElems(env, jlangtag, -1, months, monthsType,
314                       0, MONTHTYPES, 0, TRUE);
315     return months;
316 }
317 
318 /*
319  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
320  * Method:    getShortMonths
321  * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
322  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortMonths(JNIEnv * env,jclass cls,jstring jlangtag,jobjectArray smonths)323 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortMonths
324   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray smonths) {
325     replaceCalendarArrayElems(env, jlangtag, -1, smonths, sMonthsType,
326                       0, MONTHTYPES, 0, TRUE);
327     return smonths;
328 }
329 
330 /*
331  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
332  * Method:    getWeekdays
333  * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
334  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays(JNIEnv * env,jclass cls,jstring jlangtag,jobjectArray wdays)335 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays
336   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {
337     replaceCalendarArrayElems(env, jlangtag, -1, wdays, wDaysType,
338                       1, DOWTYPES, 0, TRUE);
339     return wdays;
340 }
341 
342 /*
343  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
344  * Method:    getShortWeekdays
345  * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
346  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortWeekdays(JNIEnv * env,jclass cls,jstring jlangtag,jobjectArray swdays)347 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getShortWeekdays
348   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray swdays) {
349     replaceCalendarArrayElems(env, jlangtag, -1, swdays, sWDaysType,
350                       1, DOWTYPES, 0, TRUE);
351     return swdays;
352 }
353 
354 /*
355  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
356  * Method:    getNumberPattern
357  * Signature: (ILjava/lang/String;)Ljava/lang/String;
358  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPattern(JNIEnv * env,jclass cls,jint numberStyle,jstring jlangtag)359 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPattern
360   (JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) {
361     const jchar *langtag;
362     jstring ret;
363     WCHAR * pattern;
364 
365     langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
366     CHECK_NULL_RETURN(langtag, NULL);
367     pattern = getNumberPattern(langtag, numberStyle);
368     CHECK_NULL_RETURN(pattern, NULL);
369 
370     (*env)->ReleaseStringChars(env, jlangtag, langtag);
371     ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern));
372     free(pattern);
373 
374     return ret;
375 }
376 
377 /*
378  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
379  * Method:    isNativeDigit
380  * Signature: (Ljava/lang/String;)Z
381  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_isNativeDigit(JNIEnv * env,jclass cls,jstring jlangtag)382 JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_isNativeDigit
383   (JNIEnv *env, jclass cls, jstring jlangtag) {
384     DWORD num;
385     int got;
386     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
387     CHECK_NULL_RETURN(langtag, JNI_FALSE);
388     got = getLocaleInfoWrapper(langtag,
389         LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
390         (LPWSTR)&num, sizeof(num));
391     (*env)->ReleaseStringChars(env, jlangtag, langtag);
392 
393     return got && num == 2; // 2: native digit substitution
394 }
395 
396 /*
397  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
398  * Method:    getCurrencySymbol
399  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
400  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol(JNIEnv * env,jclass cls,jstring jlangtag,jstring currencySymbol)401 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCurrencySymbol
402   (JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) {
403     WCHAR buf[BUFLEN];
404     int got;
405     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
406     CHECK_NULL_RETURN(langtag, currencySymbol);
407     got = getLocaleInfoWrapper(langtag, LOCALE_SCURRENCY, buf, BUFLEN);
408     (*env)->ReleaseStringChars(env, jlangtag, langtag);
409 
410     if (got) {
411         return (*env)->NewString(env, buf, (jsize)wcslen(buf));
412     } else {
413         return currencySymbol;
414     }
415 }
416 
417 /*
418  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
419  * Method:    getDecimalSeparator
420  * Signature: (Ljava/lang/String;C)C
421  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator(JNIEnv * env,jclass cls,jstring jlangtag,jchar decimalSeparator)422 JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDecimalSeparator
423   (JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) {
424     WCHAR buf[BUFLEN];
425     int got;
426     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
427     CHECK_NULL_RETURN(langtag, decimalSeparator);
428     got = getLocaleInfoWrapper(langtag, LOCALE_SDECIMAL, buf, BUFLEN);
429     (*env)->ReleaseStringChars(env, jlangtag, langtag);
430 
431     if (got) {
432         return buf[0];
433     } else {
434         return decimalSeparator;
435     }
436 }
437 
438 /*
439  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
440  * Method:    getGroupingSeparator
441  * Signature: (Ljava/lang/String;C)C
442  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator(JNIEnv * env,jclass cls,jstring jlangtag,jchar groupingSeparator)443 JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getGroupingSeparator
444   (JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) {
445     WCHAR buf[BUFLEN];
446     int got;
447     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
448     CHECK_NULL_RETURN(langtag, groupingSeparator);
449     got = getLocaleInfoWrapper(langtag, LOCALE_STHOUSAND, buf, BUFLEN);
450     (*env)->ReleaseStringChars(env, jlangtag, langtag);
451 
452     if (got) {
453         return buf[0];
454     } else {
455         return groupingSeparator;
456     }
457 }
458 
459 /*
460  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
461  * Method:    getInfinity
462  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
463  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity(JNIEnv * env,jclass cls,jstring jlangtag,jstring infinity)464 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInfinity
465   (JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) {
466     WCHAR buf[BUFLEN];
467     int got;
468     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
469     CHECK_NULL_RETURN(langtag, infinity);
470     got = getLocaleInfoWrapper(langtag, LOCALE_SPOSINFINITY, buf, BUFLEN);
471     (*env)->ReleaseStringChars(env, jlangtag, langtag);
472 
473     if (got) {
474         return (*env)->NewString(env, buf, (jsize)wcslen(buf));
475     } else {
476         return infinity;
477     }
478 }
479 
480 /*
481  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
482  * Method:    getInternationalCurrencySymbol
483  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
484  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol(JNIEnv * env,jclass cls,jstring jlangtag,jstring internationalCurrencySymbol)485 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getInternationalCurrencySymbol
486   (JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) {
487     WCHAR buf[BUFLEN];
488     int got;
489     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
490     CHECK_NULL_RETURN(langtag, internationalCurrencySymbol);
491     got = getLocaleInfoWrapper(langtag, LOCALE_SINTLSYMBOL, buf, BUFLEN);
492     (*env)->ReleaseStringChars(env, jlangtag, langtag);
493 
494     if (got) {
495         return (*env)->NewString(env, buf, (jsize)wcslen(buf));
496     } else {
497         return internationalCurrencySymbol;
498     }
499 }
500 
501 /*
502  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
503  * Method:    getMinusSign
504  * Signature: (Ljava/lang/String;C)C
505  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign(JNIEnv * env,jclass cls,jstring jlangtag,jchar minusSign)506 JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMinusSign
507   (JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) {
508     WCHAR buf[BUFLEN];
509     int got;
510     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
511     CHECK_NULL_RETURN(langtag, minusSign);
512     got = getLocaleInfoWrapper(langtag, LOCALE_SNEGATIVESIGN, buf, BUFLEN);
513     (*env)->ReleaseStringChars(env, jlangtag, langtag);
514 
515     if (got) {
516         return buf[0];
517     } else {
518         return minusSign;
519     }
520 }
521 
522 /*
523  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
524  * Method:    getMonetaryDecimalSeparator
525  * Signature: (Ljava/lang/String;C)C
526  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator(JNIEnv * env,jclass cls,jstring jlangtag,jchar monetaryDecimalSeparator)527 JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getMonetaryDecimalSeparator
528   (JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) {
529     WCHAR buf[BUFLEN];
530     int got;
531     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
532     CHECK_NULL_RETURN(langtag, monetaryDecimalSeparator);
533     got = getLocaleInfoWrapper(langtag, LOCALE_SMONDECIMALSEP, buf, BUFLEN);
534     (*env)->ReleaseStringChars(env, jlangtag, langtag);
535 
536     if (got) {
537         return buf[0];
538     } else {
539         return monetaryDecimalSeparator;
540     }
541 }
542 
543 /*
544  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
545  * Method:    getNaN
546  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
547  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN(JNIEnv * env,jclass cls,jstring jlangtag,jstring nan)548 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNaN
549   (JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) {
550     WCHAR buf[BUFLEN];
551     int got;
552     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
553     CHECK_NULL_RETURN(langtag, nan);
554     got = getLocaleInfoWrapper(langtag, LOCALE_SNAN, buf, BUFLEN);
555     (*env)->ReleaseStringChars(env, jlangtag, langtag);
556 
557     if (got) {
558         return (*env)->NewString(env, buf, (jsize)wcslen(buf));
559     } else {
560         return nan;
561     }
562 }
563 
564 /*
565  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
566  * Method:    getPercent
567  * Signature: (Ljava/lang/String;C)C
568  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent(JNIEnv * env,jclass cls,jstring jlangtag,jchar percent)569 JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPercent
570   (JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) {
571     WCHAR buf[BUFLEN];
572     int got;
573     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
574     CHECK_NULL_RETURN(langtag, percent);
575     got = getLocaleInfoWrapper(langtag, LOCALE_SPERCENT, buf, BUFLEN);
576     (*env)->ReleaseStringChars(env, jlangtag, langtag);
577 
578     if (got) {
579         return buf[0];
580     } else {
581         return percent;
582     }
583 }
584 
585 /*
586  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
587  * Method:    getPerMill
588  * Signature: (Ljava/lang/String;C)C
589  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill(JNIEnv * env,jclass cls,jstring jlangtag,jchar perMill)590 JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getPerMill
591   (JNIEnv *env, jclass cls, jstring jlangtag, jchar perMill) {
592     WCHAR buf[BUFLEN];
593     const jchar *langtag;
594     int got;
595     langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
596     CHECK_NULL_RETURN(langtag, perMill);
597     got = getLocaleInfoWrapper(langtag, LOCALE_SPERMILLE, buf, BUFLEN);
598 
599     (*env)->ReleaseStringChars(env, jlangtag, langtag);
600 
601     if (got) {
602         return buf[0];
603     } else {
604         return perMill;
605     }
606 }
607 
608 /*
609  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
610  * Method:    getZeroDigit
611  * Signature: (Ljava/lang/String;C)C
612  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit(JNIEnv * env,jclass cls,jstring jlangtag,jchar zeroDigit)613 JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getZeroDigit
614   (JNIEnv *env, jclass cls, jstring jlangtag, jchar zeroDigit) {
615     WCHAR buf[BUFLEN];
616     const jchar *langtag;
617     int got;
618     langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
619     CHECK_NULL_RETURN(langtag, zeroDigit);
620     got = getLocaleInfoWrapper(langtag, LOCALE_SNATIVEDIGITS, buf, BUFLEN);
621 
622     (*env)->ReleaseStringChars(env, jlangtag, langtag);
623 
624     if (got) {
625         return buf[0];
626     } else {
627         return zeroDigit;
628     }
629 }
630 
631 /*
632  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
633  * Method:    getCalendarDataValue
634  * Signature: (Ljava/lang/String;I)I
635  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDataValue(JNIEnv * env,jclass cls,jstring jlangtag,jint type)636 JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDataValue
637   (JNIEnv *env, jclass cls, jstring jlangtag, jint type) {
638     DWORD num;
639     const jchar *langtag;
640     int got = 0;
641 
642     langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
643     CHECK_NULL_RETURN(langtag, -1);
644     switch (type) {
645     case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:
646         got = getLocaleInfoWrapper(langtag,
647             LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER,
648             (LPWSTR)&num, sizeof(num));
649         break;
650     }
651 
652     (*env)->ReleaseStringChars(env, jlangtag, langtag);
653 
654     if (got) {
655         return num;
656     } else {
657         return -1;
658     }
659 }
660 
661 /*
662  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
663  * Method:    getCalendarDisplayStrings
664  * Signature: (Ljava/lang/String;III)[Ljava/lang/String;
665  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDisplayStrings(JNIEnv * env,jclass cls,jstring jlangtag,jint calid,jint field,jint style)666 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDisplayStrings
667   (JNIEnv *env, jclass cls, jstring jlangtag, jint calid, jint field, jint style) {
668     jobjectArray ret = NULL;
669     CALTYPE * pCalType = NULL;
670 
671     switch (field) {
672     case CALENDAR_FIELD_ERA:
673         return getErasImpl(env, jlangtag, calid, style, NULL);
674 
675     case CALENDAR_FIELD_AM_PM:
676         ret = (*env)->NewObjectArray(env, AMPMTYPES,
677                 (*env)->FindClass(env, "java/lang/String"), NULL);
678         if (ret != NULL) {
679             replaceCalendarArrayElems(env, jlangtag, calid, ret, ampmType,
680                           0, AMPMTYPES, style, FALSE);
681         }
682         return ret;
683 
684     case CALENDAR_FIELD_DAY_OF_WEEK:
685         ret = (*env)->NewObjectArray(env, DOWTYPES,
686                 (*env)->FindClass(env, "java/lang/String"), NULL);
687         if (ret != NULL) {
688             if (style & CALENDAR_STYLE_SHORT_MASK) {
689                 pCalType = sWDaysType;
690             } else {
691                 pCalType = wDaysType;
692             }
693 
694             replaceCalendarArrayElems(env, jlangtag, calid, ret, pCalType,
695                           0, DOWTYPES, style, TRUE);
696         }
697         return ret;
698 
699     case CALENDAR_FIELD_MONTH:
700         ret = (*env)->NewObjectArray(env, MONTHTYPES,
701                 (*env)->FindClass(env, "java/lang/String"), NULL);
702         if (ret != NULL) {
703             if (style & CALENDAR_STYLE_SHORT_MASK) {
704                 pCalType = sMonthsType;
705             } else {
706                 pCalType = monthsType;
707             }
708 
709             replaceCalendarArrayElems(env, jlangtag, calid, ret, pCalType,
710                           0, MONTHTYPES, style, TRUE);
711         }
712         return ret;
713 
714     default:
715         // not supported
716         return NULL;
717     }
718 }
719 
720 /*
721  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
722  * Method:    getDisplayString
723  * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
724  */
Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString(JNIEnv * env,jclass cls,jstring jlangtag,jint type,jstring jvalue)725 JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString
726   (JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring jvalue) {
727     LCTYPE lcType;
728     jstring jStr;
729     const jchar * pjChar;
730     WCHAR buf[BUFLEN];
731     int got = 0;
732 
733     switch (type) {
734         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_NAME:
735             lcType = LOCALE_SNATIVECURRNAME;
736             jStr = jlangtag;
737             break;
738         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:
739             lcType = LOCALE_SCURRENCY;
740             jStr = jlangtag;
741             break;
742         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:
743             lcType = LOCALE_SLOCALIZEDLANGUAGENAME;
744             jStr = jvalue;
745             break;
746         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:
747             lcType = LOCALE_SLOCALIZEDCOUNTRYNAME;
748             jStr = jvalue;
749             break;
750         default:
751             return NULL;
752     }
753 
754     pjChar = (*env)->GetStringChars(env, jStr, JNI_FALSE);
755     CHECK_NULL_RETURN(pjChar, NULL);
756     got = getLocaleInfoWrapper(pjChar, lcType, buf, BUFLEN);
757     (*env)->ReleaseStringChars(env, jStr, pjChar);
758 
759     if (got) {
760         return (*env)->NewString(env, buf, (jsize)wcslen(buf));
761     } else {
762         return NULL;
763     }
764 }
765 
getLocaleInfoWrapper(const jchar * langtag,LCTYPE type,LPWSTR data,int buflen)766 int getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen) {
767     if (pGetLocaleInfoEx) {
768         if (wcscmp(L"und", (LPWSTR)langtag) == 0) {
769             // defaults to "en"
770             return pGetLocaleInfoEx(L"en", type, data, buflen);
771         } else {
772             return pGetLocaleInfoEx((LPWSTR)langtag, type, data, buflen);
773         }
774     } else {
775         // If we ever wanted to support WinXP, we will need extra module from
776         // MS...
777         // return GetLocaleInfo(DownlevelLocaleNameToLCID(langtag, 0), type, data, buflen);
778         return 0;
779     }
780 }
781 
getCalendarInfoWrapper(const jchar * langtag,CALID id,LPCWSTR reserved,CALTYPE type,LPWSTR data,int buflen,LPDWORD val)782 int getCalendarInfoWrapper(const jchar *langtag, CALID id, LPCWSTR reserved, CALTYPE type, LPWSTR data, int buflen, LPDWORD val) {
783     if (pGetCalendarInfoEx) {
784         if (wcscmp(L"und", (LPWSTR)langtag) == 0) {
785             // defaults to "en"
786             return pGetCalendarInfoEx(L"en", id, reserved, type, data, buflen, val);
787         } else {
788             return pGetCalendarInfoEx((LPWSTR)langtag, id, reserved, type, data, buflen, val);
789         }
790     } else {
791         // If we ever wanted to support WinXP, we will need extra module from
792         // MS...
793         // return GetCalendarInfo(DownlevelLocaleNameToLCID(langtag, 0), ...);
794         return 0;
795     }
796 }
797 
getCalendarID(const jchar * langtag)798 jint getCalendarID(const jchar *langtag) {
799     DWORD type = -1;
800     int got = getLocaleInfoWrapper(langtag,
801         LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER,
802         (LPWSTR)&type, sizeof(type));
803 
804     if (got) {
805         switch (type) {
806             case CAL_GREGORIAN:
807             case CAL_GREGORIAN_US:
808             case CAL_JAPAN:
809             case CAL_TAIWAN:
810             case CAL_HIJRI:
811             case CAL_THAI:
812             case CAL_GREGORIAN_ME_FRENCH:
813             case CAL_GREGORIAN_ARABIC:
814             case CAL_GREGORIAN_XLIT_ENGLISH:
815             case CAL_GREGORIAN_XLIT_FRENCH:
816             case CAL_UMALQURA:
817                 break;
818 
819             default:
820                 // non-supported calendars return -1
821                 type = -1;
822                 break;
823         }
824     }
825 
826     return type;
827 }
828 
replaceCalendarArrayElems(JNIEnv * env,jstring jlangtag,jint calid,jobjectArray jarray,DWORD * pTypes,int offset,int length,int style,BOOL bCal)829 void replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jint calid, jobjectArray jarray, DWORD* pTypes, int offset, int length, int style, BOOL bCal) {
830     WCHAR name[BUFLEN];
831     const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
832     jstring tmp_string;
833     CALTYPE isGenitive;
834 
835     CHECK_NULL(langtag);
836 
837     if (calid < 0) {
838         calid = getCalendarID(langtag);
839     }
840 
841     if (calid != -1) {
842         int i;
843 
844         if (!(style & CALENDAR_STYLE_STANDALONE_MASK)) {
845             isGenitive = CAL_RETURN_GENITIVE_NAMES;
846         }
847 
848         for (i = 0; i < length; i++) {
849             if (bCal && getCalendarInfoWrapper(langtag, calid, NULL,
850                             pTypes[i] | isGenitive, name, BUFLEN, NULL) != 0 ||
851                 getLocaleInfoWrapper(langtag, pTypes[i] | isGenitive, name, BUFLEN) != 0) {
852                 tmp_string = (*env)->NewString(env, name, (jsize)wcslen(name));
853                 if (tmp_string != NULL) {
854                     (*env)->SetObjectArrayElement(env, jarray, i + offset, tmp_string);
855                 }
856             }
857         }
858     }
859 
860     (*env)->ReleaseStringChars(env, jlangtag, langtag);
861 }
862 
getNumberPattern(const jchar * langtag,const jint numberStyle)863 WCHAR * getNumberPattern(const jchar * langtag, const jint numberStyle) {
864     WCHAR ret[BUFLEN];
865     WCHAR number[BUFLEN];
866     WCHAR fix[BUFLEN];
867 
868     getFixPart(langtag, numberStyle, TRUE, TRUE, ret); // "+"
869     getNumberPart(langtag, numberStyle, number);
870     wcscat_s(ret, BUFLEN-wcslen(ret), number);      // "+12.34"
871     getFixPart(langtag, numberStyle, TRUE, FALSE, fix);
872     wcscat_s(ret, BUFLEN-wcslen(ret), fix);         // "+12.34$"
873     wcscat_s(ret, BUFLEN-wcslen(ret), L";");        // "+12.34$;"
874     getFixPart(langtag, numberStyle, FALSE, TRUE, fix);
875     wcscat_s(ret, BUFLEN-wcslen(ret), fix);         // "+12.34$;("
876     wcscat_s(ret, BUFLEN-wcslen(ret), number);      // "+12.34$;(12.34"
877     getFixPart(langtag, numberStyle, FALSE, FALSE, fix);
878     wcscat_s(ret, BUFLEN-wcslen(ret), fix);         // "+12.34$;(12.34$)"
879 
880     return _wcsdup(ret);
881 }
882 
getNumberPart(const jchar * langtag,const jint numberStyle,WCHAR * number)883 void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number) {
884     DWORD digits = 0;
885     DWORD leadingZero = 0;
886     WCHAR grouping[BUFLEN];
887     int groupingLen;
888     WCHAR fractionPattern[BUFLEN];
889     WCHAR * integerPattern = number;
890     WCHAR * pDest;
891 
892     // Get info from Windows
893     switch (numberStyle) {
894         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:
895             getLocaleInfoWrapper(langtag,
896                 LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER,
897                 (LPWSTR)&digits, sizeof(digits));
898             break;
899 
900         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:
901             break;
902 
903         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:
904         case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:
905         default:
906             getLocaleInfoWrapper(langtag,
907                 LOCALE_IDIGITS | LOCALE_RETURN_NUMBER,
908                 (LPWSTR)&digits, sizeof(digits));
909             break;
910     }
911 
912     getLocaleInfoWrapper(langtag,
913         LOCALE_ILZERO | LOCALE_RETURN_NUMBER,
914         (LPWSTR)&leadingZero, sizeof(leadingZero));
915     groupingLen = getLocaleInfoWrapper(langtag, LOCALE_SGROUPING, grouping, BUFLEN);
916 
917     // fraction pattern
918     if (digits > 0) {
919         int i;
920         for(i = digits;  i > 0; i--) {
921             fractionPattern[i] = L'#';
922         }
923         fractionPattern[0] = L'.';
924         fractionPattern[digits+1] = L'\0';
925     } else {
926         fractionPattern[0] = L'\0';
927     }
928 
929     // integer pattern
930     pDest = integerPattern;
931     if (groupingLen > 0) {
932         int cur = groupingLen - 1;// subtracting null terminator
933         while (--cur >= 0) {
934             int repnum;
935 
936             if (grouping[cur] == L';') {
937                 continue;
938             }
939 
940             repnum = grouping[cur] - 0x30;
941             if (repnum > 0) {
942                 *pDest++ = L'#';
943                 *pDest++ = L',';
944                 while(--repnum > 0) {
945                     *pDest++ = L'#';
946                 }
947             }
948         }
949     }
950 
951     if (leadingZero != 0) {
952         *pDest++ = L'0';
953     } else {
954         *pDest++ = L'#';
955     }
956     *pDest = L'\0';
957 
958     wcscat_s(integerPattern, BUFLEN, fractionPattern);
959 }
960 
getFixPart(const jchar * langtag,const jint numberStyle,BOOL positive,BOOL prefix,WCHAR * ret)961 void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret) {
962     DWORD pattern = 0;
963     int style = numberStyle;
964     int got = 0;
965 
966     if (positive) {
967         if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {
968             got = getLocaleInfoWrapper(langtag,
969                 LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER,
970                 (LPWSTR)&pattern, sizeof(pattern));
971         } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {
972             got = getLocaleInfoWrapper(langtag,
973                 LOCALE_IPOSITIVEPERCENT | LOCALE_RETURN_NUMBER,
974                 (LPWSTR)&pattern, sizeof(pattern));
975         }
976     } else {
977         if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {
978             got = getLocaleInfoWrapper(langtag,
979                 LOCALE_INEGCURR | LOCALE_RETURN_NUMBER,
980                 (LPWSTR)&pattern, sizeof(pattern));
981         } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {
982             got = getLocaleInfoWrapper(langtag,
983                 LOCALE_INEGATIVEPERCENT | LOCALE_RETURN_NUMBER,
984                 (LPWSTR)&pattern, sizeof(pattern));
985         } else {
986             got = getLocaleInfoWrapper(langtag,
987                 LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER,
988                 (LPWSTR)&pattern, sizeof(pattern));
989         }
990     }
991 
992     if (numberStyle == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER) {
993         style = sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER;
994     }
995 
996     wcscpy(ret, fixes[!prefix][!positive][style][pattern]);
997 }
998 
enumCalendarInfoWrapper(const jchar * langtag,CALID calid,CALTYPE type,LPWSTR buf,int buflen)999 int enumCalendarInfoWrapper(const jchar *langtag, CALID calid, CALTYPE type, LPWSTR buf, int buflen) {
1000     if (pEnumCalendarInfoExEx) {
1001         if (wcscmp(L"und", (LPWSTR)langtag) == 0) {
1002             // defaults to "en"
1003             return pEnumCalendarInfoExEx(&EnumCalendarInfoProc, L"en",
1004                 calid, NULL, type, (LPARAM)buf);
1005         } else {
1006             return pEnumCalendarInfoExEx(&EnumCalendarInfoProc, langtag,
1007                 calid, NULL, type, (LPARAM)buf);
1008         }
1009     } else {
1010         return 0;
1011     }
1012 }
1013 
EnumCalendarInfoProc(LPWSTR lpCalInfoStr,CALID calid,LPWSTR lpReserved,LPARAM lParam)1014 BOOL CALLBACK EnumCalendarInfoProc(LPWSTR lpCalInfoStr, CALID calid, LPWSTR lpReserved, LPARAM lParam) {
1015     wcscat_s((LPWSTR)lParam, BUFLEN, lpCalInfoStr);
1016     wcscat_s((LPWSTR)lParam, BUFLEN, L",");
1017     return TRUE;
1018 }
1019 
getErasImpl(JNIEnv * env,jstring jlangtag,jint calid,jint style,jobjectArray eras)1020 jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint calid, jint style, jobjectArray eras) {
1021     const jchar * langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
1022     WCHAR buf[BUFLEN];
1023     jobjectArray ret = eras;
1024     CALTYPE type;
1025 
1026     CHECK_NULL_RETURN(langtag, ret);
1027 
1028     buf[0] = '\0';
1029     if (style & CALENDAR_STYLE_SHORT_MASK) {
1030         type = CAL_SABBREVERASTRING;
1031     } else {
1032         type = CAL_SERASTRING;
1033     }
1034 
1035     if (calid < 0) {
1036         calid = getCalendarID(langtag);
1037     }
1038 
1039     if (calid != -1 && enumCalendarInfoWrapper(langtag, calid, type, buf, BUFLEN)) {
1040         // format in buf: "era0,era1,era2," where era0 is the current one
1041         int eraCount;
1042         LPWSTR current;
1043         jsize array_length;
1044 
1045         for(eraCount = 0, current = buf; *current != '\0'; current++) {
1046             if (*current == L',') {
1047                 eraCount ++;
1048             }
1049         }
1050 
1051         if (eras != NULL) {
1052             array_length = (*env)->GetArrayLength(env, eras);
1053         } else {
1054             // +1 for the "before" era, e.g., BC, which Windows does not return.
1055             array_length = (jsize)eraCount + 1;
1056             ret = (*env)->NewObjectArray(env, array_length,
1057                 (*env)->FindClass(env, "java/lang/String"), NULL);
1058         }
1059 
1060         if (ret != NULL) {
1061             int eraIndex;
1062             LPWSTR era;
1063 
1064             for(eraIndex = 0, era = current = buf; eraIndex < eraCount; era = current, eraIndex++) {
1065                 while (*current != L',') {
1066                     current++;
1067                 }
1068                 *current++ = '\0';
1069 
1070                 if (eraCount - eraIndex < array_length &&
1071                     *era != '\0') {
1072                     (*env)->SetObjectArrayElement(env, ret,
1073                         (jsize)(eraCount - eraIndex),
1074                         (*env)->NewString(env, era, (jsize)wcslen(era)));
1075                 }
1076             }
1077 
1078             // Hack for the Japanese Imperial Calendar to insert Gregorian era for
1079             // "Before Meiji"
1080             if (calid == CAL_JAPAN) {
1081                 buf[0] = '\0';
1082                 if (enumCalendarInfoWrapper(langtag, CAL_GREGORIAN, type, buf, BUFLEN)) {
1083                     jsize len = (jsize)wcslen(buf);
1084                     buf[--len] = '\0'; // remove the last ','
1085                     (*env)->SetObjectArrayElement(env, ret, 0, (*env)->NewString(env, buf, len));
1086                 }
1087             }
1088         }
1089     }
1090 
1091     (*env)->ReleaseStringChars(env, jlangtag, langtag);
1092     return ret;
1093 }
1094