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