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