Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/util/TimeZone_md.c
32287 views
1
/*
2
* Copyright (c) 1999, 2015, 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
#include <windows.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include "jvm.h"
30
#include "TimeZone_md.h"
31
#include "jdk_util.h"
32
33
#define VALUE_UNKNOWN 0
34
#define VALUE_KEY 1
35
#define VALUE_MAPID 2
36
#define VALUE_GMTOFFSET 3
37
38
#define MAX_ZONE_CHAR 256
39
#define MAX_MAPID_LENGTH 32
40
41
#define NT_TZ_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
42
#define WIN_TZ_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones"
43
#define WIN_CURRENT_TZ_KEY "System\\CurrentControlSet\\Control\\TimeZoneInformation"
44
45
typedef struct _TziValue {
46
LONG bias;
47
LONG stdBias;
48
LONG dstBias;
49
SYSTEMTIME stdDate;
50
SYSTEMTIME dstDate;
51
} TziValue;
52
53
#if _WIN32_WINNT < 0x0600 /* < _WIN32_WINNT_VISTA */
54
typedef struct _TIME_DYNAMIC_ZONE_INFORMATION {
55
LONG Bias;
56
WCHAR StandardName[32];
57
SYSTEMTIME StandardDate;
58
LONG StandardBias;
59
WCHAR DaylightName[32];
60
SYSTEMTIME DaylightDate;
61
LONG DaylightBias;
62
WCHAR TimeZoneKeyName[128];
63
BOOLEAN DynamicDaylightTimeDisabled;
64
} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION;
65
#endif
66
67
/*
68
* Registry key names
69
*/
70
static void *keyNames[] = {
71
(void *) L"StandardName",
72
(void *) "StandardName",
73
(void *) L"Std",
74
(void *) "Std"
75
};
76
77
/*
78
* Indices to keyNames[]
79
*/
80
#define STANDARD_NAME 0
81
#define STD_NAME 2
82
83
/*
84
* Calls RegQueryValueEx() to get the value for the specified key. If
85
* the platform is NT, 2000 or XP, it calls the Unicode
86
* version. Otherwise, it calls the ANSI version and converts the
87
* value to Unicode. In this case, it assumes that the current ANSI
88
* Code Page is the same as the native platform code page (e.g., Code
89
* Page 932 for the Japanese Windows systems.
90
*
91
* `keyIndex' is an index value to the keyNames in Unicode
92
* (WCHAR). `keyIndex' + 1 points to its ANSI value.
93
*
94
* Returns the status value. ERROR_SUCCESS if succeeded, a
95
* non-ERROR_SUCCESS value otherwise.
96
*/
97
static LONG
98
getValueInRegistry(HKEY hKey,
99
int keyIndex,
100
LPDWORD typePtr,
101
LPBYTE buf,
102
LPDWORD bufLengthPtr)
103
{
104
LONG ret;
105
DWORD bufLength = *bufLengthPtr;
106
char val[MAX_ZONE_CHAR];
107
DWORD valSize;
108
int len;
109
110
*typePtr = 0;
111
ret = RegQueryValueExW(hKey, (WCHAR *) keyNames[keyIndex], NULL,
112
typePtr, buf, bufLengthPtr);
113
if (ret == ERROR_SUCCESS && *typePtr == REG_SZ) {
114
return ret;
115
}
116
117
valSize = sizeof(val);
118
ret = RegQueryValueExA(hKey, (char *) keyNames[keyIndex + 1], NULL,
119
typePtr, val, &valSize);
120
if (ret != ERROR_SUCCESS) {
121
return ret;
122
}
123
if (*typePtr != REG_SZ) {
124
return ERROR_BADKEY;
125
}
126
127
len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
128
(LPCSTR) val, -1,
129
(LPWSTR) buf, bufLength/sizeof(WCHAR));
130
if (len <= 0) {
131
return ERROR_BADKEY;
132
}
133
return ERROR_SUCCESS;
134
}
135
136
/*
137
* Produces custom name "GMT+hh:mm" from the given bias in buffer.
138
*/
139
static void customZoneName(LONG bias, char *buffer) {
140
LONG gmtOffset;
141
int sign;
142
143
if (bias > 0) {
144
gmtOffset = bias;
145
sign = -1;
146
} else {
147
gmtOffset = -bias;
148
sign = 1;
149
}
150
if (gmtOffset != 0) {
151
sprintf(buffer, "GMT%c%02d:%02d",
152
((sign >= 0) ? '+' : '-'),
153
gmtOffset / 60,
154
gmtOffset % 60);
155
} else {
156
strcpy(buffer, "GMT");
157
}
158
}
159
160
/*
161
* Use NO_DYNAMIC_TIME_ZONE_INFO as the return value indicating that no
162
* dynamic time zone information is available.
163
*/
164
#define NO_DYNAMIC_TIME_ZONE_INFO (-128)
165
166
static int getDynamicTimeZoneInfo(PDYNAMIC_TIME_ZONE_INFORMATION pdtzi) {
167
DWORD timeType = NO_DYNAMIC_TIME_ZONE_INFO;
168
HMODULE dllHandle;
169
170
/*
171
* Dynamically load the dll to call GetDynamicTimeZoneInformation.
172
*/
173
dllHandle = JDK_LoadSystemLibrary("Kernel32.dll");
174
if (dllHandle != NULL) {
175
typedef DWORD (WINAPI *GetDynamicTimezoneInfoType)(PDYNAMIC_TIME_ZONE_INFORMATION);
176
GetDynamicTimezoneInfoType getDynamicTimeZoneInfoFunc =
177
(GetDynamicTimezoneInfoType) GetProcAddress(dllHandle,
178
"GetDynamicTimeZoneInformation");
179
180
if (getDynamicTimeZoneInfo != NULL) {
181
timeType = getDynamicTimeZoneInfoFunc(pdtzi);
182
}
183
}
184
return timeType;
185
}
186
187
/*
188
* Gets the current time zone entry in the "Time Zones" registry.
189
*/
190
static int getWinTimeZone(char *winZoneName, char *winMapID)
191
{
192
TIME_ZONE_INFORMATION tzi;
193
OSVERSIONINFO ver;
194
int onlyMapID;
195
HANDLE hKey = NULL, hSubKey = NULL;
196
LONG ret;
197
DWORD nSubKeys, i;
198
ULONG valueType;
199
TCHAR subKeyName[MAX_ZONE_CHAR];
200
TCHAR szValue[MAX_ZONE_CHAR];
201
WCHAR stdNameInReg[MAX_ZONE_CHAR];
202
TziValue tempTzi;
203
WCHAR *stdNamePtr = tzi.StandardName;
204
DWORD valueSize;
205
DWORD timeType;
206
int isVistaOrLater;
207
208
/*
209
* Determine if this is a Vista or later.
210
*/
211
ver.dwOSVersionInfoSize = sizeof(ver);
212
GetVersionEx(&ver);
213
isVistaOrLater = (ver.dwMajorVersion >= 6);
214
215
if (isVistaOrLater) {
216
DYNAMIC_TIME_ZONE_INFORMATION dtzi;
217
DWORD bufSize;
218
DWORD val;
219
220
/*
221
* Get the dynamic time zone information, if available, so that time
222
* zone redirection can be supported. (see JDK-7044727)
223
*/
224
timeType = getDynamicTimeZoneInfo(&dtzi);
225
if (timeType == TIME_ZONE_ID_INVALID) {
226
goto err;
227
}
228
229
if (timeType != NO_DYNAMIC_TIME_ZONE_INFO) {
230
/*
231
* Make sure TimeZoneKeyName is available from the API call. If
232
* DynamicDaylightTime is disabled, return a custom time zone name
233
* based on the GMT offset. Otherwise, return the TimeZoneKeyName
234
* value.
235
*/
236
if (dtzi.TimeZoneKeyName[0] != 0) {
237
if (dtzi.DynamicDaylightTimeDisabled) {
238
customZoneName(dtzi.Bias, winZoneName);
239
return VALUE_GMTOFFSET;
240
}
241
wcstombs(winZoneName, dtzi.TimeZoneKeyName, MAX_ZONE_CHAR);
242
return VALUE_KEY;
243
}
244
245
/*
246
* If TimeZoneKeyName is not available, check whether StandardName
247
* is available to fall back to the older API GetTimeZoneInformation.
248
* If not, directly read the value from registry keys.
249
*/
250
if (dtzi.StandardName[0] == 0) {
251
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
252
KEY_READ, (PHKEY)&hKey);
253
if (ret != ERROR_SUCCESS) {
254
goto err;
255
}
256
257
/*
258
* Determine if auto-daylight time adjustment is turned off.
259
*/
260
bufSize = sizeof(val);
261
ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
262
&valueType, (LPBYTE) &val, &bufSize);
263
if (ret != ERROR_SUCCESS) {
264
goto err;
265
}
266
/*
267
* Return a custom time zone name if auto-daylight time
268
* adjustment is disabled.
269
*/
270
if (val == 1) {
271
customZoneName(dtzi.Bias, winZoneName);
272
(void) RegCloseKey(hKey);
273
return VALUE_GMTOFFSET;
274
}
275
276
bufSize = MAX_ZONE_CHAR;
277
ret = RegQueryValueExA(hKey, "TimeZoneKeyName",NULL,
278
&valueType, (LPBYTE)winZoneName, &bufSize);
279
if (ret != ERROR_SUCCESS) {
280
goto err;
281
}
282
(void) RegCloseKey(hKey);
283
return VALUE_KEY;
284
}
285
}
286
}
287
288
/*
289
* Fall back to GetTimeZoneInformation
290
*/
291
timeType = GetTimeZoneInformation(&tzi);
292
if (timeType == TIME_ZONE_ID_INVALID) {
293
goto err;
294
}
295
296
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
297
KEY_READ, (PHKEY)&hKey);
298
if (ret == ERROR_SUCCESS) {
299
DWORD val;
300
DWORD bufSize;
301
302
/*
303
* Determine if auto-daylight time adjustment is turned off.
304
*/
305
bufSize = sizeof(val);
306
ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
307
&valueType, (LPBYTE) &val, &bufSize);
308
if (ret != ERROR_SUCCESS) {
309
/*
310
* Try the old key name.
311
*/
312
bufSize = sizeof(val);
313
ret = RegQueryValueExA(hKey, "DisableAutoDaylightTimeSet", NULL,
314
&valueType, (LPBYTE) &val, &bufSize);
315
}
316
317
if (ret == ERROR_SUCCESS) {
318
int daylightSavingsUpdateDisabledOther = (val == 1 && tzi.DaylightDate.wMonth != 0);
319
int daylightSavingsUpdateDisabledVista = (val == 1);
320
int daylightSavingsUpdateDisabled
321
= (isVistaOrLater ? daylightSavingsUpdateDisabledVista : daylightSavingsUpdateDisabledOther);
322
323
if (daylightSavingsUpdateDisabled) {
324
(void) RegCloseKey(hKey);
325
customZoneName(tzi.Bias, winZoneName);
326
return VALUE_GMTOFFSET;
327
}
328
}
329
330
/*
331
* Win32 problem: If the length of the standard time name is equal
332
* to (or probably longer than) 32 in the registry,
333
* GetTimeZoneInformation() on NT returns a null string as its
334
* standard time name. We need to work around this problem by
335
* getting the same information from the TimeZoneInformation
336
* registry.
337
*/
338
if (tzi.StandardName[0] == 0) {
339
bufSize = sizeof(stdNameInReg);
340
ret = getValueInRegistry(hKey, STANDARD_NAME, &valueType,
341
(LPBYTE) stdNameInReg, &bufSize);
342
if (ret != ERROR_SUCCESS) {
343
goto err;
344
}
345
stdNamePtr = stdNameInReg;
346
}
347
(void) RegCloseKey(hKey);
348
}
349
350
/*
351
* Open the "Time Zones" registry.
352
*/
353
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey);
354
if (ret != ERROR_SUCCESS) {
355
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey);
356
/*
357
* If both failed, then give up.
358
*/
359
if (ret != ERROR_SUCCESS) {
360
return VALUE_UNKNOWN;
361
}
362
}
363
364
/*
365
* Get the number of subkeys of the "Time Zones" registry for
366
* enumeration.
367
*/
368
ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, &nSubKeys,
369
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
370
if (ret != ERROR_SUCCESS) {
371
goto err;
372
}
373
374
/*
375
* Compare to the "Std" value of each subkey and find the entry that
376
* matches the current control panel setting.
377
*/
378
onlyMapID = 0;
379
for (i = 0; i < nSubKeys; ++i) {
380
DWORD size = sizeof(subKeyName);
381
ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL);
382
if (ret != ERROR_SUCCESS) {
383
goto err;
384
}
385
ret = RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, (PHKEY)&hSubKey);
386
if (ret != ERROR_SUCCESS) {
387
goto err;
388
}
389
390
size = sizeof(szValue);
391
ret = getValueInRegistry(hSubKey, STD_NAME, &valueType,
392
szValue, &size);
393
if (ret != ERROR_SUCCESS) {
394
/*
395
* NT 4.0 SP3 fails here since it doesn't have the "Std"
396
* entry in the Time Zones registry.
397
*/
398
RegCloseKey(hSubKey);
399
onlyMapID = 1;
400
ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey);
401
if (ret != ERROR_SUCCESS) {
402
goto err;
403
}
404
break;
405
}
406
407
if (wcscmp((WCHAR *)szValue, stdNamePtr) == 0) {
408
/*
409
* Some localized Win32 platforms use a same name to
410
* different time zones. So, we can't rely only on the name
411
* here. We need to check GMT offsets and transition dates
412
* to make sure it's the registry of the current time
413
* zone.
414
*/
415
DWORD tziValueSize = sizeof(tempTzi);
416
ret = RegQueryValueEx(hSubKey, "TZI", NULL, &valueType,
417
(unsigned char *) &tempTzi, &tziValueSize);
418
if (ret == ERROR_SUCCESS) {
419
if ((tzi.Bias != tempTzi.bias) ||
420
(memcmp((const void *) &tzi.StandardDate,
421
(const void *) &tempTzi.stdDate,
422
sizeof(SYSTEMTIME)) != 0)) {
423
goto out;
424
}
425
426
if (tzi.DaylightBias != 0) {
427
if ((tzi.DaylightBias != tempTzi.dstBias) ||
428
(memcmp((const void *) &tzi.DaylightDate,
429
(const void *) &tempTzi.dstDate,
430
sizeof(SYSTEMTIME)) != 0)) {
431
goto out;
432
}
433
}
434
}
435
436
/*
437
* found matched record, terminate search
438
*/
439
strcpy(winZoneName, subKeyName);
440
break;
441
}
442
out:
443
(void) RegCloseKey(hSubKey);
444
}
445
446
/*
447
* Get the "MapID" value of the registry to be able to eliminate
448
* duplicated key names later.
449
*/
450
valueSize = MAX_MAPID_LENGTH;
451
ret = RegQueryValueExA(hSubKey, "MapID", NULL, &valueType, winMapID, &valueSize);
452
(void) RegCloseKey(hSubKey);
453
(void) RegCloseKey(hKey);
454
455
if (ret != ERROR_SUCCESS) {
456
/*
457
* Vista doesn't have mapID. VALUE_UNKNOWN should be returned
458
* only for Windows NT.
459
*/
460
if (onlyMapID == 1) {
461
return VALUE_UNKNOWN;
462
}
463
}
464
465
return VALUE_KEY;
466
467
err:
468
if (hKey != NULL) {
469
(void) RegCloseKey(hKey);
470
}
471
return VALUE_UNKNOWN;
472
}
473
474
/*
475
* The mapping table file name.
476
*/
477
#define MAPPINGS_FILE "\\lib\\tzmappings"
478
479
/*
480
* Index values for the mapping table.
481
*/
482
#define TZ_WIN_NAME 0
483
#define TZ_MAPID 1
484
#define TZ_REGION 2
485
#define TZ_JAVA_NAME 3
486
487
#define TZ_NITEMS 4 /* number of items (fields) */
488
489
/*
490
* Looks up the mapping table (tzmappings) and returns a Java time
491
* zone ID (e.g., "America/Los_Angeles") if found. Otherwise, NULL is
492
* returned.
493
*
494
* value_type is one of the following values:
495
* VALUE_KEY for exact key matching
496
* VALUE_MAPID for MapID (this is
497
* required for the old Windows, such as NT 4.0 SP3).
498
*/
499
static char *matchJavaTZ(const char *java_home_dir, int value_type, char *tzName,
500
char *mapID)
501
{
502
int line;
503
int IDmatched = 0;
504
FILE *fp;
505
char *javaTZName = NULL;
506
char *items[TZ_NITEMS];
507
char *mapFileName;
508
char lineBuffer[MAX_ZONE_CHAR * 4];
509
int noMapID = *mapID == '\0'; /* no mapID on Vista and later */
510
511
mapFileName = malloc(strlen(java_home_dir) + strlen(MAPPINGS_FILE) + 1);
512
if (mapFileName == NULL) {
513
return NULL;
514
}
515
strcpy(mapFileName, java_home_dir);
516
strcat(mapFileName, MAPPINGS_FILE);
517
518
if ((fp = fopen(mapFileName, "r")) == NULL) {
519
jio_fprintf(stderr, "can't open %s.\n", mapFileName);
520
free((void *) mapFileName);
521
return NULL;
522
}
523
free((void *) mapFileName);
524
525
line = 0;
526
while (fgets(lineBuffer, sizeof(lineBuffer), fp) != NULL) {
527
char *start, *idx, *endp;
528
int itemIndex = 0;
529
530
line++;
531
start = idx = lineBuffer;
532
endp = &lineBuffer[sizeof(lineBuffer)];
533
534
/*
535
* Ignore comment and blank lines.
536
*/
537
if (*idx == '#' || *idx == '\n') {
538
continue;
539
}
540
541
for (itemIndex = 0; itemIndex < TZ_NITEMS; itemIndex++) {
542
items[itemIndex] = start;
543
while (*idx && *idx != ':') {
544
if (++idx >= endp) {
545
goto illegal_format;
546
}
547
}
548
if (*idx == '\0') {
549
goto illegal_format;
550
}
551
*idx++ = '\0';
552
start = idx;
553
}
554
555
if (*idx != '\n') {
556
goto illegal_format;
557
}
558
559
if (noMapID || strcmp(mapID, items[TZ_MAPID]) == 0) {
560
/*
561
* When there's no mapID, we need to scan items until the
562
* exact match is found or the end of data is detected.
563
*/
564
if (!noMapID) {
565
IDmatched = 1;
566
}
567
if (strcmp(items[TZ_WIN_NAME], tzName) == 0) {
568
/*
569
* Found the time zone in the mapping table.
570
*/
571
javaTZName = _strdup(items[TZ_JAVA_NAME]);
572
break;
573
}
574
} else {
575
if (IDmatched == 1) {
576
/*
577
* No need to look up the mapping table further.
578
*/
579
break;
580
}
581
}
582
}
583
fclose(fp);
584
585
return javaTZName;
586
587
illegal_format:
588
(void) fclose(fp);
589
jio_fprintf(stderr, "tzmappings: Illegal format at line %d.\n", line);
590
return NULL;
591
}
592
593
/*
594
* Detects the platform time zone which maps to a Java time zone ID.
595
*/
596
char *findJavaTZ_md(const char *java_home_dir)
597
{
598
char winZoneName[MAX_ZONE_CHAR];
599
char winMapID[MAX_MAPID_LENGTH];
600
char *std_timezone = NULL;
601
int result;
602
603
winMapID[0] = 0;
604
result = getWinTimeZone(winZoneName, winMapID);
605
606
if (result != VALUE_UNKNOWN) {
607
if (result == VALUE_GMTOFFSET) {
608
std_timezone = _strdup(winZoneName);
609
} else {
610
std_timezone = matchJavaTZ(java_home_dir, result,
611
winZoneName, winMapID);
612
if (std_timezone == NULL) {
613
std_timezone = getGMTOffsetID();
614
}
615
}
616
}
617
return std_timezone;
618
}
619
620
/**
621
* Returns a GMT-offset-based time zone ID.
622
*/
623
char *
624
getGMTOffsetID()
625
{
626
LONG bias = 0;
627
LONG ret;
628
HANDLE hKey = NULL;
629
char zonename[32];
630
631
// Obtain the current GMT offset value of ActiveTimeBias.
632
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
633
KEY_READ, (PHKEY)&hKey);
634
if (ret == ERROR_SUCCESS) {
635
DWORD val;
636
DWORD bufSize = sizeof(val);
637
ULONG valueType = 0;
638
ret = RegQueryValueExA(hKey, "ActiveTimeBias",
639
NULL, &valueType, (LPBYTE) &val, &bufSize);
640
if (ret == ERROR_SUCCESS) {
641
bias = (LONG) val;
642
}
643
(void) RegCloseKey(hKey);
644
}
645
646
// If we can't get the ActiveTimeBias value, use Bias of TimeZoneInformation.
647
// Note: Bias doesn't reflect current daylight saving.
648
if (ret != ERROR_SUCCESS) {
649
TIME_ZONE_INFORMATION tzi;
650
if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
651
bias = tzi.Bias;
652
}
653
}
654
655
customZoneName(bias, zonename);
656
return _strdup(zonename);
657
}
658
659