Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/lang/java_props_md.c
32287 views
/*1* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/* Access APIs for Windows Vista and above */26#ifndef _WIN32_WINNT27#define _WIN32_WINNT 0x060128#endif2930#include "jni.h"31#include "jni_util.h"3233#include <windows.h>34#include <shlobj.h>35#include <objidl.h>36#include <locale.h>37#include <sys/types.h>38#include <sys/timeb.h>39#include <tchar.h>4041#include <stdlib.h>42#include <Wincon.h>4344#include "locale_str.h"45#include "java_props.h"4647#ifndef VER_PLATFORM_WIN32_WINDOWS48#define VER_PLATFORM_WIN32_WINDOWS 149#endif5051#ifndef PROCESSOR_ARCHITECTURE_AMD6452#define PROCESSOR_ARCHITECTURE_AMD64 953#endif5455typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);56static boolean SetupI18nProps(LCID lcid, char** language, char** script, char** country,57char** variant, char** encoding);5859#define PROPSIZE 9 // eight-letter + null terminator60#define SNAMESIZE 86 // max number of chars for LOCALE_SNAME is 856162static char *63getEncodingInternal(LCID lcid)64{65int codepage;66char * ret = malloc(16);67if (ret == NULL) {68return NULL;69}7071if (GetLocaleInfo(lcid,72LOCALE_IDEFAULTANSICODEPAGE,73ret+2, 14) == 0) {74codepage = 1252;75} else {76codepage = atoi(ret+2);77}7879switch (codepage) {80case 0:81strcpy(ret, "UTF-8");82break;83case 874: /* 9:Thai */84case 932: /* 10:Japanese */85case 949: /* 12:Korean Extended Wansung */86case 950: /* 13:Chinese (Taiwan, Hongkong, Macau) */87case 1361: /* 15:Korean Johab */88ret[0] = 'M';89ret[1] = 'S';90break;91case 936:92strcpy(ret, "GBK");93break;94case 54936:95strcpy(ret, "GB18030");96break;97default:98ret[0] = 'C';99ret[1] = 'p';100break;101}102103//Traditional Chinese Windows should use MS950_HKSCS_XP as the104//default encoding, if HKSCS patch has been installed.105// "old" MS950 0xfa41 -> u+e001106// "new" MS950 0xfa41 -> u+92db107if (strcmp(ret, "MS950") == 0) {108TCHAR mbChar[2] = {(char)0xfa, (char)0x41};109WCHAR unicodeChar;110MultiByteToWideChar(CP_ACP, 0, mbChar, 2, &unicodeChar, 1);111if (unicodeChar == 0x92db) {112strcpy(ret, "MS950_HKSCS_XP");113}114} else {115//SimpChinese Windows should use GB18030 as the default116//encoding, if gb18030 patch has been installed (on windows117//2000/XP, (1)Codepage 54936 will be available118//(2)simsun18030.ttc will exist under system fonts dir )119if (strcmp(ret, "GBK") == 0 && IsValidCodePage(54936)) {120char systemPath[MAX_PATH + 1];121char* gb18030Font = "\\FONTS\\SimSun18030.ttc";122FILE *f = NULL;123if (GetWindowsDirectory(systemPath, MAX_PATH + 1) != 0 &&124strlen(systemPath) + strlen(gb18030Font) < MAX_PATH + 1) {125strcat(systemPath, "\\FONTS\\SimSun18030.ttc");126if ((f = fopen(systemPath, "r")) != NULL) {127fclose(f);128strcpy(ret, "GB18030");129}130}131}132}133134return ret;135}136137static char* getConsoleEncoding()138{139char* buf = malloc(16);140int cp;141if (buf == NULL) {142return NULL;143}144cp = GetConsoleCP();145if (cp >= 874 && cp <= 950)146sprintf(buf, "ms%d", cp);147else148sprintf(buf, "cp%d", cp);149return buf;150}151152// Exported entries for AWT153DllExport const char *154getEncodingFromLangID(LANGID langID)155{156return getEncodingInternal(MAKELCID(langID, SORT_DEFAULT));157}158159// Returns BCP47 Language Tag160DllExport const char *161getJavaIDFromLangID(LANGID langID)162{163char * elems[5]; // lang, script, ctry, variant, encoding164char * ret;165int index;166167ret = malloc(SNAMESIZE);168if (ret == NULL) {169return NULL;170}171172if (SetupI18nProps(MAKELCID(langID, SORT_DEFAULT),173&(elems[0]), &(elems[1]), &(elems[2]), &(elems[3]), &(elems[4]))) {174175// there always is the "language" tag176strcpy(ret, elems[0]);177178// append other elements, if any179for (index = 1; index < 4; index++) {180if ((elems[index])[0] != '\0') {181strcat(ret, "-");182strcat(ret, elems[index]);183}184}185186for (index = 0; index < 5; index++) {187free(elems[index]);188}189} else {190free(ret);191ret = NULL;192}193194return ret;195}196197/*198* Code to figure out the user's home directory using shell32.dll199*/200WCHAR*201getHomeFromShell32()202{203/*204* Note that we don't free the memory allocated205* by getHomeFromShell32.206*/207static WCHAR *u_path = NULL;208if (u_path == NULL) {209HRESULT hr;210211/*212* SHELL32 DLL is delay load DLL and we can use the trick with213* __try/__except block.214*/215__try {216/*217* For Windows Vista and later (or patched MS OS) we need to use218* [SHGetKnownFolderPath] call to avoid MAX_PATH length limitation.219* Shell32.dll (version 6.0.6000 or later)220*/221hr = SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DONT_VERIFY, NULL, &u_path);222} __except(EXCEPTION_EXECUTE_HANDLER) {223/* Exception: no [SHGetKnownFolderPath] entry */224hr = E_FAIL;225}226227if (FAILED(hr)) {228WCHAR path[MAX_PATH+1];229230/* fallback solution for WinXP and Windows 2000 */231hr = SHGetFolderPathW(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path);232if (FAILED(hr)) {233/* we can't find the shell folder. */234u_path = NULL;235} else {236/* Just to be sure about the path length until Windows Vista approach.237* [S_FALSE] could not be returned due to [CSIDL_FLAG_DONT_VERIFY] flag and UNICODE version.238*/239path[MAX_PATH] = 0;240u_path = _wcsdup(path);241}242}243}244return u_path;245}246247static boolean248haveMMX(void)249{250return IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE);251}252253static const char *254cpu_isalist(void)255{256SYSTEM_INFO info;257GetSystemInfo(&info);258switch (info.wProcessorArchitecture) {259#ifdef PROCESSOR_ARCHITECTURE_IA64260case PROCESSOR_ARCHITECTURE_IA64: return "ia64";261#endif262#ifdef PROCESSOR_ARCHITECTURE_AMD64263case PROCESSOR_ARCHITECTURE_AMD64: return "amd64";264#endif265case PROCESSOR_ARCHITECTURE_INTEL:266switch (info.wProcessorLevel) {267case 6: return haveMMX()268? "pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86"269: "pentium_pro pentium i486 i386 i86";270case 5: return haveMMX()271? "pentium+mmx pentium i486 i386 i86"272: "pentium i486 i386 i86";273case 4: return "i486 i386 i86";274case 3: return "i386 i86";275}276}277return NULL;278}279280static boolean281SetupI18nProps(LCID lcid, char** language, char** script, char** country,282char** variant, char** encoding) {283/* script */284char tmp[SNAMESIZE];285*script = malloc(PROPSIZE);286if (*script == NULL) {287return FALSE;288}289if (GetLocaleInfo(lcid,290LOCALE_SNAME, tmp, SNAMESIZE) == 0 ||291sscanf(tmp, "%*[a-z\\-]%1[A-Z]%[a-z]", *script, &((*script)[1])) == 0 ||292strlen(*script) != 4) {293(*script)[0] = '\0';294}295296/* country */297*country = malloc(PROPSIZE);298if (*country == NULL) {299return FALSE;300}301if (GetLocaleInfo(lcid,302LOCALE_SISO3166CTRYNAME, *country, PROPSIZE) == 0 &&303GetLocaleInfo(lcid,304LOCALE_SISO3166CTRYNAME2, *country, PROPSIZE) == 0) {305(*country)[0] = '\0';306}307308/* language */309*language = malloc(PROPSIZE);310if (*language == NULL) {311return FALSE;312}313if (GetLocaleInfo(lcid,314LOCALE_SISO639LANGNAME, *language, PROPSIZE) == 0 &&315GetLocaleInfo(lcid,316LOCALE_SISO639LANGNAME2, *language, PROPSIZE) == 0) {317/* defaults to en_US */318strcpy(*language, "en");319strcpy(*country, "US");320}321322/* variant */323*variant = malloc(PROPSIZE);324if (*variant == NULL) {325return FALSE;326}327(*variant)[0] = '\0';328329/* handling for Norwegian */330if (strcmp(*language, "nb") == 0) {331strcpy(*language, "no");332strcpy(*country , "NO");333} else if (strcmp(*language, "nn") == 0) {334strcpy(*language, "no");335strcpy(*country , "NO");336strcpy(*variant, "NY");337}338339/* encoding */340*encoding = getEncodingInternal(lcid);341if (*encoding == NULL) {342return FALSE;343}344return TRUE;345}346347java_props_t *348GetJavaProperties(JNIEnv* env)349{350static java_props_t sprops = {0};351int majorVersion;352int minorVersion;353int buildNumber = 0;354355if (sprops.line_separator) {356return &sprops;357}358359/* AWT properties */360sprops.awt_toolkit = "sun.awt.windows.WToolkit";361362/* tmp dir */363{364WCHAR tmpdir[MAX_PATH + 1];365/* we might want to check that this succeed */366GetTempPathW(MAX_PATH + 1, tmpdir);367sprops.tmp_dir = _wcsdup(tmpdir);368}369370/* Printing properties */371sprops.printerJob = "sun.awt.windows.WPrinterJob";372373/* Java2D properties */374sprops.graphics_env = "sun.awt.Win32GraphicsEnvironment";375376{ /* This is used only for debugging of font problems. */377WCHAR *path = _wgetenv(L"JAVA2D_FONTPATH");378sprops.font_dir = (path != NULL) ? _wcsdup(path) : NULL;379}380381/* OS properties */382{383char buf[100];384boolean is_workstation;385boolean is_64bit;386DWORD platformId;387{388OSVERSIONINFOEX ver;389ver.dwOSVersionInfoSize = sizeof(ver);390GetVersionEx((OSVERSIONINFO *) &ver);391majorVersion = ver.dwMajorVersion;392minorVersion = ver.dwMinorVersion;393/* distinguish Windows Server 2016 and 2019 by build number */394buildNumber = ver.dwBuildNumber;395is_workstation = (ver.wProductType == VER_NT_WORKSTATION);396platformId = ver.dwPlatformId;397sprops.patch_level = _strdup(ver.szCSDVersion);398}399400{401SYSTEM_INFO si;402ZeroMemory(&si, sizeof(SYSTEM_INFO));403GetNativeSystemInfo(&si);404405is_64bit = (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64);406}407do {408// Read the major and minor version number from kernel32.dll409VS_FIXEDFILEINFO *file_info;410WCHAR kernel32_path[MAX_PATH];411DWORD version_size;412LPTSTR version_info;413UINT len, ret;414415// Get the full path to \Windows\System32\kernel32.dll and use that for416// determining what version of Windows we're running on.417len = MAX_PATH - (UINT)strlen("\\kernel32.dll") - 1;418ret = GetSystemDirectoryW(kernel32_path, len);419if (ret == 0 || ret > len) {420break;421}422wcsncat(kernel32_path, L"\\kernel32.dll", MAX_PATH - ret);423424version_size = GetFileVersionInfoSizeW(kernel32_path, NULL);425if (version_size == 0) {426break;427}428429version_info = (LPTSTR)malloc(version_size);430if (version_info == NULL) {431break;432}433434if (!GetFileVersionInfoW(kernel32_path, 0, version_size, version_info)) {435free(version_info);436break;437}438439if (!VerQueryValueW(version_info, L"\\", (LPVOID*)&file_info, &len)) {440free(version_info);441break;442}443majorVersion = HIWORD(file_info->dwProductVersionMS);444minorVersion = LOWORD(file_info->dwProductVersionMS);445buildNumber = HIWORD(file_info->dwProductVersionLS);446free(version_info);447} while (0);448449/*450* From msdn page on OSVERSIONINFOEX, current as of this451* writing, decoding of dwMajorVersion and dwMinorVersion.452*453* Operating system dwMajorVersion dwMinorVersion454* ================== ============== ==============455*456* Windows 95 4 0457* Windows 98 4 10458* Windows ME 4 90459* Windows 3.51 3 51460* Windows NT 4.0 4 0461* Windows 2000 5 0462* Windows XP 32 bit 5 1463* Windows Server 2003 family 5 2464* Windows XP 64 bit 5 2465* where ((&ver.wServicePackMinor) + 2) = 1466* and si.wProcessorArchitecture = 9467* Windows Vista family 6 0 (VER_NT_WORKSTATION)468* Windows Server 2008 6 0 (!VER_NT_WORKSTATION)469* Windows 7 6 1 (VER_NT_WORKSTATION)470* Windows Server 2008 R2 6 1 (!VER_NT_WORKSTATION)471* Windows 8 6 2 (VER_NT_WORKSTATION)472* Windows Server 2012 6 2 (!VER_NT_WORKSTATION)473* Windows Server 2012 R2 6 3 (!VER_NT_WORKSTATION)474* Windows 10 10 0 (VER_NT_WORKSTATION)475* Windows Server 2016 10 0 (!VER_NT_WORKSTATION)476* Windows Server 2019 10 0 (!VER_NT_WORKSTATION)477* where (buildNumber > 17762)478*479* This mapping will presumably be augmented as new Windows480* versions are released.481*/482switch (platformId) {483case VER_PLATFORM_WIN32_WINDOWS:484if (majorVersion == 4) {485switch (minorVersion) {486case 0: sprops.os_name = "Windows 95"; break;487case 10: sprops.os_name = "Windows 98"; break;488case 90: sprops.os_name = "Windows Me"; break;489default: sprops.os_name = "Windows 9X (unknown)"; break;490}491} else {492sprops.os_name = "Windows 9X (unknown)";493}494break;495case VER_PLATFORM_WIN32_NT:496if (majorVersion <= 4) {497sprops.os_name = "Windows NT";498} else if (majorVersion == 5) {499switch (minorVersion) {500case 0: sprops.os_name = "Windows 2000"; break;501case 1: sprops.os_name = "Windows XP"; break;502case 2:503/*504* From MSDN OSVERSIONINFOEX and SYSTEM_INFO documentation:505*506* "Because the version numbers for Windows Server 2003507* and Windows XP 6u4 bit are identical, you must also test508* whether the wProductType member is VER_NT_WORKSTATION.509* and si.wProcessorArchitecture is510* PROCESSOR_ARCHITECTURE_AMD64 (which is 9)511* If it is, the operating system is Windows XP 64 bit;512* otherwise, it is Windows Server 2003."513*/514if (is_workstation && is_64bit) {515sprops.os_name = "Windows XP"; /* 64 bit */516} else {517sprops.os_name = "Windows 2003";518}519break;520default: sprops.os_name = "Windows NT (unknown)"; break;521}522} else if (majorVersion == 6) {523/*524* See table in MSDN OSVERSIONINFOEX documentation.525*/526if (is_workstation) {527switch (minorVersion) {528case 0: sprops.os_name = "Windows Vista"; break;529case 1: sprops.os_name = "Windows 7"; break;530case 2: sprops.os_name = "Windows 8"; break;531case 3: sprops.os_name = "Windows 8.1"; break;532default: sprops.os_name = "Windows NT (unknown)";533}534} else {535switch (minorVersion) {536case 0: sprops.os_name = "Windows Server 2008"; break;537case 1: sprops.os_name = "Windows Server 2008 R2"; break;538case 2: sprops.os_name = "Windows Server 2012"; break;539case 3: sprops.os_name = "Windows Server 2012 R2"; break;540default: sprops.os_name = "Windows NT (unknown)";541}542}543} else if (majorVersion == 10) {544if (is_workstation) {545switch (minorVersion) {546case 0: sprops.os_name = "Windows 10"; break;547default: sprops.os_name = "Windows NT (unknown)";548}549} else {550switch (minorVersion) {551case 0:552/* Windows server 2019 GA 10/2018 build number is 17763 */553if (buildNumber > 17762) {554sprops.os_name = "Windows Server 2019";555} else {556sprops.os_name = "Windows Server 2016";557}558break;559default: sprops.os_name = "Windows NT (unknown)";560}561}562} else {563sprops.os_name = "Windows NT (unknown)";564}565break;566default:567sprops.os_name = "Windows (unknown)";568break;569}570sprintf(buf, "%d.%d", majorVersion, minorVersion);571sprops.os_version = _strdup(buf);572#if _M_IA64573sprops.os_arch = "ia64";574#elif _M_AMD64575sprops.os_arch = "amd64";576#elif _X86_577sprops.os_arch = "x86";578#else579sprops.os_arch = "unknown";580#endif581sprops.desktop = "windows";582}583584/* Endianness of platform */585{586unsigned int endianTest = 0xff000000;587if (((char*)(&endianTest))[0] != 0) {588sprops.cpu_endian = "big";589} else {590sprops.cpu_endian = "little";591}592}593594/* CPU ISA list */595sprops.cpu_isalist = cpu_isalist();596597/*598* User name599* We try to avoid calling GetUserName as it turns out to600* be surprisingly expensive on NT. It pulls in an extra601* 100 K of footprint.602*/603{604WCHAR *uname = _wgetenv(L"USERNAME");605if (uname != NULL && wcslen(uname) > 0) {606sprops.user_name = _wcsdup(uname);607} else {608DWORD buflen = 0;609if (GetUserNameW(NULL, &buflen) == 0 &&610GetLastError() == ERROR_INSUFFICIENT_BUFFER)611{612uname = (WCHAR*)malloc(buflen * sizeof(WCHAR));613if (uname != NULL && GetUserNameW(uname, &buflen) == 0) {614free(uname);615uname = NULL;616}617} else {618uname = NULL;619}620sprops.user_name = (uname != NULL) ? uname : L"unknown";621}622}623624/*625* Home directory626*627* The normal result is that for a given user name XXX:628* On multi-user NT, user.home gets set to c:\winnt\profiles\XXX.629* On multi-user Win95, user.home gets set to c:\windows\profiles\XXX.630* On single-user Win95, user.home gets set to c:\windows.631*/632{633WCHAR *homep = getHomeFromShell32();634if (homep == NULL) {635homep = L"C:\\";636}637sprops.user_home = homep;638}639640/*641* user.language642* user.script, user.country, user.variant (if user's environment specifies them)643* file.encoding644* file.encoding.pkg645*/646{647/*648* query the system for the current system default locale649* (which is a Windows LCID value),650*/651LCID userDefaultLCID = GetUserDefaultLCID();652LCID systemDefaultLCID = GetSystemDefaultLCID();653LCID userDefaultUILang = GetUserDefaultUILanguage();654655{656char * display_encoding;657HANDLE hStdOutErr;658659// Windows UI Language selection list only cares "language"660// information of the UI Language. For example, the list661// just lists "English" but it actually means "en_US", and662// the user cannot select "en_GB" (if exists) in the list.663// So, this hack is to use the user LCID region information664// for the UI Language, if the "language" portion of those665// two locales are the same.666if (PRIMARYLANGID(LANGIDFROMLCID(userDefaultLCID)) ==667PRIMARYLANGID(LANGIDFROMLCID(userDefaultUILang))) {668userDefaultUILang = userDefaultLCID;669}670671SetupI18nProps(userDefaultUILang,672&sprops.language,673&sprops.script,674&sprops.country,675&sprops.variant,676&display_encoding);677SetupI18nProps(userDefaultLCID,678&sprops.format_language,679&sprops.format_script,680&sprops.format_country,681&sprops.format_variant,682&sprops.encoding);683SetupI18nProps(userDefaultUILang,684&sprops.display_language,685&sprops.display_script,686&sprops.display_country,687&sprops.display_variant,688&display_encoding);689690sprops.sun_jnu_encoding = getEncodingInternal(systemDefaultLCID);691if (LANGIDFROMLCID(userDefaultLCID) == 0x0c04 && majorVersion == 6) {692// MS claims "Vista has built-in support for HKSCS-2004.693// All of the HKSCS-2004 characters have Unicode 4.1.694// PUA code point assignments". But what it really means695// is that the HKSCS-2004 is ONLY supported in Unicode.696// Test indicates the MS950 in its zh_HK locale is a697// "regular" MS950 which does not handle HKSCS-2004 at698// all. Set encoding to MS950_HKSCS.699sprops.encoding = "MS950_HKSCS";700sprops.sun_jnu_encoding = "MS950_HKSCS";701}702703hStdOutErr = GetStdHandle(STD_OUTPUT_HANDLE);704if (hStdOutErr != INVALID_HANDLE_VALUE &&705GetFileType(hStdOutErr) == FILE_TYPE_CHAR) {706sprops.sun_stdout_encoding = getConsoleEncoding();707}708hStdOutErr = GetStdHandle(STD_ERROR_HANDLE);709if (hStdOutErr != INVALID_HANDLE_VALUE &&710GetFileType(hStdOutErr) == FILE_TYPE_CHAR) {711if (sprops.sun_stdout_encoding != NULL)712sprops.sun_stderr_encoding = sprops.sun_stdout_encoding;713else714sprops.sun_stderr_encoding = getConsoleEncoding();715}716}717}718719sprops.unicode_encoding = "UnicodeLittle";720/* User TIMEZONE */721{722/*723* We defer setting up timezone until it's actually necessary.724* Refer to TimeZone.getDefault(). However, the system725* property is necessary to be able to be set by the command726* line interface -D. Here temporarily set a null string to727* timezone.728*/729sprops.timezone = "";730}731732/* Current directory */733{734WCHAR buf[MAX_PATH];735if (GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR), buf) != 0)736sprops.user_dir = _wcsdup(buf);737}738739sprops.file_separator = "\\";740sprops.path_separator = ";";741sprops.line_separator = "\r\n";742743return &sprops;744}745746jstring747GetStringPlatform(JNIEnv *env, nchar* wcstr)748{749return (*env)->NewString(env, wcstr, wcslen(wcstr));750}751752753