OLD | NEW |
1 /* | 1 /* |
2 ******************************************************************************** | 2 ******************************************************************************** |
3 * Copyright (C) 2005-2013, International Business Machines | 3 * Copyright (C) 2005-2014, International Business Machines |
4 * Corporation and others. All Rights Reserved. | 4 * Corporation and others. All Rights Reserved. |
5 ******************************************************************************** | 5 ******************************************************************************** |
6 * | 6 * |
7 * File WINTZ.CPP | 7 * File WINTZ.CPP |
8 * | 8 * |
9 ******************************************************************************** | 9 ******************************************************************************** |
10 */ | 10 */ |
11 | 11 |
12 #include "unicode/utypes.h" | 12 #include "unicode/utypes.h" |
13 | 13 |
14 #if U_PLATFORM_HAS_WIN32_API | 14 #if U_PLATFORM_HAS_WIN32_API |
15 | 15 |
16 #include "wintz.h" | 16 #include "wintz.h" |
17 #include "cmemory.h" | 17 #include "cmemory.h" |
18 #include "cstring.h" | 18 #include "cstring.h" |
19 | 19 |
| 20 #include "unicode/ures.h" |
20 #include "unicode/ustring.h" | 21 #include "unicode/ustring.h" |
21 #include "unicode/ures.h" | |
22 | 22 |
23 # define WIN32_LEAN_AND_MEAN | 23 # define WIN32_LEAN_AND_MEAN |
24 # define VC_EXTRALEAN | 24 # define VC_EXTRALEAN |
25 # define NOUSER | 25 # define NOUSER |
26 # define NOSERVICE | 26 # define NOSERVICE |
27 # define NOIME | 27 # define NOIME |
28 # define NOMCX | 28 # define NOMCX |
29 #include <windows.h> | 29 #include <windows.h> |
30 | 30 |
31 #define MAX_LENGTH_ID 40 | 31 #define MAX_LENGTH_ID 40 |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 (LPBYTE)regStdName, | 186 (LPBYTE)regStdName, |
187 &cbData); | 187 &cbData); |
188 | 188 |
189 } | 189 } |
190 | 190 |
191 RegCloseKey(hkey); | 191 RegCloseKey(hkey); |
192 | 192 |
193 return result; | 193 return result; |
194 } | 194 } |
195 | 195 |
| 196 static LONG getTZKeyName(char* tzKeyName, int32_t length) { |
| 197 HKEY hkey; |
| 198 LONG result = FALSE; |
| 199 DWORD cbData = length; |
| 200 |
| 201 if(ERROR_SUCCESS == RegOpenKeyExA( |
| 202 HKEY_LOCAL_MACHINE, |
| 203 CURRENT_ZONE_REGKEY, |
| 204 0, |
| 205 KEY_QUERY_VALUE, |
| 206 &hkey)) |
| 207 { |
| 208 result = RegQueryValueExA( |
| 209 hkey, |
| 210 "TimeZoneKeyName", |
| 211 NULL, |
| 212 NULL, |
| 213 (LPBYTE)tzKeyName, |
| 214 &cbData); |
| 215 } |
| 216 |
| 217 return result; |
| 218 } |
| 219 |
196 /* | 220 /* |
197 This code attempts to detect the Windows time zone, as set in the | 221 This code attempts to detect the Windows time zone, as set in the |
198 Windows Date and Time control panel. It attempts to work on | 222 Windows Date and Time control panel. It attempts to work on |
199 multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized | 223 multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized |
200 installs. It works by directly interrogating the registry and | 224 installs. It works by directly interrogating the registry and |
201 comparing the data there with the data returned by the | 225 comparing the data there with the data returned by the |
202 GetTimeZoneInformation API, along with some other strategies. The | 226 GetTimeZoneInformation API, along with some other strategies. The |
203 registry contains time zone data under one of two keys (depending on | 227 registry contains time zone data under one of two keys (depending on |
204 the flavor of Windows): | 228 the flavor of Windows): |
205 | 229 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 | 267 |
244 /** | 268 /** |
245 * Main Windows time zone detection function. Returns the Windows | 269 * Main Windows time zone detection function. Returns the Windows |
246 * time zone, translated to an ICU time zone, or NULL upon failure. | 270 * time zone, translated to an ICU time zone, or NULL upon failure. |
247 */ | 271 */ |
248 U_CFUNC const char* U_EXPORT2 | 272 U_CFUNC const char* U_EXPORT2 |
249 uprv_detectWindowsTimeZone() { | 273 uprv_detectWindowsTimeZone() { |
250 UErrorCode status = U_ZERO_ERROR; | 274 UErrorCode status = U_ZERO_ERROR; |
251 UResourceBundle* bundle = NULL; | 275 UResourceBundle* bundle = NULL; |
252 char* icuid = NULL; | 276 char* icuid = NULL; |
253 UChar apiStd[MAX_LENGTH_ID]; | |
254 char apiStdName[MAX_LENGTH_ID]; | 277 char apiStdName[MAX_LENGTH_ID]; |
255 char regStdName[MAX_LENGTH_ID]; | 278 char regStdName[MAX_LENGTH_ID]; |
256 char tmpid[MAX_LENGTH_ID]; | 279 char tmpid[MAX_LENGTH_ID]; |
257 int32_t len; | 280 int32_t len; |
258 int id; | 281 int id; |
259 int errorCode; | 282 int errorCode; |
260 char ISOcode[3]; /* 2 letter iso code */ | 283 UChar ISOcodeW[3]; /* 2 letter iso code in UTF-16*/ |
| 284 char ISOcodeA[3]; /* 2 letter iso code in ansi */ |
261 | 285 |
262 LONG result; | 286 LONG result; |
263 TZI tziKey; | 287 TZI tziKey; |
264 TZI tziReg; | 288 TZI tziReg; |
265 TIME_ZONE_INFORMATION apiTZI; | 289 TIME_ZONE_INFORMATION apiTZI; |
266 | 290 |
| 291 BOOL isVistaOrHigher; |
| 292 BOOL tryPreVistaFallback; |
| 293 OSVERSIONINFO osVerInfo; |
| 294 |
267 /* Obtain TIME_ZONE_INFORMATION from the API, and then convert it | 295 /* Obtain TIME_ZONE_INFORMATION from the API, and then convert it |
268 to TZI. We could also interrogate the registry directly; we do | 296 to TZI. We could also interrogate the registry directly; we do |
269 this below if needed. */ | 297 this below if needed. */ |
270 uprv_memset(&apiTZI, 0, sizeof(apiTZI)); | 298 uprv_memset(&apiTZI, 0, sizeof(apiTZI)); |
271 uprv_memset(&tziKey, 0, sizeof(tziKey)); | 299 uprv_memset(&tziKey, 0, sizeof(tziKey)); |
272 uprv_memset(&tziReg, 0, sizeof(tziReg)); | 300 uprv_memset(&tziReg, 0, sizeof(tziReg)); |
273 GetTimeZoneInformation(&apiTZI); | 301 GetTimeZoneInformation(&apiTZI); |
274 tziKey.bias = apiTZI.Bias; | 302 tziKey.bias = apiTZI.Bias; |
275 uprv_memcpy((char *)&tziKey.standardDate, (char*)&apiTZI.StandardDate, | 303 uprv_memcpy((char *)&tziKey.standardDate, (char*)&apiTZI.StandardDate, |
276 sizeof(apiTZI.StandardDate)); | 304 sizeof(apiTZI.StandardDate)); |
277 uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate, | 305 uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate, |
278 sizeof(apiTZI.DaylightDate)); | 306 sizeof(apiTZI.DaylightDate)); |
279 | 307 |
280 /* Convert the wchar_t* standard name to char* */ | 308 /* Convert the wchar_t* standard name to char* */ |
281 uprv_memset(apiStdName, 0, sizeof(apiStdName)); | 309 uprv_memset(apiStdName, 0, sizeof(apiStdName)); |
282 u_strFromWCS(apiStd, MAX_LENGTH_ID, NULL, apiTZI.StandardName, -1, &status); | 310 wcstombs(apiStdName, apiTZI.StandardName, MAX_LENGTH_ID); |
283 u_austrncpy(apiStdName, apiStd, sizeof(apiStdName) - 1); | |
284 | 311 |
285 tmpid[0] = 0; | 312 tmpid[0] = 0; |
286 | 313 |
287 id = GetUserGeoID(GEOCLASS_NATION); | 314 id = GetUserGeoID(GEOCLASS_NATION); |
288 errorCode = GetGeoInfoA(id,GEO_ISO2,ISOcode,3,0); | 315 errorCode = GetGeoInfoW(id,GEO_ISO2,ISOcodeW,3,0); |
| 316 u_strToUTF8(ISOcodeA, 3, NULL, ISOcodeW, 3, &status); |
289 | 317 |
290 bundle = ures_openDirect(NULL, "windowsZones", &status); | 318 bundle = ures_openDirect(NULL, "windowsZones", &status); |
291 ures_getByKey(bundle, "mapTimezones", bundle, &status); | 319 ures_getByKey(bundle, "mapTimezones", bundle, &status); |
292 | 320 |
293 /* Note: We get the winid not from static tables but from resource bundle. *
/ | 321 /* |
294 while (U_SUCCESS(status) && ures_hasNext(bundle)) { | 322 Windows Vista+ provides us with a "TimeZoneKeyName" that is not localize
d |
295 UBool idFound = FALSE; | 323 and can be used to directly map a name in our bundle. Try to use that fi
rst |
296 const char* winid; | 324 if we're on Vista or higher |
297 UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status); | 325 */ |
298 if (U_FAILURE(status)) { | 326 uprv_memset(&osVerInfo, 0, sizeof(osVerInfo)); |
299 break; | 327 osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo); |
300 } | 328 GetVersionEx(&osVerInfo); |
301 winid = ures_getKey(winTZ); | 329 isVistaOrHigher = osVerInfo.dwMajorVersion >= 6;» /* actually includes Win
dows Server 2008 as well, but don't worry about it */ |
302 result = getTZI(winid, &tziReg); | 330 tryPreVistaFallback = TRUE; |
303 | 331 if(isVistaOrHigher) { |
304 if (result == ERROR_SUCCESS) { | 332 result = getTZKeyName(regStdName, sizeof(regStdName)); |
305 /* Windows alters the DaylightBias in some situations. | 333 if(ERROR_SUCCESS == result) { |
306 Using the bias and the rules suffices, so overwrite | 334 UResourceBundle* winTZ = ures_getByKey(bundle, regStdName, NULL, &st
atus); |
307 these unreliable fields. */ | 335 if(U_SUCCESS(status)) { |
308 tziKey.standardBias = tziReg.standardBias; | |
309 tziKey.daylightBias = tziReg.daylightBias; | |
310 | |
311 if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) ==
0) { | |
312 const UChar* icuTZ = NULL; | 336 const UChar* icuTZ = NULL; |
313 if (errorCode != 0) { | 337 if (errorCode != 0) { |
314 icuTZ = ures_getStringByKey(winTZ, ISOcode, &len, &status); | 338 icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status); |
315 } | 339 } |
316 if (errorCode==0 || icuTZ==NULL) { | 340 if (errorCode==0 || icuTZ==NULL) { |
317 /* fallback to default "001" and reset status */ | 341 /* fallback to default "001" and reset status */ |
318 status = U_ZERO_ERROR; | 342 status = U_ZERO_ERROR; |
319 icuTZ = ures_getStringByKey(winTZ, "001", &len, &status); | 343 icuTZ = ures_getStringByKey(winTZ, "001", &len, &status); |
320 } | 344 } |
321 | 345 |
322 if (U_SUCCESS(status)) { | 346 if(U_SUCCESS(status)) { |
323 /* Get the standard name from the registry key to compare wi
th | 347 int index=0; |
324 the one from Windows API call. */ | 348 while (! (*icuTZ == '\0' || *icuTZ ==' ')) { |
325 uprv_memset(regStdName, 0, sizeof(regStdName)); | 349 tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'cha
r' is ASCII compatible on windows */ |
326 result = getSTDName(winid, regStdName, sizeof(regStdName)); | 350 } |
327 if (result == ERROR_SUCCESS) { | 351 tmpid[index]='\0'; |
328 if (uprv_strcmp(apiStdName, regStdName) == 0) { | 352 tryPreVistaFallback = FALSE; |
329 idFound = TRUE; | 353 } |
330 } | 354 } |
| 355 } |
| 356 } |
| 357 |
| 358 if(tryPreVistaFallback) { |
| 359 |
| 360 /* Note: We get the winid not from static tables but from resource bundl
e. */ |
| 361 while (U_SUCCESS(status) && ures_hasNext(bundle)) { |
| 362 UBool idFound = FALSE; |
| 363 const char* winid; |
| 364 UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status)
; |
| 365 if (U_FAILURE(status)) { |
| 366 break; |
| 367 } |
| 368 winid = ures_getKey(winTZ); |
| 369 result = getTZI(winid, &tziReg); |
| 370 |
| 371 if (result == ERROR_SUCCESS) { |
| 372 /* Windows alters the DaylightBias in some situations. |
| 373 Using the bias and the rules suffices, so overwrite |
| 374 these unreliable fields. */ |
| 375 tziKey.standardBias = tziReg.standardBias; |
| 376 tziKey.daylightBias = tziReg.daylightBias; |
| 377 |
| 378 if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey))
== 0) { |
| 379 const UChar* icuTZ = NULL; |
| 380 if (errorCode != 0) { |
| 381 icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &stat
us); |
| 382 } |
| 383 if (errorCode==0 || icuTZ==NULL) { |
| 384 /* fallback to default "001" and reset status */ |
| 385 status = U_ZERO_ERROR; |
| 386 icuTZ = ures_getStringByKey(winTZ, "001", &len, &status)
; |
331 } | 387 } |
332 | 388 |
333 /* tmpid buffer holds the ICU timezone ID corresponding to t
he timezone ID from Windows. | 389 if (U_SUCCESS(status)) { |
334 * If none is found, tmpid buffer will contain a fallback ID
(i.e. the time zone ID matching | 390 /* Get the standard name from the registry key to compar
e with |
335 * the current time zone information) | 391 the one from Windows API call. */ |
336 */ | 392 uprv_memset(regStdName, 0, sizeof(regStdName)); |
337 if (idFound || tmpid[0] == 0) { | 393 result = getSTDName(winid, regStdName, sizeof(regStdName
)); |
338 /* if icuTZ has more than one city, take only the first
(i.e. terminate icuTZ at first space) */ | 394 if (result == ERROR_SUCCESS) { |
339 int index=0; | 395 if (uprv_strcmp(apiStdName, regStdName) == 0) { |
340 while (! (*icuTZ == '\0' || *icuTZ ==' ')) { | 396 idFound = TRUE; |
341 tmpid[index++]=(char)(*icuTZ++); /* safe to assume
'char' is ASCII compatible on windows */ | 397 } |
342 } | 398 } |
343 tmpid[index]='\0'; | 399 |
| 400 /* tmpid buffer holds the ICU timezone ID corresponding
to the timezone ID from Windows. |
| 401 * If none is found, tmpid buffer will contain a fallbac
k ID (i.e. the time zone ID matching |
| 402 * the current time zone information) |
| 403 */ |
| 404 if (idFound || tmpid[0] == 0) { |
| 405 /* if icuTZ has more than one city, take only the fi
rst (i.e. terminate icuTZ at first space) */ |
| 406 int index=0; |
| 407 while (! (*icuTZ == '\0' || *icuTZ ==' ')) { |
| 408 tmpid[index++]=(char)(*icuTZ++); /* safe to ass
ume 'char' is ASCII compatible on windows */ |
| 409 } |
| 410 tmpid[index]='\0'; |
| 411 } |
344 } | 412 } |
345 } | 413 } |
346 } | 414 } |
347 } | 415 ures_close(winTZ); |
348 ures_close(winTZ); | 416 if (idFound) { |
349 if (idFound) { | 417 break; |
350 break; | 418 } |
351 } | 419 } |
352 } | 420 } |
353 | 421 |
354 /* | 422 /* |
355 * Copy the timezone ID to icuid to be returned. | 423 * Copy the timezone ID to icuid to be returned. |
356 */ | 424 */ |
357 if (tmpid[0] != 0) { | 425 if (tmpid[0] != 0) { |
358 len = uprv_strlen(tmpid); | 426 len = uprv_strlen(tmpid); |
359 icuid = (char*)uprv_calloc(len + 1, sizeof(char)); | 427 icuid = (char*)uprv_calloc(len + 1, sizeof(char)); |
360 if (icuid != NULL) { | 428 if (icuid != NULL) { |
361 uprv_strcpy(icuid, tmpid); | 429 uprv_strcpy(icuid, tmpid); |
362 } | 430 } |
363 } | 431 } |
364 | 432 |
365 ures_close(bundle); | 433 ures_close(bundle); |
366 | 434 |
367 return icuid; | 435 return icuid; |
368 } | 436 } |
369 | 437 |
370 #endif /* U_PLATFORM_HAS_WIN32_API */ | 438 #endif /* U_PLATFORM_HAS_WIN32_API */ |
OLD | NEW |