1 /* 2 * Copyright (c) 1998, 2018, 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 /* Access APIs for Windows Vista and above */ 27 #ifndef _WIN32_WINNT 28 #define _WIN32_WINNT 0x0601 29 #endif 30 31 #include "jni.h" 32 #include "jni_util.h" 33 34 #include <windows.h> 35 #include <shlobj.h> 36 #include <objidl.h> 37 #include <locale.h> 38 #include <sys/types.h> 39 #include <sys/timeb.h> 40 #include <tchar.h> 41 42 #include <stdlib.h> 43 #include <Wincon.h> 44 45 #include "locale_str.h" 46 #include "java_props.h" 47 48 #ifndef VER_PLATFORM_WIN32_WINDOWS 49 #define VER_PLATFORM_WIN32_WINDOWS 1 50 #endif 51 52 #ifndef PROCESSOR_ARCHITECTURE_AMD64 53 #define PROCESSOR_ARCHITECTURE_AMD64 9 54 #endif 55 56 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); 57 static boolean SetupI18nProps(LCID lcid, char** language, char** script, char** country, 58 char** variant, char** encoding); 59 60 #define PROPSIZE 9 // eight-letter + null terminator 61 #define SNAMESIZE 86 // max number of chars for LOCALE_SNAME is 85 62 63 static char * 64 getEncodingInternal(LCID lcid) 65 { 66 int codepage; 67 char * ret = malloc(16); 68 if (ret == NULL) { 69 return NULL; 70 } 71 72 if (GetLocaleInfo(lcid, 73 LOCALE_IDEFAULTANSICODEPAGE, 74 ret+2, 14) == 0) { 75 codepage = 1252; 76 } else { 77 codepage = atoi(ret+2); 78 } 79 80 switch (codepage) { 81 case 0: 82 strcpy(ret, "UTF-8"); 83 break; 84 case 874: /* 9:Thai */ 85 case 932: /* 10:Japanese */ 86 case 949: /* 12:Korean Extended Wansung */ 87 case 950: /* 13:Chinese (Taiwan, Hongkong, Macau) */ 88 case 1361: /* 15:Korean Johab */ 89 ret[0] = 'M'; 90 ret[1] = 'S'; 91 break; 92 case 936: 93 strcpy(ret, "GBK"); 94 break; 95 case 54936: 96 strcpy(ret, "GB18030"); 97 break; 98 default: 99 ret[0] = 'C'; 100 ret[1] = 'p'; 101 break; 102 } 103 104 //Traditional Chinese Windows should use MS950_HKSCS_XP as the 105 //default encoding, if HKSCS patch has been installed. 106 // "old" MS950 0xfa41 -> u+e001 107 // "new" MS950 0xfa41 -> u+92db 108 if (strcmp(ret, "MS950") == 0) { 109 TCHAR mbChar[2] = {(char)0xfa, (char)0x41}; 110 WCHAR unicodeChar; 111 MultiByteToWideChar(CP_ACP, 0, mbChar, 2, &unicodeChar, 1); 112 if (unicodeChar == 0x92db) { 113 strcpy(ret, "MS950_HKSCS_XP"); 114 } 115 } else { 116 //SimpChinese Windows should use GB18030 as the default 117 //encoding, if gb18030 patch has been installed (on windows 118 //2000/XP, (1)Codepage 54936 will be available 119 //(2)simsun18030.ttc will exist under system fonts dir ) 120 if (strcmp(ret, "GBK") == 0 && IsValidCodePage(54936)) { 121 char systemPath[MAX_PATH + 1]; 122 char* gb18030Font = "\\FONTS\\SimSun18030.ttc"; 123 FILE *f = NULL; 124 if (GetWindowsDirectory(systemPath, MAX_PATH + 1) != 0 && 125 strlen(systemPath) + strlen(gb18030Font) < MAX_PATH + 1) { 126 strcat(systemPath, "\\FONTS\\SimSun18030.ttc"); 127 if ((f = fopen(systemPath, "r")) != NULL) { 128 fclose(f); 129 strcpy(ret, "GB18030"); 130 } 131 } 132 } 133 } 134 135 return ret; 136 } 137 138 static char* getConsoleEncoding() 139 { 140 char* buf = malloc(16); 141 int cp; 142 if (buf == NULL) { 143 return NULL; 144 } 145 cp = GetConsoleCP(); 146 if (cp >= 874 && cp <= 950) 147 sprintf(buf, "ms%d", cp); 148 else 149 sprintf(buf, "cp%d", cp); 150 return buf; 151 } 152 153 // Exported entries for AWT 154 DllExport const char * 155 getEncodingFromLangID(LANGID langID) 156 { 157 return getEncodingInternal(MAKELCID(langID, SORT_DEFAULT)); 158 } 159 160 // Returns BCP47 Language Tag 161 DllExport const char * 162 getJavaIDFromLangID(LANGID langID) 163 { 164 char * elems[5]; // lang, script, ctry, variant, encoding 165 char * ret; 166 int index; 167 168 ret = malloc(SNAMESIZE); 169 if (ret == NULL) { 170 return NULL; 171 } 172 173 for (index = 0; index < 5; index++) { 174 elems[index] = NULL; 175 } 176 177 if (SetupI18nProps(MAKELCID(langID, SORT_DEFAULT), 178 &(elems[0]), &(elems[1]), &(elems[2]), &(elems[3]), &(elems[4]))) { 179 180 // there always is the "language" tag 181 strcpy(ret, elems[0]); 182 183 // append other elements, if any 184 for (index = 1; index < 4; index++) { 185 if ((elems[index])[0] != '\0') { 186 strcat(ret, "-"); 187 strcat(ret, elems[index]); 188 } 189 } 190 } else { 191 free(ret); 192 ret = NULL; 193 } 194 195 for (index = 0; index < 5; index++) { 196 if (elems[index] != NULL) { 197 free(elems[index]); 198 } 199 } 200 201 return ret; 202 } 203 204 /* 205 * Code to figure out the user's home directory using shell32.dll 206 */ 207 WCHAR* 208 getHomeFromShell32() 209 { 210 /* 211 * Note that we don't free the memory allocated 212 * by getHomeFromShell32. 213 */ 214 static WCHAR *u_path = NULL; 215 if (u_path == NULL) { 216 HRESULT hr; 217 218 /* 219 * SHELL32 DLL is delay load DLL and we can use the trick with 220 * __try/__except block. 221 */ 222 __try { 223 /* 224 * For Windows Vista and later (or patched MS OS) we need to use 225 * [SHGetKnownFolderPath] call to avoid MAX_PATH length limitation. 226 * Shell32.dll (version 6.0.6000 or later) 227 */ 228 hr = SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DONT_VERIFY, NULL, &u_path); 229 } __except(EXCEPTION_EXECUTE_HANDLER) { 230 /* Exception: no [SHGetKnownFolderPath] entry */ 231 hr = E_FAIL; 232 } 233 234 if (FAILED(hr)) { 235 WCHAR path[MAX_PATH+1]; 236 237 /* fallback solution for WinXP and Windows 2000 */ 238 hr = SHGetFolderPathW(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path); 239 if (FAILED(hr)) { 240 /* we can't find the shell folder. */ 241 u_path = NULL; 242 } else { 243 /* Just to be sure about the path length until Windows Vista approach. 244 * [S_FALSE] could not be returned due to [CSIDL_FLAG_DONT_VERIFY] flag and UNICODE version. 245 */ 246 path[MAX_PATH] = 0; 247 u_path = _wcsdup(path); 248 } 249 } 250 } 251 return u_path; 252 } 253 254 static boolean 255 haveMMX(void) 256 { 257 return IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE); 258 } 259 260 static const char * 261 cpu_isalist(void) 262 { 263 SYSTEM_INFO info; 264 GetSystemInfo(&info); 265 switch (info.wProcessorArchitecture) { 266 #ifdef PROCESSOR_ARCHITECTURE_IA64 267 case PROCESSOR_ARCHITECTURE_IA64: return "ia64"; 268 #endif 269 #ifdef PROCESSOR_ARCHITECTURE_AMD64 270 case PROCESSOR_ARCHITECTURE_AMD64: return "amd64"; 271 #endif 272 case PROCESSOR_ARCHITECTURE_INTEL: 273 switch (info.wProcessorLevel) { 274 case 6: return haveMMX() 275 ? "pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86" 276 : "pentium_pro pentium i486 i386 i86"; 277 case 5: return haveMMX() 278 ? "pentium+mmx pentium i486 i386 i86" 279 : "pentium i486 i386 i86"; 280 case 4: return "i486 i386 i86"; 281 case 3: return "i386 i86"; 282 } 283 } 284 return NULL; 285 } 286 287 static boolean 288 SetupI18nProps(LCID lcid, char** language, char** script, char** country, 289 char** variant, char** encoding) { 290 /* script */ 291 char tmp[SNAMESIZE]; 292 *script = malloc(PROPSIZE); 293 if (*script == NULL) { 294 return FALSE; 295 } 296 if (GetLocaleInfo(lcid, 297 LOCALE_SNAME, tmp, SNAMESIZE) == 0 || 298 sscanf(tmp, "%*[a-z\\-]%1[A-Z]%[a-z]", *script, &((*script)[1])) == 0 || 299 strlen(*script) != 4) { 300 (*script)[0] = '\0'; 301 } 302 303 /* country */ 304 *country = malloc(PROPSIZE); 305 if (*country == NULL) { 306 return FALSE; 307 } 308 if (GetLocaleInfo(lcid, 309 LOCALE_SISO3166CTRYNAME, *country, PROPSIZE) == 0 && 310 GetLocaleInfo(lcid, 311 LOCALE_SISO3166CTRYNAME2, *country, PROPSIZE) == 0) { 312 (*country)[0] = '\0'; 313 } 314 315 /* language */ 316 *language = malloc(PROPSIZE); 317 if (*language == NULL) { 318 return FALSE; 319 } 320 if (GetLocaleInfo(lcid, 321 LOCALE_SISO639LANGNAME, *language, PROPSIZE) == 0 && 322 GetLocaleInfo(lcid, 323 LOCALE_SISO639LANGNAME2, *language, PROPSIZE) == 0) { 324 /* defaults to en_US */ 325 strcpy(*language, "en"); 326 strcpy(*country, "US"); 327 } 328 329 /* variant */ 330 *variant = malloc(PROPSIZE); 331 if (*variant == NULL) { 332 return FALSE; 333 } 334 (*variant)[0] = '\0'; 335 336 /* handling for Norwegian */ 337 if (strcmp(*language, "nb") == 0) { 338 strcpy(*language, "no"); 339 strcpy(*country , "NO"); 340 } else if (strcmp(*language, "nn") == 0) { 341 strcpy(*language, "no"); 342 strcpy(*country , "NO"); 343 strcpy(*variant, "NY"); 344 } 345 346 /* encoding */ 347 *encoding = getEncodingInternal(lcid); 348 if (*encoding == NULL) { 349 return FALSE; 350 } 351 return TRUE; 352 } 353 354 // GetVersionEx is deprecated; disable the warning until a replacement is found 355 #pragma warning(disable : 4996) 356 java_props_t * 357 GetJavaProperties(JNIEnv* env) 358 { 359 static java_props_t sprops = {0}; 360 int majorVersion; 361 int minorVersion; 362 int buildNumber = 0; 363 364 if (sprops.line_separator) { 365 return &sprops; 366 } 367 368 /* AWT properties */ 369 sprops.awt_toolkit = "sun.awt.windows.WToolkit"; 370 371 /* tmp dir */ 372 { 373 WCHAR tmpdir[MAX_PATH + 1]; 374 /* we might want to check that this succeed */ 375 GetTempPathW(MAX_PATH + 1, tmpdir); 376 sprops.tmp_dir = _wcsdup(tmpdir); 377 } 378 379 /* Java2D properties */ 380 sprops.graphics_env = "sun.awt.Win32GraphicsEnvironment"; 381 382 { /* This is used only for debugging of font problems. */ 383 WCHAR *path = _wgetenv(L"JAVA2D_FONTPATH"); 384 sprops.font_dir = (path != NULL) ? _wcsdup(path) : NULL; 385 } 386 387 /* OS properties */ 388 { 389 char buf[100]; 390 boolean is_workstation; 391 boolean is_64bit; 392 DWORD platformId; 393 { 394 OSVERSIONINFOEX ver; 395 ver.dwOSVersionInfoSize = sizeof(ver); 396 GetVersionEx((OSVERSIONINFO *) &ver); 397 majorVersion = ver.dwMajorVersion; 398 minorVersion = ver.dwMinorVersion; 399 /* distinguish Windows Server 2016 and 2019 by build number */ 400 buildNumber = ver.dwBuildNumber; 401 is_workstation = (ver.wProductType == VER_NT_WORKSTATION); 402 platformId = ver.dwPlatformId; 403 sprops.patch_level = _strdup(ver.szCSDVersion); 404 } 405 406 { 407 SYSTEM_INFO si; 408 ZeroMemory(&si, sizeof(SYSTEM_INFO)); 409 GetNativeSystemInfo(&si); 410 411 is_64bit = (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64); 412 } 413 do { 414 // Read the major and minor version number from kernel32.dll 415 VS_FIXEDFILEINFO *file_info; 416 WCHAR kernel32_path[MAX_PATH]; 417 DWORD version_size; 418 LPTSTR version_info; 419 UINT len, ret; 420 421 // Get the full path to \Windows\System32\kernel32.dll and use that for 422 // determining what version of Windows we're running on. 423 len = MAX_PATH - (UINT)strlen("\\kernel32.dll") - 1; 424 ret = GetSystemDirectoryW(kernel32_path, len); 425 if (ret == 0 || ret > len) { 426 break; 427 } 428 wcsncat(kernel32_path, L"\\kernel32.dll", MAX_PATH - ret); 429 430 version_size = GetFileVersionInfoSizeW(kernel32_path, NULL); 431 if (version_size == 0) { 432 break; 433 } 434 435 version_info = (LPTSTR)malloc(version_size); 436 if (version_info == NULL) { 437 break; 438 } 439 440 if (!GetFileVersionInfoW(kernel32_path, 0, version_size, version_info)) { 441 free(version_info); 442 break; 443 } 444 445 if (!VerQueryValueW(version_info, L"\\", (LPVOID*)&file_info, &len)) { 446 free(version_info); 447 break; 448 } 449 majorVersion = HIWORD(file_info->dwProductVersionMS); 450 minorVersion = LOWORD(file_info->dwProductVersionMS); 451 buildNumber = HIWORD(file_info->dwProductVersionLS); 452 free(version_info); 453 } while (0); 454 455 /* 456 * From msdn page on OSVERSIONINFOEX, current as of this 457 * writing, decoding of dwMajorVersion and dwMinorVersion. 458 * 459 * Operating system dwMajorVersion dwMinorVersion 460 * ================== ============== ============== 461 * 462 * Windows 95 4 0 463 * Windows 98 4 10 464 * Windows ME 4 90 465 * Windows 3.51 3 51 466 * Windows NT 4.0 4 0 467 * Windows 2000 5 0 468 * Windows XP 32 bit 5 1 469 * Windows Server 2003 family 5 2 470 * Windows XP 64 bit 5 2 471 * where ((&ver.wServicePackMinor) + 2) = 1 472 * and si.wProcessorArchitecture = 9 473 * Windows Vista family 6 0 (VER_NT_WORKSTATION) 474 * Windows Server 2008 6 0 (!VER_NT_WORKSTATION) 475 * Windows 7 6 1 (VER_NT_WORKSTATION) 476 * Windows Server 2008 R2 6 1 (!VER_NT_WORKSTATION) 477 * Windows 8 6 2 (VER_NT_WORKSTATION) 478 * Windows Server 2012 6 2 (!VER_NT_WORKSTATION) 479 * Windows Server 2012 R2 6 3 (!VER_NT_WORKSTATION) 480 * Windows 10 10 0 (VER_NT_WORKSTATION) 481 * Windows Server 2016 10 0 (!VER_NT_WORKSTATION) 482 * Windows Server 2019 10 0 (!VER_NT_WORKSTATION) 483 * where (buildNumber > 17762) 484 * 485 * This mapping will presumably be augmented as new Windows 486 * versions are released. 487 */ 488 switch (platformId) { 489 case VER_PLATFORM_WIN32_WINDOWS: 490 if (majorVersion == 4) { 491 switch (minorVersion) { 492 case 0: sprops.os_name = "Windows 95"; break; 493 case 10: sprops.os_name = "Windows 98"; break; 494 case 90: sprops.os_name = "Windows Me"; break; 495 default: sprops.os_name = "Windows 9X (unknown)"; break; 496 } 497 } else { 498 sprops.os_name = "Windows 9X (unknown)"; 499 } 500 break; 501 case VER_PLATFORM_WIN32_NT: 502 if (majorVersion <= 4) { 503 sprops.os_name = "Windows NT"; 504 } else if (majorVersion == 5) { 505 switch (minorVersion) { 506 case 0: sprops.os_name = "Windows 2000"; break; 507 case 1: sprops.os_name = "Windows XP"; break; 508 case 2: 509 /* 510 * From MSDN OSVERSIONINFOEX and SYSTEM_INFO documentation: 511 * 512 * "Because the version numbers for Windows Server 2003 513 * and Windows XP 6u4 bit are identical, you must also test 514 * whether the wProductType member is VER_NT_WORKSTATION. 515 * and si.wProcessorArchitecture is 516 * PROCESSOR_ARCHITECTURE_AMD64 (which is 9) 517 * If it is, the operating system is Windows XP 64 bit; 518 * otherwise, it is Windows Server 2003." 519 */ 520 if (is_workstation && is_64bit) { 521 sprops.os_name = "Windows XP"; /* 64 bit */ 522 } else { 523 sprops.os_name = "Windows 2003"; 524 } 525 break; 526 default: sprops.os_name = "Windows NT (unknown)"; break; 527 } 528 } else if (majorVersion == 6) { 529 /* 530 * See table in MSDN OSVERSIONINFOEX documentation. 531 */ 532 if (is_workstation) { 533 switch (minorVersion) { 534 case 0: sprops.os_name = "Windows Vista"; break; 535 case 1: sprops.os_name = "Windows 7"; break; 536 case 2: sprops.os_name = "Windows 8"; break; 537 case 3: sprops.os_name = "Windows 8.1"; break; 538 default: sprops.os_name = "Windows NT (unknown)"; 539 } 540 } else { 541 switch (minorVersion) { 542 case 0: sprops.os_name = "Windows Server 2008"; break; 543 case 1: sprops.os_name = "Windows Server 2008 R2"; break; 544 case 2: sprops.os_name = "Windows Server 2012"; break; 545 case 3: sprops.os_name = "Windows Server 2012 R2"; break; 546 default: sprops.os_name = "Windows NT (unknown)"; 547 } 548 } 549 } else if (majorVersion == 10) { 550 if (is_workstation) { 551 switch (minorVersion) { 552 case 0: sprops.os_name = "Windows 10"; break; 553 default: sprops.os_name = "Windows NT (unknown)"; 554 } 555 } else { 556 switch (minorVersion) { 557 case 0: 558 /* Windows server 2019 GA 10/2018 build number is 17763 */ 559 if (buildNumber > 17762) { 560 sprops.os_name = "Windows Server 2019"; 561 } else { 562 sprops.os_name = "Windows Server 2016"; 563 } 564 break; 565 default: sprops.os_name = "Windows NT (unknown)"; 566 } 567 } 568 } else { 569 sprops.os_name = "Windows NT (unknown)"; 570 } 571 break; 572 default: 573 sprops.os_name = "Windows (unknown)"; 574 break; 575 } 576 sprintf(buf, "%d.%d", majorVersion, minorVersion); 577 sprops.os_version = _strdup(buf); 578 #if _M_AMD64 579 sprops.os_arch = "amd64"; 580 #elif _X86_ 581 sprops.os_arch = "x86"; 582 #else 583 sprops.os_arch = "unknown"; 584 #endif 585 sprops.desktop = "windows"; 586 } 587 588 /* Endianness of platform */ 589 { 590 unsigned int endianTest = 0xff000000; 591 if (((char*)(&endianTest))[0] != 0) { 592 sprops.cpu_endian = "big"; 593 } else { 594 sprops.cpu_endian = "little"; 595 } 596 } 597 598 /* CPU ISA list */ 599 sprops.cpu_isalist = cpu_isalist(); 600 601 /* 602 * User name 603 * We try to avoid calling GetUserName as it turns out to 604 * be surprisingly expensive on NT. It pulls in an extra 605 * 100 K of footprint. 606 */ 607 { 608 WCHAR *uname = _wgetenv(L"USERNAME"); 609 if (uname != NULL && wcslen(uname) > 0) { 610 sprops.user_name = _wcsdup(uname); 611 } else { 612 DWORD buflen = 0; 613 if (GetUserNameW(NULL, &buflen) == 0 && 614 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 615 { 616 uname = (WCHAR*)malloc(buflen * sizeof(WCHAR)); 617 if (uname != NULL && GetUserNameW(uname, &buflen) == 0) { 618 free(uname); 619 uname = NULL; 620 } 621 } else { 622 uname = NULL; 623 } 624 sprops.user_name = (uname != NULL) ? uname : L"unknown"; 625 } 626 } 627 628 /* 629 * Home directory 630 * 631 * The normal result is that for a given user name XXX: 632 * On multi-user NT, user.home gets set to c:\winnt\profiles\XXX. 633 * On multi-user Win95, user.home gets set to c:\windows\profiles\XXX. 634 * On single-user Win95, user.home gets set to c:\windows. 635 */ 636 { 637 WCHAR *homep = getHomeFromShell32(); 638 if (homep == NULL) { 639 homep = L"C:\\"; 640 } 641 sprops.user_home = homep; 642 } 643 644 /* 645 * user.language 646 * user.script, user.country, user.variant (if user's environment specifies them) 647 * file.encoding 648 */ 649 { 650 /* 651 * query the system for the current system default locale 652 * (which is a Windows LCID value), 653 */ 654 LCID userDefaultLCID = GetUserDefaultLCID(); 655 LCID systemDefaultLCID = GetSystemDefaultLCID(); 656 LCID userDefaultUILang = GetUserDefaultUILanguage(); 657 658 { 659 char * display_encoding; 660 HANDLE hStdOutErr; 661 662 // Windows UI Language selection list only cares "language" 663 // information of the UI Language. For example, the list 664 // just lists "English" but it actually means "en_US", and 665 // the user cannot select "en_GB" (if exists) in the list. 666 // So, this hack is to use the user LCID region information 667 // for the UI Language, if the "language" portion of those 668 // two locales are the same. 669 if (PRIMARYLANGID(LANGIDFROMLCID(userDefaultLCID)) == 670 PRIMARYLANGID(LANGIDFROMLCID(userDefaultUILang))) { 671 userDefaultUILang = userDefaultLCID; 672 } 673 674 SetupI18nProps(userDefaultLCID, 675 &sprops.format_language, 676 &sprops.format_script, 677 &sprops.format_country, 678 &sprops.format_variant, 679 &sprops.encoding); 680 SetupI18nProps(userDefaultUILang, 681 &sprops.display_language, 682 &sprops.display_script, 683 &sprops.display_country, 684 &sprops.display_variant, 685 &display_encoding); 686 687 sprops.sun_jnu_encoding = getEncodingInternal(systemDefaultLCID); 688 if (LANGIDFROMLCID(userDefaultLCID) == 0x0c04 && majorVersion == 6) { 689 // MS claims "Vista has built-in support for HKSCS-2004. 690 // All of the HKSCS-2004 characters have Unicode 4.1. 691 // PUA code point assignments". But what it really means 692 // is that the HKSCS-2004 is ONLY supported in Unicode. 693 // Test indicates the MS950 in its zh_HK locale is a 694 // "regular" MS950 which does not handle HKSCS-2004 at 695 // all. Set encoding to MS950_HKSCS. 696 sprops.encoding = "MS950_HKSCS"; 697 sprops.sun_jnu_encoding = "MS950_HKSCS"; 698 } 699 700 hStdOutErr = GetStdHandle(STD_OUTPUT_HANDLE); 701 if (hStdOutErr != INVALID_HANDLE_VALUE && 702 GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { 703 sprops.sun_stdout_encoding = getConsoleEncoding(); 704 } 705 hStdOutErr = GetStdHandle(STD_ERROR_HANDLE); 706 if (hStdOutErr != INVALID_HANDLE_VALUE && 707 GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { 708 if (sprops.sun_stdout_encoding != NULL) 709 sprops.sun_stderr_encoding = sprops.sun_stdout_encoding; 710 else 711 sprops.sun_stderr_encoding = getConsoleEncoding(); 712 } 713 } 714 } 715 716 sprops.unicode_encoding = "UnicodeLittle"; 717 718 /* User TIMEZONE 719 * We defer setting up timezone until it's actually necessary. 720 * Refer to TimeZone.getDefault(). The system property 721 * is able to be set by the command line interface -Duser.timezone. 722 */ 723 724 /* Current directory */ 725 { 726 WCHAR buf[MAX_PATH]; 727 if (GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR), buf) != 0) 728 sprops.user_dir = _wcsdup(buf); 729 } 730 731 sprops.file_separator = "\\"; 732 sprops.path_separator = ";"; 733 sprops.line_separator = "\r\n"; 734 735 return &sprops; 736 } 737 738 jstring 739 GetStringPlatform(JNIEnv *env, nchar* wcstr) 740 { 741 return (*env)->NewString(env, wcstr, (jsize)wcslen(wcstr)); 742 }