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