1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott********************************************************************************
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott*   Copyright (C) 2005-2008, International Business Machines
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott*   Corporation and others.  All Rights Reserved.
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott********************************************************************************
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott*
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott* File WINTZ.CPP
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott*
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott********************************************************************************
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott*/
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "unicode/utypes.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifdef U_WINDOWS
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "wintz.h"
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "cmemory.h"
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "cstring.h"
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "unicode/ustring.h"
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "unicode/ures.h"
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#   define WIN32_LEAN_AND_MEAN
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#   define VC_EXTRALEAN
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#   define NOUSER
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#   define NOSERVICE
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#   define NOIME
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#   define NOMCX
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <windows.h>
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* The layout of the Tzi value in the registry */
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttypedef struct
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int32_t bias;
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int32_t standardBias;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int32_t daylightBias;
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SYSTEMTIME standardDate;
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SYSTEMTIME daylightDate;
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} TZI;
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/**
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Various registry keys and key fragments.
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char STANDARD_NAME_REGKEY[] = "StandardName";
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char STANDARD_TIME_REGKEY[] = " Standard Time";
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char TZI_REGKEY[] = "TZI";
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char STD_REGKEY[] = "Std";
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/**
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * HKLM subkeys used to probe for the flavor of Windows.  Note that we
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * specifically check for the "GMT" zone subkey; this is present on
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * NT, but on XP has become "GMT Standard Time".  We need to
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * discriminate between these cases.
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char* const WIN_TYPE_PROBE_REGKEY[] = {
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* WIN_9X_ME_TYPE */
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones",
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* WIN_NT_TYPE */
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT"
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* otherwise: WIN_2K_XP_TYPE */
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/**
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * The time zone root subkeys (under HKLM) for different flavors of
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Windows.
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char* const TZ_REGKEY[] = {
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* WIN_9X_ME_TYPE */
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\",
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* WIN_NT_TYPE | WIN_2K_XP_TYPE */
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/**
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Flavor of Windows, from our perspective.  Not a real OS version,
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * but rather the flavor of the layout of the time zone information in
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * the registry.
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottenum {
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    WIN_9X_ME_TYPE = 1,
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    WIN_NT_TYPE = 2,
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    WIN_2K_XP_TYPE = 3
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int32_t gWinType = 0;
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int32_t detectWindowsType()
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int32_t winType;
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LONG result;
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    HKEY hkey;
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* Detect the version of windows by trying to open a sequence of
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        probe keys.  We don't use the OS version API because what we
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        really want to know is how the registry is laid out.
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        Specifically, is it 9x/Me or not, and is it "GMT" or "GMT
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        Standard Time". */
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (winType = 0; winType < 2; winType++) {
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                              WIN_TYPE_PROBE_REGKEY[winType],
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                              0,
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                              KEY_QUERY_VALUE,
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                              &hkey);
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (result == ERROR_SUCCESS) {
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            RegCloseKey(hkey);
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            break;
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return winType+1; // +1 to bring it inline with the enum
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic LONG openTZRegKey(HKEY *hkey, const char *winid)
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char subKeyName[110]; /* TODO: why 96?? */
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char *name;
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LONG result;
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* This isn't thread safe, but it's good enough because the result should be constant per system. */
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (gWinType <= 0) {
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        gWinType = detectWindowsType();
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uprv_strcpy(subKeyName, TZ_REGKEY[(gWinType != WIN_9X_ME_TYPE)]);
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    name = &subKeyName[strlen(subKeyName)];
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uprv_strcat(subKeyName, winid);
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (gWinType == WIN_9X_ME_TYPE) {
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        /* Remove " Standard Time" */
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        char *pStd = uprv_strstr(subKeyName, STANDARD_TIME_REGKEY);
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (pStd) {
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            *pStd = 0;
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            subKeyName,
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            0,
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            KEY_QUERY_VALUE,
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            hkey);
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic LONG getTZI(const char *winid, TZI *tzi)
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DWORD cbData = sizeof(TZI);
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LONG result;
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    HKEY hkey;
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = openTZRegKey(&hkey, winid);
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (result == ERROR_SUCCESS) {
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = RegQueryValueExA(hkey,
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    TZI_REGKEY,
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    NULL,
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    NULL,
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    (LPBYTE)tzi,
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    &cbData);
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        RegCloseKey(hkey);
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  This code attempts to detect the Windows time zone, as set in the
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Windows Date and Time control panel.  It attempts to work on
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  installs.  It works by directly interrogating the registry and
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  comparing the data there with the data returned by the
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GetTimeZoneInformation API, along with some other strategies.  The
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  registry contains time zone data under one of two keys (depending on
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  the flavor of Windows):
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Under this key are several subkeys, one for each time zone.  These
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  subkeys are named "Pacific" on Win9x/Me and "Pacific Standard Time"
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  on WinNT/2k/XP.  There are some other wrinkles; see the code for
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  details.  The subkey name is NOT LOCALIZED, allowing us to support
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  localized installs.
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Under the subkey are data values.  We care about:
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Std   Standard time display name, localized
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    TZI   Binary block of data
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  The TZI data is of particular interest.  It contains the offset, two
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  more offsets for standard and daylight time, and the start and end
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rules.  This is the same data returned by the GetTimeZoneInformation
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  API.  The API may modify the data on the way out, so we have to be
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  careful, but essentially we do a binary comparison against the TZI
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  blocks of various registry keys.  When we find a match, we know what
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  time zone Windows is set to.  Since the registry key is not
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  localized, we can then translate the key through a simple table
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lookup into the corresponding ICU time zone.
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  This strategy doesn't always work because there are zones which
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  share an offset and rules, so more than one TZI block will match.
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  For example, both Tokyo and Seoul are at GMT+9 with no DST rules;
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  their TZI blocks are identical.  For these cases, we fall back to a
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  name lookup.  We attempt to match the display name as stored in the
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  registry for the current zone to the display name stored in the
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  registry for various Windows zones.  By comparing the registry data
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  directly we avoid conversion complications.
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Author: Alan Liu
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Since: ICU 2.6
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Based on original code by Carl Brown <cbrown@xnetinc.com>
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott*/
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/**
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Main Windows time zone detection function.  Returns the Windows
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * time zone, translated to an ICU time zone, or NULL upon failure.
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottU_CFUNC const char* U_EXPORT2
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottuprv_detectWindowsTimeZone() {
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    UErrorCode status = U_ZERO_ERROR;
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    UResourceBundle* bundle = NULL;
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char* icuid = NULL;
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LONG result;
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    TZI tziKey;
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    TZI tziReg;
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    TIME_ZONE_INFORMATION apiTZI;
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* Obtain TIME_ZONE_INFORMATION from the API, and then convert it
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       to TZI.  We could also interrogate the registry directly; we do
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       this below if needed. */
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uprv_memset(&apiTZI, 0, sizeof(apiTZI));
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uprv_memset(&tziKey, 0, sizeof(tziKey));
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uprv_memset(&tziReg, 0, sizeof(tziReg));
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    GetTimeZoneInformation(&apiTZI);
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tziKey.bias = apiTZI.Bias;
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uprv_memcpy((char *)&tziKey.standardDate, (char*)&apiTZI.StandardDate,
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott           sizeof(apiTZI.StandardDate));
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate,
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott           sizeof(apiTZI.DaylightDate));
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bundle = ures_openDirect(NULL, "supplementalData", &status);
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bundle = ures_getByKey(bundle, "mapTimezones", bundle, &status);
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bundle = ures_getByKey(bundle, "windows", bundle, &status);
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    /* Note: We get the winid not from static tables but from resource bundle. */
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (U_SUCCESS(status) && ures_hasNext(bundle)) {
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        const char* winid;
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        int32_t len;
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status);
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (U_FAILURE(status)) {
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            break;
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        winid = ures_getKey(winTZ);
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = getTZI(winid, &tziReg);
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (result == ERROR_SUCCESS) {
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            /* Windows alters the DaylightBias in some situations.
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               Using the bias and the rules suffices, so overwrite
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               these unreliable fields. */
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            tziKey.standardBias = tziReg.standardBias;
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            tziKey.daylightBias = tziReg.daylightBias;
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) {
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                const UChar* icuTZ = ures_getString(winTZ, &len, &status);
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                if (U_SUCCESS(status)) {
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    icuid = (char*)uprv_malloc(sizeof(char) * (len + 1));
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    uprv_memset(icuid, 0, len + 1);
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    u_austrncpy(icuid, icuTZ, len);
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                }
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            }
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        ures_close(winTZ);
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (icuid != NULL) {
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            break;
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ures_close(bundle);
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return icuid;
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif /* #ifdef U_WINDOWS */
290