Ignore:
Timestamp:
Dec 23, 2010, 6:54:11 AM (15 years ago)
Author:
dmik
Message:

Deduce Windows Time Zone information from the TZ environment variable.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/initsystem.cpp

    r6129 r21535  
    2222#include "cpuhlp.h"
    2323#include <odininst.h>
    24 #include <win\options.h>
     24#include <win/options.h>
     25#include <win/winnls.h>
    2526#include "directory.h"
    2627#include <versionos2.h>
     
    101102void InitDynamicRegistry()
    102103{
    103  OSVERSIONINFOA versioninfo;
    104  HKEY           hkey;
    105  char           buf[16] = "";
     104    OSVERSIONINFOA versioninfo;
     105    HKEY           hkey;
     106    char           buf[16] = "";
    106107
    107108    versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
     
    112113    // "ProductType"="WinNT"
    113114    if(RegCreateKeyA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",&hkey)!=ERROR_SUCCESS) {
    114         dprintf(("InitRegistry: Unable to register system information (2)"));
    115             return;
     115        dprintf(("InitRegistry: Unable to register system information (2)"));
     116        return;
    116117    }
    117118    switch(versioninfo.dwPlatformId) {
     
    128129    RegSetValueExA(hkey,"ProductType",0,REG_SZ, (LPBYTE)buf, strlen(buf)+1);
    129130    RegCloseKey(hkey);
     131
     132    // Deduce the Windows time zone from TZ
     133    const char *tz = getenv("TZ");
     134    if (tz == NULL) {
     135        if (RegCreateKeyA(HKEY_LOCAL_MACHINE,
     136                          "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation",
     137                          &hkey) == ERROR_SUCCESS) {
     138            // use the last value
     139            RegCloseKey(hkey);
     140            return;
     141        }
     142        //default is Central European Time
     143        tz = "CET-1CDT";
     144    }
     145
     146    char *tzBuf = strdup(tz);
     147    if (!tzBuf) {
     148        dprintf(("InitRegistry: Unable to allocate memory"));
     149        return;
     150    }
     151
     152    TIME_ZONE_INFORMATION tzi;
     153    memset(&tzi, 0, sizeof(tzi));
     154    dprintf(("InitRegistry: TZ=%s", tzBuf));
     155
     156    int state = 0;
     157    char *tok = strtok(tzBuf, ",");
     158    for (; tok && state != -1; state++, tok = strtok(NULL, ",")) {
     159        switch (state) {
     160        case 0: {
     161            // STD bias(sec) DST
     162            char *s = tok;
     163            while (isalpha(*s))
     164                ++s;
     165            if (s - tok == 3) {
     166                MultiByteToWideChar(CP_ACP, 0, tok, 3, tzi.StandardName,
     167                                    sizeof(tzi.StandardName));
     168                char *fail;
     169                long n = strtol(s, &fail, 10);
     170                s = fail;
     171                if (*s)
     172                    while (*s && isalpha(*s))
     173                        ++s;
     174                if (!*s) {
     175                    MultiByteToWideChar(CP_ACP, 0, fail, -1, tzi.DaylightName, sizeof(tzi.DaylightName));
     176                    tzi.Bias = n * 60;
     177                } else {
     178                    state = -1;
     179                }
     180            } else {
     181                state = -1;
     182            }
     183            break;
     184        }
     185        // the rest has the following format:
     186        // DST_m,DST_n,DST_w,DST_t,STD_m,STD_n,STD_w,STD_t,DST_bias
     187        // where _m is month, _w is day of week, _n is the occurence
     188        // of this day, _t is the time (sec)
     189        case 1:
     190        case 5: {
     191            // month
     192            char *fail;
     193            long n = strtol(tok, &fail, 10);
     194            if (*fail == 0 && n >= 1 && n <= 12) {
     195                state == 1 ? tzi.DaylightDate.wMonth = n
     196                           : tzi.StandardDate.wMonth = n;
     197            } else {
     198                state = -1;
     199            }
     200            break;
     201        }
     202        case 2:
     203        case 6: {
     204            // occurence
     205            char *fail;
     206            long n = strtol(tok, &fail, 10);
     207            if (*fail == 0 && (n >= 1 && n <= 5) || n == -1) {
     208                if (n == -1)
     209                    n = 5; // this is what Windows expect
     210                state == 2 ? tzi.DaylightDate.wDay = n
     211                           : tzi.StandardDate.wDay = n;
     212            } else {
     213                state = -1;
     214            }
     215            break;
     216        }
     217        case 3:
     218        case 7: {
     219            // day of week
     220            char *fail;
     221            long n = strtol(tok, &fail, 10);
     222            if (*fail == 0 && n >= 0 && n <= 6) {
     223                state == 3 ? tzi.DaylightDate.wDayOfWeek = n
     224                           : tzi.StandardDate.wDayOfWeek = n;
     225            } else {
     226                state = -1;
     227            }
     228            break;
     229        }
     230        case 4:
     231        case 8: {
     232            // time (sec)
     233            char *fail;
     234            long n = strtol(tok, &fail, 10);
     235            if (*fail == 0 && n >= 0) {
     236                SYSTEMTIME *t = state == 4 ? &tzi.DaylightDate
     237                                           : &tzi.StandardDate;
     238                t->wHour = n / 3600;
     239                t->wMinute = (n % 3600) / 60;
     240            } else {
     241                state = -1;
     242            }
     243            break;
     244        }
     245        case 9: {
     246            // daylight bias (sec)
     247            char *fail;
     248            long n = strtol(tok, &fail, 10);
     249            if (*fail == 0) {
     250                tzi.DaylightBias = - (n / 60);
     251            } else {
     252                state = -1;
     253            }
     254            break;
     255        }
     256        default:
     257            state = -1;
     258            break;
     259        }
     260    }
     261
     262    free(tzBuf);
     263    if (state == -1 || (state != 1 && state != 10)) {
     264        dprintf(("InitRegistry: Unable to parse TZ"));
     265        return;
     266    }
     267
     268    // apply the daylight bias to the standard start time
     269    // (windows expects this)
     270    if (tzi.DaylightBias) {
     271        DWORD min = tzi.StandardDate.wHour * 60 + tzi.StandardDate.wMinute;
     272        min -= tzi.DaylightBias;
     273        tzi.StandardDate.wHour = min / 60;
     274        tzi.StandardDate.wMinute = min % 60;
     275    }
     276
     277    dprintf(("InitRegistry: Bias         %d", tzi.Bias));
     278    dprintf(("InitRegistry: StandardName '%ls'", tzi.StandardName));
     279    dprintf(("InitRegistry: StandardDate %d,%d,%d,%d:%d",
     280             tzi.StandardDate.wMonth, tzi.StandardDate.wDay,
     281             tzi.StandardDate.wDayOfWeek,
     282             tzi.StandardDate.wHour, tzi.StandardDate.wMinute));
     283    dprintf(("InitRegistry: StandardBias %d", tzi.StandardBias));
     284    dprintf(("InitRegistry: DaylightName '%ls'", tzi.DaylightName));
     285    dprintf(("InitRegistry: DaylightDate %d,%d,%d,%d:%d",
     286             tzi.DaylightDate.wMonth, tzi.DaylightDate.wDay,
     287             tzi.DaylightDate.wDayOfWeek,
     288             tzi.DaylightDate.wHour, tzi.DaylightDate.wMinute));
     289    dprintf(("InitRegistry: DaylightBias %d", tzi.DaylightBias));
     290
     291    struct REG_TZI_FORMAT {
     292        LONG Bias;
     293        LONG StandardBias;
     294        LONG DaylightBias;
     295        SYSTEMTIME StandardDate;
     296        SYSTEMTIME DaylightDate;
     297    } rtzi, rtzitmp;
     298
     299    memset(&rtzi, 0, sizeof(rtzi));
     300    rtzi.Bias = tzi.Bias;
     301    rtzi.StandardBias = tzi.StandardBias;
     302    rtzi.DaylightBias = tzi.DaylightBias;
     303    rtzi.StandardDate = tzi.StandardDate;
     304    rtzi.DaylightDate = tzi.DaylightDate;
     305
     306    DWORD bestMatch = 0;
     307    if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
     308                    "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
     309                    &hkey) == ERROR_SUCCESS) {
     310        DWORD idx = 0;
     311        char name[256];
     312        DWORD len;
     313        for (;; idx++) {
     314            len = sizeof(name);
     315            if (RegEnumKeyExA(hkey, idx, name, &len, NULL, NULL, NULL,
     316                              NULL) != ERROR_SUCCESS)
     317                    break;
     318
     319            HKEY hsubkey;
     320            DWORD len;
     321            if (RegOpenKeyA(hkey, name, &hsubkey) == ERROR_SUCCESS) {
     322                len = sizeof(rtzitmp);
     323                if (RegQueryValueExA(hsubkey, "TZI", NULL, NULL,
     324                                     (LPBYTE)&rtzitmp, &len) == ERROR_SUCCESS) {
     325                    DWORD match = 0;
     326                    if (rtzi.Bias == rtzitmp.Bias) {
     327                        match = 1;
     328                        if (rtzi.StandardBias == rtzitmp.StandardBias &&
     329                            rtzi.DaylightBias == rtzitmp.DaylightBias) {
     330                            match = 2;
     331                            if (memcmp(&rtzi.StandardDate, &rtzitmp.StandardDate,
     332                                       sizeof(rtzi.StandardDate)) == 0 &&
     333                                    memcmp(&rtzi.DaylightDate, &rtzitmp.DaylightDate,
     334                                           sizeof(rtzi.DaylightDate)) == 0) {
     335                                match = 3;
     336                            }
     337                        }
     338                    }
     339                    if (match > bestMatch) {
     340                        len = sizeof(tzi.StandardName);
     341                        if (RegQueryValueExW(hsubkey, (LPCWSTR)L"Std", NULL, NULL,
     342                                             (LPBYTE)tzi.StandardName, &len) == ERROR_SUCCESS) {
     343                            len = sizeof(tzi.DaylightName);
     344                            if (RegQueryValueExW(hsubkey, (LPCWSTR)L"Dlt", NULL, NULL,
     345                                                 (LPBYTE)tzi.DaylightName, &len) == ERROR_SUCCESS) {
     346                                tzi.StandardName[sizeof(tzi.StandardName) - 1] = '\0';
     347                                tzi.DaylightName[sizeof(tzi.DaylightName) - 1] = '\0';
     348                                // copy the found data over (it may be more precise)
     349                                tzi.Bias = rtzitmp.Bias;
     350                                tzi.StandardBias = rtzitmp.StandardBias;
     351                                tzi.DaylightBias = rtzitmp.DaylightBias;
     352                                tzi.StandardDate = rtzitmp.StandardDate;
     353                                tzi.DaylightDate = rtzitmp.DaylightDate;
     354
     355                                bestMatch = match;
     356                            }
     357                        }
     358                    }
     359                }
     360                RegCloseKey(hsubkey);
     361            }
     362        }
     363        RegCloseKey(hkey);
     364    }
     365
     366    if (bestMatch) {
     367        dprintf(("InitRegistry: Found Windows Time Zone (best match %d):", bestMatch));
     368        dprintf(("InitRegistry: StandardName '%ls'", tzi.StandardName));
     369        dprintf(("InitRegistry: DaylightName '%ls'", tzi.DaylightName));
     370    } else {
     371        dprintf(("InitRegistry: WARNING: Couldn't match TZ to Windows Time Zone."));
     372        dprintf(("InitRegistry: Check 'HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones' key."));
     373    }
     374
     375    SetTimeZoneInformation (&tzi);
    130376}
    131377//******************************************************************************
Note: See TracChangeset for help on using the changeset viewer.