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
40 #define NT_TZ_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
41 #define WIN_TZ_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones"
42 #define WIN_CURRENT_TZ_KEY "System\\CurrentControlSet\\Control\\TimeZoneInformation"
43
44 typedef struct _TziValue {
45 LONG bias;
46 LONG stdBias;
47 LONG dstBias;
48 SYSTEMTIME stdDate;
49 SYSTEMTIME dstDate;
50 } TziValue;
51
52 /*
53 * Registry key names
54 */
55 static void *keyNames[] = {
56 (void *) L"StandardName",
57 (void *) "StandardName",
58 (void *) L"Std",
128 if (bias > 0) {
129 gmtOffset = bias;
130 sign = -1;
131 } else {
132 gmtOffset = -bias;
133 sign = 1;
134 }
135 if (gmtOffset != 0) {
136 sprintf(buffer, "GMT%c%02d:%02d",
137 ((sign >= 0) ? '+' : '-'),
138 gmtOffset / 60,
139 gmtOffset % 60);
140 } else {
141 strcpy(buffer, "GMT");
142 }
143 }
144
145 /*
146 * Gets the current time zone entry in the "Time Zones" registry.
147 */
148 static int getWinTimeZone(char *winZoneName, char *winMapID)
149 {
150 DYNAMIC_TIME_ZONE_INFORMATION dtzi;
151 DWORD timeType;
152 DWORD bufSize;
153 DWORD val;
154 HANDLE hKey = NULL;
155 LONG ret;
156 ULONG valueType;
157
158 /*
159 * Get the dynamic time zone information so that time zone redirection
160 * can be supported. (see JDK-7044727)
161 */
162 timeType = GetDynamicTimeZoneInformation(&dtzi);
163 if (timeType == TIME_ZONE_ID_INVALID) {
164 goto err;
165 }
166
167 /*
168 * Make sure TimeZoneKeyName is available from the API call. If
214 ret = RegQueryValueExA(hKey, "TimeZoneKeyName", NULL,
215 &valueType, (LPBYTE) winZoneName, &bufSize);
216 if (ret != ERROR_SUCCESS) {
217 goto err;
218 }
219 (void) RegCloseKey(hKey);
220 return VALUE_KEY;
221 } else {
222 /*
223 * Fall back to GetTimeZoneInformation
224 */
225 TIME_ZONE_INFORMATION tzi;
226 HANDLE hSubKey = NULL;
227 DWORD nSubKeys, i;
228 ULONG valueType;
229 TCHAR subKeyName[MAX_ZONE_CHAR];
230 TCHAR szValue[MAX_ZONE_CHAR];
231 WCHAR stdNameInReg[MAX_ZONE_CHAR];
232 TziValue tempTzi;
233 WCHAR *stdNamePtr = tzi.StandardName;
234 DWORD valueSize;
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);
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 /*
376 * Get the "MapID" value of the registry to be able to eliminate
377 * duplicated key names later.
378 */
379 valueSize = MAX_MAPID_LENGTH;
380 ret = RegQueryValueExA(hSubKey, "MapID", NULL, &valueType, winMapID, &valueSize);
381 (void) RegCloseKey(hSubKey);
382 (void) RegCloseKey(hKey);
383
384 if (ret != ERROR_SUCCESS) {
385 /*
386 * Vista doesn't have mapID. VALUE_UNKNOWN should be returned
387 * only for Windows NT.
388 */
389 if (onlyMapID == 1) {
390 return VALUE_UNKNOWN;
391 }
392 }
393 }
394
395 return VALUE_KEY;
396
397 err:
398 if (hKey != NULL) {
399 (void) RegCloseKey(hKey);
400 }
401 return VALUE_UNKNOWN;
402 }
403
404 /*
405 * The mapping table file name.
406 */
407 #define MAPPINGS_FILE "\\lib\\tzmappings"
408
409 /*
410 * Index values for the mapping table.
411 */
412 #define TZ_WIN_NAME 0
413 #define TZ_MAPID 1
414 #define TZ_REGION 2
415 #define TZ_JAVA_NAME 3
416
417 #define TZ_NITEMS 4 /* number of items (fields) */
418
419 /*
420 * Looks up the mapping table (tzmappings) and returns a Java time
421 * zone ID (e.g., "America/Los_Angeles") if found. Otherwise, NULL is
422 * returned.
423 *
424 * value_type is one of the following values:
425 * VALUE_KEY for exact key matching
426 * VALUE_MAPID for MapID (this is
427 * required for the old Windows, such as NT 4.0 SP3).
428 */
429 static char *matchJavaTZ(const char *java_home_dir, int value_type, char *tzName,
430 char *mapID)
431 {
432 int line;
433 int IDmatched = 0;
434 FILE *fp;
435 char *javaTZName = NULL;
436 char *items[TZ_NITEMS];
437 char *mapFileName;
438 char lineBuffer[MAX_ZONE_CHAR * 4];
439 int noMapID = *mapID == '\0'; /* no mapID on Vista and later */
440 int offset = 0;
441 const char* errorMessage = "unknown error";
442
443 mapFileName = malloc(strlen(java_home_dir) + strlen(MAPPINGS_FILE) + 1);
444 if (mapFileName == NULL) {
445 return NULL;
446 }
447 strcpy(mapFileName, java_home_dir);
448 strcat(mapFileName, MAPPINGS_FILE);
449
450 if ((fp = fopen(mapFileName, "r")) == NULL) {
451 jio_fprintf(stderr, "can't open %s.\n", mapFileName);
452 free((void *) mapFileName);
453 return NULL;
454 }
455 free((void *) mapFileName);
456
457 line = 0;
458 while (fgets(lineBuffer, sizeof(lineBuffer), fp) != NULL) {
459 char *start, *idx, *endp;
460 int itemIndex = 0;
461
477 errorMessage = "premature end of line";
478 offset = (int)(idx - lineBuffer);
479 goto illegal_format;
480 }
481 }
482 if (*idx == '\0') {
483 errorMessage = "illegal null character found";
484 offset = (int)(idx - lineBuffer);
485 goto illegal_format;
486 }
487 *idx++ = '\0';
488 start = idx;
489 }
490
491 if (*idx != '\n') {
492 errorMessage = "illegal non-newline character found";
493 offset = (int)(idx - lineBuffer);
494 goto illegal_format;
495 }
496
497 if (noMapID || strcmp(mapID, items[TZ_MAPID]) == 0) {
498 /*
499 * When there's no mapID, we need to scan items until the
500 * exact match is found or the end of data is detected.
501 */
502 if (!noMapID) {
503 IDmatched = 1;
504 }
505 if (strcmp(items[TZ_WIN_NAME], tzName) == 0) {
506 /*
507 * Found the time zone in the mapping table.
508 */
509 javaTZName = _strdup(items[TZ_JAVA_NAME]);
510 break;
511 }
512 } else {
513 if (IDmatched == 1) {
514 /*
515 * No need to look up the mapping table further.
516 */
517 break;
518 }
519 }
520 }
521 fclose(fp);
522
523 return javaTZName;
524
525 illegal_format:
526 (void) fclose(fp);
527 jio_fprintf(stderr, "Illegal format in tzmappings file: %s at line %d, offset %d.\n",
528 errorMessage, line, offset);
529 return NULL;
530 }
531
532 /*
533 * Detects the platform time zone which maps to a Java time zone ID.
534 */
535 char *findJavaTZ_md(const char *java_home_dir)
536 {
537 char winZoneName[MAX_ZONE_CHAR];
538 char winMapID[MAX_MAPID_LENGTH];
539 char *std_timezone = NULL;
540 int result;
541
542 winMapID[0] = 0;
543 result = getWinTimeZone(winZoneName, winMapID);
544
545 if (result != VALUE_UNKNOWN) {
546 if (result == VALUE_GMTOFFSET) {
547 std_timezone = _strdup(winZoneName);
548 } else {
549 std_timezone = matchJavaTZ(java_home_dir, result,
550 winZoneName, winMapID);
551 if (std_timezone == NULL) {
552 std_timezone = getGMTOffsetID();
553 }
554 }
555 }
556 return std_timezone;
557 }
558
559 /**
560 * Returns a GMT-offset-based time zone ID.
561 */
562 char *
563 getGMTOffsetID()
564 {
565 LONG bias = 0;
566 LONG ret;
567 HANDLE hKey = NULL;
568 char zonename[32];
569
570 // Obtain the current GMT offset value of ActiveTimeBias.
|
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",
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
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);
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
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.
|