/*
* Copyright ( c ) 1999 , 2022 , Oracle and / or its affiliates . All rights reserved .
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
* published by the Free Software Foundation . Oracle designates this
* particular file as subject to the " Classpath " exception as provided
* by Oracle in the LICENSE file that accompanied this code .
*
* This code is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "jvm.h"
#include "TimeZone_md.h"
#define VALUE_UNKNOWN 0
#define VALUE_KEY 1
#define VALUE_MAPID 2
#define VALUE_GMTOFFSET 3
#define MAX_ZONE_CHAR 256
#define MAX_MAPID_LENGTH 32
#define MAX_REGION_LENGTH 4
#define NT_TZ_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
#define WIN_TZ_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones"
#define WIN_CURRENT_TZ_KEY "System\\CurrentControlSet\\Control\\TimeZoneInformation"
typedef struct _TziValue {
LONG bias;
LONG stdBias;
LONG dstBias;
SYSTEMTIME stdDate;
SYSTEMTIME dstDate;
} TziValue;
/*
* Registry key names
*/
static void *keyNames[] = {
(void *) L"StandardName" ,
(void *) "StandardName" ,
(void *) L"Std" ,
(void *) "Std"
};
/*
* Indices to keyNames [ ]
*/
#define STANDARD_NAME 0
#define STD_NAME 2
/*
* Calls RegQueryValueEx ( ) to get the value for the specified key . If
* the platform is NT , 2000 or XP , it calls the Unicode
* version . Otherwise , it calls the ANSI version and converts the
* value to Unicode . In this case , it assumes that the current ANSI
* Code Page is the same as the native platform code page ( e . g . , Code
* Page 932 for the Japanese Windows systems .
*
* ` keyIndex ' is an index value to the keyNames in Unicode
* ( WCHAR ) . ` keyIndex ' + 1 points to its ANSI value .
*
* Returns the status value . ERROR_SUCCESS if succeeded , a
* non - ERROR_SUCCESS value otherwise .
*/
static LONG
getValueInRegistry(HKEY hKey,
int keyIndex,
LPDWORD typePtr,
LPBYTE buf,
LPDWORD bufLengthPtr)
{
LONG ret;
DWORD bufLength = *bufLengthPtr;
char val[MAX_ZONE_CHAR];
DWORD valSize;
int len;
*typePtr = 0 ;
ret = RegQueryValueExW(hKey, (WCHAR *) keyNames[keyIndex], NULL,
typePtr, buf, bufLengthPtr);
if (ret == ERROR_SUCCESS && *typePtr == REG_SZ) {
return ret;
}
valSize = sizeof (val);
ret = RegQueryValueExA(hKey, (char *) keyNames[keyIndex + 1 ], NULL,
typePtr, val, &valSize);
if (ret != ERROR_SUCCESS) {
return ret;
}
if (*typePtr != REG_SZ) {
return ERROR_BADKEY;
}
len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
(LPCSTR) val, -1 ,
(LPWSTR) buf, bufLength/sizeof (WCHAR));
if (len <= 0 ) {
return ERROR_BADKEY;
}
return ERROR_SUCCESS;
}
/*
* Produces custom name " GMT + hh : mm " from the given bias in buffer .
*/
static void customZoneName(LONG bias, char *buffer) {
LONG gmtOffset;
int sign;
if (bias > 0 ) {
gmtOffset = bias;
sign = -1 ;
} else {
gmtOffset = -bias;
sign = 1 ;
}
if (gmtOffset != 0 ) {
sprintf(buffer, "GMT%c%02d:%02d" ,
((sign >= 0 ) ? '+' : '-' ),
gmtOffset / 60 ,
gmtOffset % 60 );
} else {
strcpy(buffer, "GMT" );
}
}
/*
* Gets the current time zone entry in the " Time Zones " registry .
*/
static int getWinTimeZone(char *winZoneName)
{
DYNAMIC_TIME_ZONE_INFORMATION dtzi;
DWORD timeType;
DWORD bufSize;
DWORD val;
HANDLE hKey = NULL;
LONG ret;
ULONG valueType;
/*
* Get the dynamic time zone information so that time zone redirection
* can be supported . ( see JDK - 7044727 )
*/
timeType = GetDynamicTimeZoneInformation(&dtzi);
if (timeType == TIME_ZONE_ID_INVALID) {
goto err;
}
/*
* Make sure TimeZoneKeyName is available from the API call . If
* DynamicDaylightTime is disabled , return a custom time zone name
* based on the GMT offset . Otherwise , return the TimeZoneKeyName
* value .
*/
if (dtzi.TimeZoneKeyName[0 ] != 0 ) {
if (dtzi.DynamicDaylightTimeDisabled) {
customZoneName(dtzi.Bias, winZoneName);
return VALUE_GMTOFFSET;
}
wcstombs(winZoneName, dtzi.TimeZoneKeyName, MAX_ZONE_CHAR);
return VALUE_KEY;
}
/*
* If TimeZoneKeyName is not available , check whether StandardName
* is available to fall back to the older API GetTimeZoneInformation .
* If not , directly read the value from registry keys .
*/
if (dtzi.StandardName[0 ] == 0 ) {
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0 ,
KEY_READ, (PHKEY)&hKey);
if (ret != ERROR_SUCCESS) {
goto err;
}
/*
* Determine if auto - daylight time adjustment is turned off .
*/
bufSize = sizeof (val);
ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled" , NULL,
&valueType, (LPBYTE) &val, &bufSize);
if (ret != ERROR_SUCCESS) {
goto err;
}
/*
* Return a custom time zone name if auto - daylight time adjustment
* is disabled .
*/
if (val == 1 ) {
customZoneName(dtzi.Bias, winZoneName);
(void ) RegCloseKey(hKey);
return VALUE_GMTOFFSET;
}
bufSize = MAX_ZONE_CHAR;
ret = RegQueryValueExA(hKey, "TimeZoneKeyName" , NULL,
&valueType, (LPBYTE) winZoneName, &bufSize);
if (ret != ERROR_SUCCESS) {
goto err;
}
(void ) RegCloseKey(hKey);
return VALUE_KEY;
} else {
/*
* Fall back to GetTimeZoneInformation
*/
TIME_ZONE_INFORMATION tzi;
HANDLE hSubKey = NULL;
DWORD nSubKeys, i;
ULONG valueType;
TCHAR subKeyName[MAX_ZONE_CHAR];
TCHAR szValue[MAX_ZONE_CHAR];
WCHAR stdNameInReg[MAX_ZONE_CHAR];
TziValue tempTzi;
WCHAR *stdNamePtr = tzi.StandardName;
int onlyMapID;
timeType = GetTimeZoneInformation(&tzi);
if (timeType == TIME_ZONE_ID_INVALID) {
goto err;
}
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0 ,
KEY_READ, (PHKEY)&hKey);
if (ret == ERROR_SUCCESS) {
/*
* Determine if auto - daylight time adjustment is turned off .
*/
bufSize = sizeof (val);
ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled" , NULL,
&valueType, (LPBYTE) &val, &bufSize);
if (ret == ERROR_SUCCESS) {
if (val == 1 && tzi.DaylightDate.wMonth != 0 ) {
(void ) RegCloseKey(hKey);
customZoneName(tzi.Bias, winZoneName);
return VALUE_GMTOFFSET;
}
}
/*
* Win32 problem : If the length of the standard time name is equal
* to ( or probably longer than ) 32 in the registry ,
* GetTimeZoneInformation ( ) on NT returns a null string as its
* standard time name . We need to work around this problem by
* getting the same information from the TimeZoneInformation
* registry .
*/
if (tzi.StandardName[0 ] == 0 ) {
bufSize = sizeof (stdNameInReg);
ret = getValueInRegistry(hKey, STANDARD_NAME, &valueType,
(LPBYTE) stdNameInReg, &bufSize);
if (ret != ERROR_SUCCESS) {
goto err;
}
stdNamePtr = stdNameInReg;
}
(void ) RegCloseKey(hKey);
}
/*
* Open the " Time Zones " registry .
*/
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT_TZ_KEY, 0 , KEY_READ, (PHKEY)&hKey);
if (ret != ERROR_SUCCESS) {
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_TZ_KEY, 0 , KEY_READ, (PHKEY)&hKey);
/*
* If both failed , then give up .
*/
if (ret != ERROR_SUCCESS) {
return VALUE_UNKNOWN;
}
}
/*
* Get the number of subkeys of the " Time Zones " registry for
* enumeration .
*/
ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, &nSubKeys,
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS) {
goto err;
}
/*
* Compare to the " Std " value of each subkey and find the entry that
* matches the current control panel setting .
*/
onlyMapID = 0 ;
for (i = 0 ; i < nSubKeys; ++i) {
DWORD size = sizeof (subKeyName);
ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS) {
goto err;
}
ret = RegOpenKeyEx(hKey, subKeyName, 0 , KEY_READ, (PHKEY)&hSubKey);
if (ret != ERROR_SUCCESS) {
goto err;
}
size = sizeof (szValue);
ret = getValueInRegistry(hSubKey, STD_NAME, &valueType,
szValue, &size);
if (ret != ERROR_SUCCESS) {
/*
* NT 4 . 0 SP3 fails here since it doesn ' t have the " Std "
* entry in the Time Zones registry .
*/
RegCloseKey(hSubKey);
onlyMapID = 1 ;
ret = RegOpenKeyExW(hKey, stdNamePtr, 0 , KEY_READ, (PHKEY)&hSubKey);
if (ret != ERROR_SUCCESS) {
goto err;
}
break ;
}
if (wcscmp((WCHAR *)szValue, stdNamePtr) == 0 ) {
/*
* Some localized Win32 platforms use a same name to
* different time zones . So , we can ' t rely only on the name
* here . We need to check GMT offsets and transition dates
* to make sure it ' s the registry of the current time
* zone .
*/
DWORD tziValueSize = sizeof (tempTzi);
ret = RegQueryValueEx(hSubKey, "TZI" , NULL, &valueType,
(unsigned char *) &tempTzi, &tziValueSize);
if (ret == ERROR_SUCCESS) {
if ((tzi.Bias != tempTzi.bias) ||
(memcmp((const void *) &tzi.StandardDate,
(const void *) &tempTzi.stdDate,
sizeof (SYSTEMTIME)) != 0 )) {
goto out;
}
if (tzi.DaylightBias != 0 ) {
if ((tzi.DaylightBias != tempTzi.dstBias) ||
(memcmp((const void *) &tzi.DaylightDate,
(const void *) &tempTzi.dstDate,
sizeof (SYSTEMTIME)) != 0 )) {
goto out;
}
}
}
/*
* found matched record , terminate search
*/
strcpy(winZoneName, subKeyName);
break ;
}
out:
(void ) RegCloseKey(hSubKey);
}
(void ) RegCloseKey(hKey);
}
return VALUE_KEY;
err:
if (hKey != NULL) {
(void ) RegCloseKey(hKey);
}
return VALUE_UNKNOWN;
}
/*
* The mapping table file name .
*/
#define MAPPINGS_FILE "\\lib\\tzmappings"
/*
* Index values for the mapping table .
*/
#define TZ_WIN_NAME 0
#define TZ_REGION 1
#define TZ_JAVA_NAME 2
#define TZ_NITEMS 3 /* number of items (fields) */
/*
* Looks up the mapping table ( tzmappings ) and returns a Java time
* zone ID ( e . g . , " America / Los_Angeles " ) if found . Otherwise , NULL is
* returned .
*/
static char *matchJavaTZ(const char *java_home_dir, char *tzName)
{
int line;
FILE *fp;
char *javaTZName = NULL;
char *items[TZ_NITEMS];
char *mapFileName;
char lineBuffer[MAX_ZONE_CHAR * 4 ];
int offset = 0 ;
const char * errorMessage = "unknown error" ;
char region[MAX_REGION_LENGTH];
// Get the user's location
if (GetGeoInfo(GetUserGeoID(GEOCLASS_NATION),
GEO_ISO2, region, MAX_REGION_LENGTH, 0 ) == 0 ) {
// If GetGeoInfo fails, fallback to LCID's country
LCID lcid = GetUserDefaultLCID();
if (GetLocaleInfo(lcid,
LOCALE_SISO3166CTRYNAME, region, MAX_REGION_LENGTH) == 0 &&
GetLocaleInfo(lcid,
LOCALE_SISO3166CTRYNAME2, region, MAX_REGION_LENGTH) == 0 ) {
region[0 ] = '\0' ;
}
}
mapFileName = malloc(strlen(java_home_dir) + strlen(MAPPINGS_FILE) + 1 );
if (mapFileName == NULL) {
return NULL;
}
strcpy(mapFileName, java_home_dir);
strcat(mapFileName, MAPPINGS_FILE);
if ((fp = fopen(mapFileName, "r" )) == NULL) {
jio_fprintf(stderr, "can't open %s.\n" , mapFileName);
free((void *) mapFileName);
return NULL;
}
free((void *) mapFileName);
line = 0 ;
while (fgets(lineBuffer, sizeof (lineBuffer), fp) != NULL) {
char *start, *idx, *endp;
int itemIndex = 0 ;
line++;
start = idx = lineBuffer;
endp = &lineBuffer[sizeof (lineBuffer)];
/*
* Ignore comment and blank lines .
*/
if (*idx == '#' || *idx == '\n' ) {
continue ;
}
for (itemIndex = 0 ; itemIndex < TZ_NITEMS; itemIndex++) {
items[itemIndex] = start;
while (*idx && *idx != ':' ) {
if (++idx >= endp) {
errorMessage = "premature end of line" ;
offset = (int )(idx - lineBuffer);
goto illegal_format;
}
}
if (*idx == '\0' ) {
errorMessage = "illegal null character found" ;
offset = (int )(idx - lineBuffer);
goto illegal_format;
}
*idx++ = '\0' ;
start = idx;
}
if (*idx != '\n' ) {
errorMessage = "illegal non-newline character found" ;
offset = (int )(idx - lineBuffer);
goto illegal_format;
}
/*
* We need to scan items until the
* exact match is found or the end of data is detected .
*/
if (strcmp(items[TZ_WIN_NAME], tzName) == 0 ) {
/*
* Found the time zone in the mapping table .
* Check the region code and select the appropriate entry
*/
if (strcmp(items[TZ_REGION], region) == 0 ||
strcmp(items[TZ_REGION], "001" ) == 0 ) {
javaTZName = _strdup(items[TZ_JAVA_NAME]);
break ;
}
}
}
fclose(fp);
return javaTZName;
illegal_format:
(void ) fclose(fp);
jio_fprintf(stderr, "Illegal format in tzmappings file: %s at line %d, offset %d.\n" ,
errorMessage, line, offset);
return NULL;
}
/*
* Detects the platform time zone which maps to a Java time zone ID .
*/
char *findJavaTZ_md(const char *java_home_dir)
{
char winZoneName[MAX_ZONE_CHAR];
char *std_timezone = NULL;
int result;
result = getWinTimeZone(winZoneName);
if (result != VALUE_UNKNOWN) {
if (result == VALUE_GMTOFFSET) {
std_timezone = _strdup(winZoneName);
} else {
std_timezone = matchJavaTZ(java_home_dir, winZoneName);
if (std_timezone == NULL) {
std_timezone = getGMTOffsetID();
}
}
}
return std_timezone;
}
/**
* Returns a GMT - offset - based time zone ID .
*/
char *
getGMTOffsetID()
{
LONG bias = 0 ;
LONG ret;
HANDLE hKey = NULL;
char zonename[32 ];
// Obtain the current GMT offset value of ActiveTimeBias.
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0 ,
KEY_READ, (PHKEY)&hKey);
if (ret == ERROR_SUCCESS) {
DWORD val;
DWORD bufSize = sizeof (val);
ULONG valueType = 0 ;
ret = RegQueryValueExA(hKey, "ActiveTimeBias" ,
NULL, &valueType, (LPBYTE) &val, &bufSize);
if (ret == ERROR_SUCCESS) {
bias = (LONG ) val;
}
(void ) RegCloseKey(hKey);
}
// If we can't get the ActiveTimeBias value, use Bias of TimeZoneInformation.
// Note: Bias doesn't reflect current daylight saving.
if (ret != ERROR_SUCCESS) {
TIME_ZONE_INFORMATION tzi;
if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
bias = tzi.Bias;
}
}
customZoneName(bias, zonename);
return _strdup(zonename);
}
Messung V0.5 in Prozent C=95 H=91 G=92
¤ Dauer der Verarbeitung: 0.11 Sekunden
¤
*© Formatika GbR, Deutschland