diff options
Diffstat (limited to 'intl/icu/source/common/wintz.cpp')
-rw-r--r-- | intl/icu/source/common/wintz.cpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/intl/icu/source/common/wintz.cpp b/intl/icu/source/common/wintz.cpp new file mode 100644 index 0000000000..115512e704 --- /dev/null +++ b/intl/icu/source/common/wintz.cpp @@ -0,0 +1,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 */ |