aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/icu/common/wintz.cpp
blob: 47a4c818ea32505aeaee488fd661065394dbc9dc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// © 2016 and later: Unicode, Inc. and others. 
// License & terms of use: http://www.unicode.org/copyright.html 
/* 
******************************************************************************** 
*   Copyright (C) 2005-2015, International Business Machines 
*   Corporation and others.  All Rights Reserved. 
******************************************************************************** 
* 
* File WINTZ.CPP 
* 
******************************************************************************** 
*/ 
 
#include "unicode/utypes.h" 
 
#if U_PLATFORM_USES_ONLY_WIN32_API 
 
#include "wintz.h" 
#include "cmemory.h" 
#include "cstring.h" 
 
#include "unicode/ures.h" 
#include "unicode/ustring.h" 
#include "uresimp.h" 
 
#ifndef WIN32_LEAN_AND_MEAN 
#   define WIN32_LEAN_AND_MEAN 
#endif 
#   define VC_EXTRALEAN 
#   define NOUSER 
#   define NOSERVICE 
#   define NOIME 
#   define NOMCX 
#include <windows.h> 
 
U_NAMESPACE_BEGIN 
 
// The max size of TimeZoneKeyName is 128, defined in DYNAMIC_TIME_ZONE_INFORMATION 
#define MAX_TIMEZONE_ID_LENGTH 128 
 
/** 
* Main Windows time zone detection function. 
* Returns the Windows time zone converted to an ICU time zone as a heap-allocated buffer, or nullptr upon failure. 
* Note: We use the Win32 API GetDynamicTimeZoneInformation to get the current time zone info. 
* This API returns a non-localized time zone name, which we can then map to an ICU time zone name. 
*/ 
U_INTERNAL const char* U_EXPORT2 
uprv_detectWindowsTimeZone() 
{ 
    UErrorCode status = U_ZERO_ERROR; 
    char* icuid = nullptr; 
    char dynamicTZKeyName[MAX_TIMEZONE_ID_LENGTH]; 
    char tmpid[MAX_TIMEZONE_ID_LENGTH]; 
    int32_t len; 
    int id = GEOID_NOT_AVAILABLE; 
    int errorCode; 
    wchar_t ISOcodeW[3] = {}; /* 2 letter ISO code in UTF-16 */ 
    char ISOcode[3] = {}; /* 2 letter ISO code in UTF-8 */ 
 
    DYNAMIC_TIME_ZONE_INFORMATION dynamicTZI; 
    uprv_memset(&dynamicTZI, 0, sizeof(dynamicTZI)); 
    uprv_memset(dynamicTZKeyName, 0, sizeof(dynamicTZKeyName)); 
    uprv_memset(tmpid, 0, sizeof(tmpid)); 
 
    /* Obtain TIME_ZONE_INFORMATION from the API and get the non-localized time zone name. */ 
    if (TIME_ZONE_ID_INVALID == GetDynamicTimeZoneInformation(&dynamicTZI)) { 
        return nullptr; 
    } 
 
    id = GetUserGeoID(GEOCLASS_NATION); 
    errorCode = GetGeoInfoW(id, GEO_ISO2, ISOcodeW, 3, 0); 
 
    // convert from wchar_t* (UTF-16 on Windows) to char* (UTF-8). 
    u_strToUTF8(ISOcode, UPRV_LENGTHOF(ISOcode), nullptr, 
        reinterpret_cast<const UChar*>(ISOcodeW), UPRV_LENGTHOF(ISOcodeW), &status); 
 
    LocalUResourceBundlePointer bundle(ures_openDirect(nullptr, "windowsZones", &status)); 
    ures_getByKey(bundle.getAlias(), "mapTimezones", bundle.getAlias(), &status); 
 
    // convert from wchar_t* (UTF-16 on Windows) to char* (UTF-8). 
    u_strToUTF8(dynamicTZKeyName, UPRV_LENGTHOF(dynamicTZKeyName), nullptr, 
        reinterpret_cast<const UChar*>(dynamicTZI.TimeZoneKeyName), -1, &status); 
 
    if (U_FAILURE(status)) { 
        return nullptr; 
    } 
 
    if (dynamicTZI.TimeZoneKeyName[0] != 0) { 
        StackUResourceBundle winTZ; 
        ures_getByKey(bundle.getAlias(), dynamicTZKeyName, winTZ.getAlias(), &status); 
 
        if (U_SUCCESS(status)) { 
            const UChar* icuTZ = nullptr; 
            if (errorCode != 0) { 
                icuTZ = ures_getStringByKey(winTZ.getAlias(), ISOcode, &len, &status); 
            } 
            if (errorCode == 0 || icuTZ == nullptr) { 
                /* fallback to default "001" and reset status */ 
                status = U_ZERO_ERROR; 
                icuTZ = ures_getStringByKey(winTZ.getAlias(), "001", &len, &status); 
            } 
 
            if (U_SUCCESS(status)) { 
                int index = 0; 
 
                while (!(*icuTZ == '\0' || *icuTZ == ' ')) { 
                    // time zone IDs only contain ASCII invariant characters. 
                    tmpid[index++] = (char)(*icuTZ++); 
                } 
                tmpid[index] = '\0'; 
            } 
        } 
    } 
 
    // Copy the timezone ID to icuid to be returned. 
    if (tmpid[0] != 0) { 
        icuid = uprv_strdup(tmpid); 
    } 
 
    return icuid; 
} 
 
U_NAMESPACE_END 
#endif /* U_PLATFORM_USES_ONLY_WIN32_API  */