blob: ec0561c04e11db95e7ea9045306de8defe6877e8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#include <windows.h>
27#include <shlobj.h>
28#include <objidl.h>
29#include <locale.h>
30#include <sys/types.h>
31#include <sys/timeb.h>
32#include <tchar.h>
33
34#include "locale_str.h"
35#include "java_props.h"
36
37#ifndef VER_PLATFORM_WIN32_WINDOWS
38#define VER_PLATFORM_WIN32_WINDOWS 1
39#endif
40
41#define SHELL_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
42
43/* Encodings for Windows language groups. According to
44 www.microsoft.com/globaldev/faqs/locales.asp,
45 some locales do not have codepages, and are
46 supported in Windows 2000/XP solely through Unicode.
47 In this case, we use utf-8 encoding */
48
49static char *encoding_names[] = {
50 "Cp1250", /* 0:Latin 2 */
51 "Cp1251", /* 1:Cyrillic */
52 "Cp1252", /* 2:Latin 1 */
53 "Cp1253", /* 3:Greek */
54 "Cp1254", /* 4:Latin 5 */
55 "Cp1255", /* 5:Hebrew */
56 "Cp1256", /* 6:Arabic */
57 "Cp1257", /* 7:Baltic */
58 "Cp1258", /* 8:Viet Nam */
59 "MS874", /* 9:Thai */
60 "MS932", /* 10:Japanese */
61 "GBK", /* 11:PRC GBK */
62 "MS949", /* 12:Korean Extended Wansung */
63 "MS950", /* 13:Chinese (Taiwan, Hongkong, Macau) */
64 "utf-8", /* 14:Unicode */
65 "MS1361", /* 15:Korean Johab */
66};
67
68/*
69 * List mapping from LanguageID to Java locale IDs.
70 * The entries in this list should not be construed to suggest we actually have
71 * full locale-data and other support for all of these locales; these are
72 * merely all of the Windows locales for which we could construct an accurate
73 * locale ID. The data is based on the web page "Windows XP/Server 2003 -
74 * List of Locale IDs, Input Locale, and Language Collection"
75 * (http://www.microsoft.com/globaldev/reference/winxp/xp-lcid.mspx)
76 *
77 * Some of the language IDs below are not yet used by Windows, but were
78 * defined by Microsoft for other products, such as Office XP. They may
79 * become Windows language IDs in the future.
80 *
81 */
82typedef struct LANGIDtoLocale {
83 WORD langID;
84 WORD encoding;
85 char* javaID;
86} LANGIDtoLocale;
87
88static LANGIDtoLocale langIDMap[] = {
89 /* fallback locales to use when the country code doesn't match anything we have */
90 0x01, 6, "ar",
91 0x02, 1, "bg",
92 0x03, 2, "ca",
93 0x04, 11, "zh",
94 0x05, 0, "cs",
95 0x06, 2, "da",
96 0x07, 2, "de",
97 0x08, 3, "el",
98 0x09, 2, "en",
99 0x0a, 2, "es",
100 0x0b, 2, "fi",
101 0x0c, 2, "fr",
102 0x0d, 5, "iw",
103 0x0e, 0, "hu",
104 0x0f, 2, "is",
105 0x10, 2, "it",
106 0x11, 10, "ja",
107 0x12, 12, "ko",
108 0x13, 2, "nl",
109 0x14, 2, "no",
110 0x15, 0, "pl",
111 0x16, 2, "pt",
112 0x17, 2, "rm",
113 0x18, 0, "ro",
114 0x19, 1, "ru",
115 0x1a, 0, "sr",
116 0x1b, 0, "sk",
117 0x1c, 0, "sq",
118 0x1d, 2, "sv",
119 0x1e, 9, "th",
120 0x1f, 4, "tr",
121 0x20, 2, "ur",
122 0x21, 2, "in",
123 0x22, 1, "uk",
124 0x23, 1, "be",
125 0x24, 0, "sl",
126 0x25, 7, "et",
127 0x26, 7, "lv",
128 0x27, 7, "lt",
129 0x28, 1, "tg",
130 0x29, 6, "fa",
131 0x2a, 8, "vi",
132 0x2b, 14, "hy",
133 0x2c, 4, "az",
134 0x2d, 2, "eu",
135/* 0x2e, 2, "??", no ISO-639 abbreviation for Sorbian */
136 0x2f, 1, "mk",
137 0x31, 2, "ts",
138 0x32, 2, "tn",
139 0x34, 2, "xh",
140 0x35, 2, "zu",
141 0x36, 2, "af",
142 0x37, 14, "ka",
143 0x38, 2, "fo",
144 0x39, 14, "hi",
145 0x3a, 14, "mt",
146 0x3b, 2, "se",
147 0x3c, 2, "gd",
148 0x3d, 2, "yi",
149 0x3e, 2, "ms",
150 0x3f, 1, "kk",
151 0x40, 1, "ky",
152 0x41, 2, "sw",
153 0x42, 0, "tk",
154 0x43, 1, "uz",
155 0x44, 1, "tt",
156 0x45, 14, "bn",
157 0x46, 14, "pa",
158 0x47, 14, "gu",
159 0x48, 14, "or",
160 0x49, 14, "ta",
161 0x4a, 14, "te",
162 0x4b, 14, "kn",
163 0x4c, 14, "ml",
164 0x4d, 14, "as",
165 0x4e, 14, "mr",
166 0x4f, 14, "sa",
167 0x50, 1, "mn",
168 0x51, 14, "bo",
169 0x52, 1, "cy",
170 0x53, 14, "km",
171 0x54, 14, "lo",
172 0x56, 2, "gl",
173 0x5b, 14, "si",
174 0x5d, 14, "iu",
175 0x5e, 14, "am",
176/* 0x5f, 2, "??", no ISO-639 abbreviation for Tamazight */
177 0x68, 2, "ha",
178 0x6a, 2, "yo",
179 0x6b, 2, "qu",
180 0x6d, 1, "ba",
181 0x6f, 2, "kl",
182 0x70, 2, "ig",
183/* 0x78, 14, "??", no ISO-639 abbreviation for Yi */
184 0x7e, 2, "br",
185 0x80, 6, "ug",
186 0x81, 14, "mi",
187 0x82, 2, "oc",
188 0x83, 2, "co",
189/* 0x84, 2, "??", no ISO-639 abbreviation for Alsatian */
190/* 0x85, 1, "??", no ISO-639 abbreviation for Yakut */
191/* 0x86, 2, "??", no ISO-639 abbreviation for K'iche */
192 0x87, 2, "rw",
193 0x88, 2, "wo",
194/* 0x8c, 6, "??", no ISO-639 abbreviation for Dari */
195 /* mappings for real Windows LCID values */
196 0x0401, 6, "ar_SA",
197 0x0402, 1, "bg_BG",
198 0x0403, 2, "ca_ES",
199 0x0404, 13, "zh_TW",
200 0x0405, 0, "cs_CZ",
201 0x0406, 2, "da_DK",
202 0x0407, 2, "de_DE",
203 0x0408, 3, "el_GR",
204 0x0409, 2, "en_US",
205 0x040a, 2, "es_ES", /* (traditional sort) */
206 0x040b, 2, "fi_FI",
207 0x040c, 2, "fr_FR",
208 0x040d, 5, "iw_IL",
209 0x040e, 0, "hu_HU",
210 0x040f, 2, "is_IS",
211 0x0410, 2, "it_IT",
212 0x0411, 10, "ja_JP",
213 0x0412, 12, "ko_KR",
214 0x0413, 2, "nl_NL",
215 0x0414, 2, "no_NO",
216 0x0415, 0, "pl_PL",
217 0x0416, 2, "pt_BR",
218 0x0417, 2, "rm_CH",
219 0x0418, 0, "ro_RO",
220 0x0419, 1, "ru_RU",
221 0x041a, 0, "hr_HR",
222 0x041b, 0, "sk_SK",
223 0x041c, 0, "sq_AL",
224 0x041d, 2, "sv_SE",
225 0x041e, 9, "th_TH",
226 0x041f, 4, "tr_TR",
227 0x0420, 6, "ur_PK",
228 0x0421, 2, "in_ID",
229 0x0422, 1, "uk_UA",
230 0x0423, 1, "be_BY",
231 0x0424, 0, "sl_SI",
232 0x0425, 7, "et_EE",
233 0x0426, 7, "lv_LV",
234 0x0427, 7, "lt_LT",
235 0x0428, 1, "tg_TJ",
236 0x0429, 6, "fa_IR",
237 0x042a, 8, "vi_VN",
238 0x042b, 14, "hy_AM", /* Armenian */
239 0x042c, 4, "az_AZ", /* Azeri_Latin */
240 0x042d, 2, "eu_ES",
241/* 0x042e, 2, "??", no ISO-639 abbreviation for Upper Sorbian */
242 0x042f, 1, "mk_MK",
243/* 0x0430, 2, "??", no ISO-639 abbreviation for Sutu */
244 0x0431, 2, "ts", /* (country?) */
245 0x0432, 2, "tn_ZA",
246/* 0x0433, 2, "??", no ISO-639 abbreviation for Venda */
247 0x0434, 2, "xh_ZA",
248 0x0435, 2, "zu_ZA",
249 0x0436, 2, "af_ZA",
250 0x0437, 14, "ka_GE", /* Georgian */
251 0x0438, 2, "fo_FO",
252 0x0439, 14, "hi_IN",
253 0x043a, 14, "mt_MT",
254 0x043b, 2, "se_NO", /* Sami, Northern - Norway */
255 0x043c, 2, "gd_GB",
256 0x043d, 2, "yi", /* (country?) */
257 0x043e, 2, "ms_MY",
258 0x043f, 1, "kk_KZ", /* Kazakh */
259 0x0440, 1, "ky_KG", /* Kyrgyz */
260 0x0441, 2, "sw_KE",
261 0x0442, 0, "tk_TM",
262 0x0443, 4, "uz_UZ", /* Uzbek_Latin */
263 0x0444, 1, "tt_RU", /* Tatar */
264 0x0445, 14, "bn_IN", /* Bengali */
265 0x0446, 14, "pa_IN", /* Punjabi */
266 0x0447, 14, "gu_IN", /* Gujarati */
267 0x0448, 14, "or_IN", /* Oriya */
268 0x0449, 14, "ta_IN", /* Tamil */
269 0x044a, 14, "te_IN", /* Telugu */
270 0x044b, 14, "kn_IN", /* Kannada */
271 0x044c, 14, "ml_IN", /* Malayalam */
272 0x044d, 14, "as_IN", /* Assamese */
273 0x044e, 14, "mr_IN", /* Marathi */
274 0x044f, 14, "sa_IN", /* Sanskrit */
275 0x0450, 1, "mn_MN", /* Mongolian */
276 0x0451, 14, "bo_CN", /* Tibetan */
277 0x0452, 2, "cy_GB", /* Welsh */
278 0x0453, 14, "km_KH", /* Khmer */
279 0x0454, 14, "lo_LA", /* Lao */
280 0x0456, 2, "gl_ES", /* Galician */
281/* 0x0457, 14, "??_IN", /* Konkani, no ISO-639 abbreviation*/
282/* 0x045a, 14, "??_SY", /* Syriac, no ISO-639 abbreviation*/
283 0x045b, 14, "si_LK", /* Sinhala */
284 0x045d, 14, "iu_CA", /* Inuktitut */
285 0x045e, 14, "am_ET", /* Amharic */
286 0x0461, 14, "ne_NP", /* Nepali */
287 0x0462, 2, "fy_NL", /* Frisian */
288 0x0463, 6, "ps_AF", /* Pushto */
289/* 0x0464, 2, "??_PH", /* Filipino, no ISO-639 abbreviation*/
290 0x0465, 14, "dv_MV", /* Divehi */
291 0x0468, 2, "ha_NG", /* Hausa */
292 0x046a, 2, "yo_NG", /* Yoruba */
293 0x046b, 2, "qu_BO", /* Quechua - Bolivia */
294/* 0x046c, 2, "??_ZA", /* Northern Sotho, no ISO-639 abbreviation */
295 0x046d, 1, "ba_RU", /* Bashkir */
296 0x046e, 2, "lb_LU", /* Luxembourgish */
297 0x046f, 2, "kl_GL", /* Greenlandic */
298 0x0470, 2, "ig_NG", /* Igbo */
299/* 0x0478, 14, "??_CN", /* Yi (PRC), no ISO-639 abbreviation */
300/* 0x047a, 2, "??_CL", /* Mapudungun (Araucanian), no ISO-639 abbreviation */
301/* 0x047c, 2, "??_CA", /* Mohawk, no ISO-639 abbreviation */
302 0x047e, 2, "br_FR", /* Breton */
303 0x0480, 6, "ug_CN", /* Uighur */
304 0x0481, 14, "mi_NZ", /* Maori - New Zealand */
305 0x0482, 2, "oc_FR", /* Occitan */
306 0x0483, 2, "co_FR", /* Corsican */
307/* 0x0484, 2, "??_FR", /* Alsatian, no ISO-639 abbreviation */
308/* 0x0485, 1, "??_RU", /* Yakut, no ISO-639 abbreviation */
309/* 0x0486, 2, "??_GT", /* K'iche, no ISO-639 abbreviation */
310 0x0487, 2, "rw_RW", /* Kinyarwanda */
311 0x0488, 2, "wo_SN", /* Wolof */
312/* 0x048c, 6, "??_AF", /* Dari, no ISO-639 abbreviation */
313 0x0801, 6, "ar_IQ",
314 0x0804, 11, "zh_CN",
315 0x0807, 2, "de_CH",
316 0x0809, 2, "en_GB",
317 0x080a, 2, "es_MX",
318 0x080c, 2, "fr_BE",
319 0x0810, 2, "it_CH",
320 0x0812, 15, "ko_KR", /* Korean(Johab)*/
321 0x0813, 2, "nl_BE",
322 0x0814, 2, "no_NO_NY",
323 0x0816, 2, "pt_PT",
324 0x0818, 0, "ro_MD",
325 0x0819, 1, "ru_MD",
326 0x081a, 0, "sr_CS",
327 0x081d, 2, "sv_FI",
328 0x082c, 1, "az_AZ", /* Azeri_Cyrillic */
329/* 0x082e, 2, "??", no ISO-639 abbreviation for Lower Sorbian */
330 0x083b, 2, "se_SE", /* Sami, Northern - Sweden */
331 0x083c, 2, "ga_IE",
332 0x083e, 2, "ms_BN",
333 0x0843, 1, "uz_UZ", /* Uzbek_Cyrillic */
334 0x0845, 14, "bn_BD", /* Bengali */
335 0x0850, 14, "mn_CN", /* Traditional Mongolian */
336 0x085d, 2, "iu_CA", /* Inuktitut */
337/* 0x085f, 2, "??_DZ", no ISO-639 abbreviation for Tamazight */
338 0x086b, 2, "qu_EC", /* Quechua - Ecuador */
339 0x0c01, 6, "ar_EG",
340 0x0c04, 13, "zh_HK",
341 0x0c07, 2, "de_AT",
342 0x0c09, 2, "en_AU",
343 0x0c0a, 2, "es_ES", /* (modern sort) */
344 0x0c0c, 2, "fr_CA",
345 0x0c1a, 1, "sr_CS",
346 0x0c3b, 2, "se_FI", /* Sami, Northern - Finland */
347 0x0c6b, 2, "qu_PE", /* Quechua - Peru */
348 0x1001, 6, "ar_LY",
349 0x1004, 11, "zh_SG",
350 0x1007, 2, "de_LU",
351 0x1009, 2, "en_CA",
352 0x100a, 2, "es_GT",
353 0x100c, 2, "fr_CH",
354 0x101a, 0, "hr_BA",
355/* 0x103b, 2, "??_NO", /* Sami, Lule - Norway */
356 0x1401, 6, "ar_DZ",
357 0x1404, 13, "zh_MO",
358 0x1407, 2, "de_LI",
359 0x1409, 2, "en_NZ",
360 0x140a, 2, "es_CR",
361 0x140c, 2, "fr_LU",
362 0x141a, 0, "bs_BA",
363/* 0x143b, 2, "??_SE", /* Sami, Lule - Sweden */
364 0x1801, 6, "ar_MA",
365 0x1809, 2, "en_IE",
366 0x180a, 2, "es_PA",
367 0x180c, 2, "fr_MC",
368 0x181a, 0, "sr_BA",
369/* 0x183b, 2, "??_NO", /* Sami, Southern - Norway */
370 0x1c01, 6, "ar_TN",
371 0x1c09, 2, "en_ZA",
372 0x1c0a, 2, "es_DO",
373 0x1c1a, 1, "sr_BA",
374/* 0x1c3b, 2, "??_SE", /* Sami, Southern - Sweden */
375 0x2001, 6, "ar_OM",
376 0x2009, 2, "en_JM",
377 0x200a, 2, "es_VE",
378 0x201a, 0, "bs_BA", /* Bosnian (Cyrillic) */
379/* 0x203b, 2, "??_FI", /* Sami, Skolt - Finland */
380 0x2401, 6, "ar_YE",
381 0x2409, 2, "en", /* ("Caribbean", which could be any of many countries) */
382 0x240a, 2, "es_CO",
383/* 0x243b, 2, "??_FI", /* Sami, Inari - Finland */
384 0x2801, 6, "ar_SY",
385 0x2809, 2, "en_BZ",
386 0x280a, 2, "es_PE",
387 0x2c01, 6, "ar_JO",
388 0x2c09, 2, "en_TT",
389 0x2c0a, 2, "es_AR",
390 0x3001, 6, "ar_LB",
391 0x3009, 2, "en_ZW",
392 0x300a, 2, "es_EC",
393 0x3401, 6, "ar_KW",
394 0x3409, 2, "en_PH",
395 0x340a, 2, "es_CL",
396 0x3801, 6, "ar_AE",
397 0x380a, 2, "es_UY",
398 0x3c01, 6, "ar_BH",
399 0x3c0a, 2, "es_PY",
400 0x4001, 6, "ar_QA",
401 0x4009, 2, "en_IN",
402 0x400a, 2, "es_BO",
403 0x4409, 2, "en_MY",
404 0x440a, 2, "es_SV",
405 0x4809, 2, "en_SG",
406 0x480a, 2, "es_HN",
407 0x4c0a, 2, "es_NI",
408 0x500a, 2, "es_PR",
409 0x540a, 2, "es_US"
410};
411
412/*
413 * binary-search our list of LANGID values. If we don't find the
414 * one we're looking for, mask out the country code and try again
415 * with just the primary language ID
416 */
417static int
418getLocaleEntryIndex(LANGID langID)
419{
420 int index = -1;
421 int tries = 0;
422 do {
423 int lo, hi, mid;
424 lo = 0;
425 hi = sizeof(langIDMap) / sizeof(LANGIDtoLocale);
426 while (index == -1 && lo < hi) {
427 mid = (lo + hi) / 2;
428 if (langIDMap[mid].langID == langID) {
429 index = mid;
430 } else if (langIDMap[mid].langID > langID) {
431 hi = mid;
432 } else {
433 lo = mid + 1;
434 }
435 }
436 langID = PRIMARYLANGID(langID);
437 ++tries;
438 } while (index == -1 && tries < 2);
439
440 return index;
441}
442
443static char *
444getEncodingInternal(int index)
445{
446 char * ret = encoding_names[langIDMap[index].encoding];
447
448 //Traditional Chinese Windows should use MS950_HKSCS as the
449 //default encoding, if HKSCS patch has been installed.
450 // "old" MS950 0xfa41 -> u+e001
451 // "new" MS950 0xfa41 -> u+92db
452 if (strcmp(ret, "MS950") == 0) {
453 TCHAR mbChar[2] = {(char)0xfa, (char)0x41};
454 WCHAR unicodeChar;
455 MultiByteToWideChar(CP_ACP, 0, mbChar, 2, &unicodeChar, 1);
456 if (unicodeChar == 0x92db) {
457 ret = "MS950_HKSCS";
458 }
459 } else {
460 //SimpChinese Windows should use GB18030 as the default
461 //encoding, if gb18030 patch has been installed (on windows
462 //2000/XP, (1)Codepage 54936 will be available
463 //(2)simsun18030.ttc will exist under system fonts dir )
464 if (strcmp(ret, "GBK") == 0 && IsValidCodePage(54936)) {
465 char systemPath[MAX_PATH + 1];
466 char* gb18030Font = "\\FONTS\\SimSun18030.ttc";
467 FILE *f = NULL;
468 if (GetWindowsDirectory(systemPath, MAX_PATH + 1) != 0 &&
469 strlen(systemPath) + strlen(gb18030Font) < MAX_PATH + 1) {
470 strcat(systemPath, "\\FONTS\\SimSun18030.ttc");
471 if ((f = fopen(systemPath, "r")) != NULL) {
472 fclose(f);
473 ret = "GB18030";
474 }
475 }
476 }
477 }
478
479 return ret;
480}
481
482// Exported entries for AWT
483DllExport const char *
484getEncodingFromLangID(LANGID langID)
485{
486 int index = getLocaleEntryIndex(langID);
487
488 if (index != (-1)) {
489 return getEncodingInternal(index);
490 } else {
491 return "Cp1252";
492 }
493}
494
495DllExport const char *
496getJavaIDFromLangID(LANGID langID)
497{
498 int index = getLocaleEntryIndex(langID);
499
500 if (index != (-1)) {
501 return langIDMap[index].javaID;
502 } else {
503 return NULL;
504 }
505}
506
507/*
508 * Code to figure out the user's home directory using the registry
509*/
510static char *
511getHomeFromRegistry()
512{
513 HKEY key;
514 int rc;
515 DWORD type;
516 char *p;
517 char path[MAX_PATH+1];
518 int size = MAX_PATH+1;
519
520 rc = RegOpenKeyEx(HKEY_CURRENT_USER, SHELL_KEY, 0, KEY_READ, &key);
521 if (rc != ERROR_SUCCESS) {
522 // Shell folder doesn't exist??!!
523 return NULL;
524 }
525
526 path[0] = 0;
527 rc = RegQueryValueEx(key, "Desktop", 0, &type, path, &size);
528 if (rc != ERROR_SUCCESS || type != REG_SZ) {
529 return NULL;
530 }
531 RegCloseKey(key);
532 /* Get the parent of Desktop directory */
533 p = strrchr(path, '\\');
534 if (p == NULL) {
535 return NULL;
536 }
537 *p = '\0';
538 return strdup(path);
539}
540
541/*
542 * Code to figure out the user's home directory using shell32.dll
543 */
544typedef HRESULT (WINAPI *GetSpecialFolderType)(HWND, int, LPITEMIDLIST *);
545typedef BOOL (WINAPI *GetPathFromIDListType)(LPCITEMIDLIST, LPSTR);
546
547char *
548getHomeFromShell32()
549{
550 HMODULE lib = LoadLibrary("SHELL32.DLL");
551 GetSpecialFolderType do_get_folder;
552 GetPathFromIDListType do_get_path;
553 HRESULT rc;
554 LPITEMIDLIST item_list = 0;
555 char *p;
556 char path[MAX_PATH+1];
557 int size = MAX_PATH+1;
558
559 if (lib == 0) {
560 // We can't load the library !!??
561 return NULL;
562 }
563
564 do_get_folder = (GetSpecialFolderType)GetProcAddress(lib, "SHGetSpecialFolderLocation");
565 do_get_path = (GetPathFromIDListType)GetProcAddress(lib, "SHGetPathFromIDListA");
566
567 if (do_get_folder == 0 || do_get_path == 0) {
568 // the library doesn't hold the right functions !!??
569 return NULL;
570 }
571
572 rc = (*do_get_folder)(NULL, CSIDL_DESKTOPDIRECTORY, &item_list);
573 if (!SUCCEEDED(rc)) {
574 // we can't find the shell folder.
575 return NULL;
576 }
577
578 path[0] = 0;
579 (*do_get_path)(item_list, path);
580
581 /* Get the parent of Desktop directory */
582 p = strrchr(path, '\\');
583 if (p) {
584 *p = 0;
585 }
586
587 /*
588 * We've been successful. Note that we don't free the memory allocated
589 * by ShGetSpecialFolderLocation. We only ever come through here once,
590 * and only if the registry lookup failed, so it's just not worth it.
591 *
592 * We also don't unload the SHELL32 DLL. We've paid the hit for loading
593 * it and we may need it again later.
594 */
595
596 return strdup(path);
597}
598
599static boolean
600haveMMX(void)
601{
602 boolean mmx = 0;
603 HMODULE lib = LoadLibrary("KERNEL32");
604 if (lib != NULL) {
605 BOOL (WINAPI *isProcessorFeaturePresent)(DWORD) =
606 (BOOL (WINAPI *)(DWORD))
607 GetProcAddress(lib, "IsProcessorFeaturePresent");
608 if (isProcessorFeaturePresent != NULL)
609 mmx = isProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE);
610 FreeLibrary(lib);
611 }
612 return mmx;
613}
614
615static const char *
616cpu_isalist(void)
617{
618 SYSTEM_INFO info;
619 GetSystemInfo(&info);
620 switch (info.wProcessorArchitecture) {
621#ifdef PROCESSOR_ARCHITECTURE_IA64
622 case PROCESSOR_ARCHITECTURE_IA64: return "ia64";
623#endif
624#ifdef PROCESSOR_ARCHITECTURE_AMD64
625 case PROCESSOR_ARCHITECTURE_AMD64: return "amd64";
626#endif
627 case PROCESSOR_ARCHITECTURE_INTEL:
628 switch (info.wProcessorLevel) {
629 case 6: return haveMMX()
630 ? "pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86"
631 : "pentium_pro pentium i486 i386 i86";
632 case 5: return haveMMX()
633 ? "pentium+mmx pentium i486 i386 i86"
634 : "pentium i486 i386 i86";
635 case 4: return "i486 i386 i86";
636 case 3: return "i386 i86";
637 }
638 }
639 return NULL;
640}
641
642java_props_t *
643GetJavaProperties(JNIEnv* env)
644{
645 static java_props_t sprops = {0};
646
647 if (sprops.user_dir) {
648 return &sprops;
649 }
650
651 /* AWT properties */
652 sprops.awt_toolkit = "sun.awt.windows.WToolkit";
653
654 /* tmp dir */
655 {
656 char tmpdir[MAX_PATH + 1];
657 /* we might want to check that this succeed */
658 GetTempPath(MAX_PATH + 1, tmpdir);
659 sprops.tmp_dir = strdup(tmpdir);
660 }
661
662 /* Printing properties */
663 sprops.printerJob = "sun.awt.windows.WPrinterJob";
664
665 /* Java2D properties */
666 sprops.graphics_env = "sun.awt.Win32GraphicsEnvironment";
667
668 { /* This is used only for debugging of font problems. */
669 char *path = getenv("JAVA2D_FONTPATH");
670 sprops.font_dir = (path != 0) ? strdup(path) : NULL;
671 }
672
673 /* OS properties */
674 {
675 char buf[100];
676 OSVERSIONINFO ver;
677 ver.dwOSVersionInfoSize = sizeof(ver);
678 GetVersionEx(&ver);
679
680 /*
681 * From msdn page on OSVERSIONINFOEX, current as of this
682 * writing decoding of dwMajorVersion and dwMinorVersion.
683 *
684 * Operating system dwMajorVersion dwMinorVersion
685 * ================== ============== ==============
686 *
687 * Windows 95 4 0
688 * Windows 98 4 10
689 * Windows ME 4 90
690 * Windows 3.51 3 51
691 * Windows NT 4.0 4 0
692 * Windows 2000 5 0
693 * Windows XP 5 1
694 * Windows Server 2003 family 5 2
695 * Windows Vista 6 0
696 *
697 * This mapping will presumably be augmented as new Windows
698 * versions are released.
699 */
700 switch (ver.dwPlatformId) {
701 case VER_PLATFORM_WIN32s:
702 sprops.os_name = "Windows 3.1";
703 break;
704 case VER_PLATFORM_WIN32_WINDOWS:
705 if (ver.dwMajorVersion == 4) {
706 switch (ver.dwMinorVersion) {
707 case 0: sprops.os_name = "Windows 95"; break;
708 case 10: sprops.os_name = "Windows 98"; break;
709 case 90: sprops.os_name = "Windows Me"; break;
710 default: sprops.os_name = "Windows 9X (unknown)"; break;
711 }
712 } else {
713 sprops.os_name = "Windows 9X (unknown)";
714 }
715 break;
716 case VER_PLATFORM_WIN32_NT:
717 if (ver.dwMajorVersion <= 4) {
718 sprops.os_name = "Windows NT";
719 } else if (ver.dwMajorVersion == 5) {
720 switch (ver.dwMinorVersion) {
721 case 0: sprops.os_name = "Windows 2000"; break;
722 case 1: sprops.os_name = "Windows XP"; break;
723 case 2: sprops.os_name = "Windows 2003"; break;
724 default: sprops.os_name = "Windows NT (unknown)"; break;
725 }
726 } else if (ver.dwMajorVersion == 6) {
727 sprops.os_name = "Windows Vista";
728 } else {
729 sprops.os_name = "Windows NT (unknown)";
730 }
731 break;
732 default:
733 sprops.os_name = "Windows (unknown)";
734 break;
735 }
736 sprintf(buf, "%d.%d", ver.dwMajorVersion, ver.dwMinorVersion);
737 sprops.os_version = strdup(buf);
738#if _M_IA64
739 sprops.os_arch = "ia64";
740#elif _M_AMD64
741 sprops.os_arch = "amd64";
742#elif _X86_
743 sprops.os_arch = "x86";
744#else
745 sprops.os_arch = "unknown";
746#endif
747
748 sprops.patch_level = strdup(ver.szCSDVersion);
749
750 sprops.desktop = "windows";
751 }
752
753 /* Endianness of platform */
754 {
755 unsigned int endianTest = 0xff000000;
756 if (((char*)(&endianTest))[0] != 0) {
757 sprops.cpu_endian = "big";
758 } else {
759 sprops.cpu_endian = "little";
760 }
761 }
762
763 /* CPU ISA list */
764 sprops.cpu_isalist = cpu_isalist();
765
766 /*
767 * User name
768 * We try to avoid calling GetUserName as it turns out to
769 * be surprisingly expensive on NT. It pulls in an extra
770 * 100 K of footprint.
771 */
772 {
773 char *uname = getenv("USERNAME");
774 if (uname != NULL && strlen(uname) > 0) {
775 sprops.user_name = strdup(uname);
776 } else {
777 char buf[100];
778 int buflen = sizeof(buf);
779 sprops.user_name =
780 GetUserName(buf, &buflen) ? strdup(buf) : "unknown";
781 }
782 }
783
784 /*
785 * Home directory/
786 *
787 * We first look under a standard registry key. If that fails we
788 * fall back on using a SHELL32.DLL API. If that fails we use a
789 * default value.
790 *
791 * Note: To save space we want to avoid loading SHELL32.DLL
792 * unless really necessary. However if we do load it, we leave it
793 * in memory, as it may be needed again later.
794 *
795 * The normal result is that for a given user name XXX:
796 * On multi-user NT, user.home gets set to c:\winnt\profiles\XXX.
797 * On multi-user Win95, user.home gets set to c:\windows\profiles\XXX.
798 * On single-user Win95, user.home gets set to c:\windows.
799 */
800 {
801 char *homep = getHomeFromRegistry();
802 if (homep == NULL) {
803 homep = getHomeFromShell32();
804 if (homep == NULL) {
805 homep = "C:\\";
806 }
807 }
808 sprops.user_home = homep;
809 }
810
811 /*
812 * user.language
813 * user.country, user.variant (if user's environment specifies them)
814 * file.encoding
815 * file.encoding.pkg
816 */
817 {
818 /*
819 * query the system for the current system default locale
820 * (which is a Windows LCID value),
821 */
822 LANGID langID = LANGIDFROMLCID(GetUserDefaultLCID());
823 LANGID sysLangID = LANGIDFROMLCID(GetSystemDefaultLCID());
824
825 {
826 int index = getLocaleEntryIndex(langID);
827
828 /*
829 * if we didn't find the LCID that the system returned to us,
830 * we don't have a Java locale ID that corresponds to it.
831 * Fall back on en_US.
832 */
833 if (index == -1) {
834 sprops.language = "en";
835 sprops.country = "US";
836 sprops.encoding = "Cp1252";
837 } else {
838
839 /* otherwise, look up the corresponding Java locale ID from
840 * the list of Java locale IDs and set up the system properties
841 * accordingly.
842 */
843
844 char* lang;
845 char* ctry;
846 char* variant;
847
848 lang = strdup(langIDMap[index].javaID);
849 ctry = lang;
850
851 while (*ctry != '_' && *ctry != 0)
852 ++ctry;
853
854 if (*ctry == '_') {
855 *ctry++ = 0;
856 }
857
858 variant = ctry;
859 while (*variant != '_' && *variant != 0)
860 ++variant;
861
862 if (*variant == '_') {
863 *variant++ = 0;
864 }
865
866 sprops.language = lang;
867 sprops.country = ctry;
868 sprops.variant = variant;
869 sprops.encoding = getEncodingInternal(index);
870 }
871 index = getLocaleEntryIndex(sysLangID);
872 if (index == -1) {
873 sprops.sun_jnu_encoding = "Cp1252";
874 } else {
875 sprops.sun_jnu_encoding = getEncodingInternal(index);
876 }
877 }
878 }
879
880 sprops.unicode_encoding = "UnicodeLittle";
881 /* User TIMEZONE */
882 {
883 /*
884 * We defer setting up timezone until it's actually necessary.
885 * Refer to TimeZone.getDefault(). However, the system
886 * property is necessary to be able to be set by the command
887 * line interface -D. Here temporarily set a null string to
888 * timezone.
889 */
890 sprops.timezone = "";
891 }
892
893 /* Current directory */
894 {
895 char buf[MAX_PATH];
896 GetCurrentDirectory(sizeof(buf), buf);
897 sprops.user_dir = strdup(buf);
898 }
899
900 sprops.file_separator = "\\";
901 sprops.path_separator = ";";
902 sprops.line_separator = "\r\n";
903
904 return &sprops;
905}