Skip to content

Commit c900357

Browse files
committed
Reimplement GetWindowsLocalTimeZone without icu.h
This commit reimplements my previous commits [1][2], which removed the dependency on WinRT on Windows by using system "icu.dll" (#315) when <icu.h> is available in the build environment. Here are major improvements: * The relevant code is extracted into separate source files "src/time_zone_name_win.{cc,h}". This is also a preparation for implementing TimeZoneIf with Windows time APIs (#328), where one more ICU API needs to be dynamically imported. * The dependency on <icu.h> is removed by locally defining required constants and API prototypes. This should make it possible to build CCTZ with the MinGW toolchain, where <icu.h> is not yet available. * LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) is replaced with LoadLibraryW with the full path to "icu.dll" in the System32 directory, because LOAD_LIBRARY_SEARCH_SYSTEM32 can be ignored when "icu.dll" is already loaded from a non-System32 directory. Let's stick to the system "icu.dll" in favor of predictability. Other than the above improvements, the overall logic remains unchanged. [1]: 2ebbe0d [2]: f8e494f
1 parent c8bc1fb commit c900357

File tree

1 file changed

+13
-18
lines changed

1 file changed

+13
-18
lines changed

src/time_zone_name_win.cc

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
namespace cctz {
3131
namespace {
3232

33-
// UChar is defined as char16_t in ICU by default, but it is also safe to assume
34-
// wchar_t and char16_t are equivalent on Windows.
33+
// Define UChar as wchar_t here because Win32 APIs receive UTF-16 strings as
34+
// wchar_t* instead of char16_t*. Using char16_t would require additional casts.
3535
using UChar = wchar_t;
3636

3737
enum UErrorCode : std::int32_t {
@@ -49,8 +49,7 @@ std::atomic<bool> g_unavailable;
4949
std::atomic<ucal_getTimeZoneIDForWindowsID_func>
5050
g_ucal_getTimeZoneIDForWindowsID;
5151

52-
template <typename T>
53-
static T AsProcAddress(HMODULE module, const char* name) {
52+
template <typename T> static T AsProcAddress(HMODULE module, const char* name) {
5453
static_assert(
5554
std::is_pointer<T>::value &&
5655
std::is_function<typename std::remove_pointer<T>::type>::value,
@@ -61,12 +60,11 @@ static T AsProcAddress(HMODULE module, const char* name) {
6160

6261
std::wstring GetSystem32Dir() {
6362
std::wstring result;
64-
// TODO: Remove std::max() when we require C++17 or higher.
65-
auto len = std::max<size_t>(result.capacity(), 1);
63+
std::uint32_t len = static_cast<std::uint32_t>(std::min<size_t>(
64+
result.capacity(), std::numeric_limits<std::uint32_t>::max()));
6665
do {
6766
result.resize(len);
68-
// TODO: Switch to std::string::data() when we require C++17 or higher.
69-
len = ::GetSystemDirectoryW(&result[0], static_cast<UINT>(result.size()));
67+
len = ::GetSystemDirectoryW(&result[0], len);
7068
} while (len > result.size());
7169
result.resize(len);
7270
return result;
@@ -129,14 +127,13 @@ std::string Utf16ToUtf8(const wchar_t* ptr, size_t size) {
129127
}
130128
const int chars_len = static_cast<int>(size);
131129
std::string result;
132-
// TODO: Remove std::max() when we require C++17 or higher.
133-
auto len = std::max<size_t>(result.capacity(), 1);
130+
std::int32_t len = static_cast<std::int32_t>(std::min<size_t>(
131+
result.capacity(), std::numeric_limits<std::int32_t>::max()));
134132
do {
135133
result.resize(len);
136134
// TODO: Switch to std::string::data() when we require C++17 or higher.
137135
len = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, chars_len,
138-
&result[0], static_cast<int>(result.size()),
139-
nullptr, nullptr);
136+
&result[0], len, nullptr, nullptr);
140137
} while (len > result.size());
141138
result.resize(len);
142139
return result;
@@ -156,15 +153,13 @@ std::string GetWindowsLocalTimeZone() {
156153
}
157154

158155
std::wstring result;
159-
// TODO: Remove std::max() when we require C++17 or higher.
160-
auto len = std::max<size_t>(result.capacity(), 1);
161-
while (true) {
156+
std::int32_t len = static_cast<std::int32_t>(std::min<size_t>(
157+
result.capacity(), std::numeric_limits<std::int32_t>::max()));
158+
for (;;) {
162159
UErrorCode status = U_ZERO_ERROR;
163160
result.resize(len);
164-
// TODO: Switch to std::string::data() when we require C++17 or higher.
165161
len = getTimeZoneIDForWindowsID(
166-
info.TimeZoneKeyName, -1, nullptr, &result[0],
167-
static_cast<std::int32_t>(result.size()), &status);
162+
info.TimeZoneKeyName, -1, nullptr, &result[0], len, &status);
168163
if (U_SUCCESS(status)) {
169164
return Utf16ToUtf8(result.data(), len);
170165
}

0 commit comments

Comments
 (0)