summaryrefslogtreecommitdiff
path: root/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc
diff options
context:
space:
mode:
Diffstat (limited to 'abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc')
-rw-r--r--abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc184
1 files changed, 180 insertions, 4 deletions
diff --git a/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc b/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc
index efdea64..d22691b 100644
--- a/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -28,6 +28,31 @@
#include <vector>
#endif
+#if defined(__Fuchsia__)
+#include <fuchsia/intl/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/fdio/directory.h>
+#include <zircon/types.h>
+#endif
+
+#if defined(_WIN32)
+#include <sdkddkver.h>
+// Include only when the SDK is for Windows 10 (and later), and the binary is
+// targeted for Windows XP and later.
+// Note: The Windows SDK added windows.globalization.h file for Windows 10, but
+// MinGW did not add it until NTDDI_WIN10_NI (SDK version 10.0.22621.0).
+#if ((defined(_WIN32_WINNT_WIN10) && !defined(__MINGW32__)) || \
+ (defined(NTDDI_WIN10_NI) && NTDDI_VERSION >= NTDDI_WIN10_NI)) && \
+ (_WIN32_WINNT >= _WIN32_WINNT_WINXP)
+#define USE_WIN32_LOCAL_TIME_ZONE
+#include <roapi.h>
+#include <tchar.h>
+#include <wchar.h>
+#include <windows.globalization.h>
+#include <windows.h>
+#endif
+#endif
+
#include <cstdlib>
#include <cstring>
#include <string>
@@ -40,8 +65,8 @@ ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
-#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
namespace {
+#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
// Android 'L' removes __system_property_get() from the NDK, however
// it is still a hidden symbol in libc so we use dlsym() to access it.
// See Chromium's base/sys_info_android.cc for a similar example.
@@ -65,9 +90,84 @@ int __system_property_get(const char* name, char* value) {
static property_get_func system_property_get = LoadSystemPropertyGet();
return system_property_get ? system_property_get(name, value) : -1;
}
+#endif
-} // namespace
+#if defined(USE_WIN32_LOCAL_TIME_ZONE)
+// Calls the WinRT Calendar.GetTimeZone method to obtain the IANA ID of the
+// local time zone. Returns an empty vector in case of an error.
+std::string win32_local_time_zone(const HMODULE combase) {
+ std::string result;
+ const auto ro_activate_instance =
+ reinterpret_cast<decltype(&RoActivateInstance)>(
+ GetProcAddress(combase, "RoActivateInstance"));
+ if (!ro_activate_instance) {
+ return result;
+ }
+ const auto windows_create_string_reference =
+ reinterpret_cast<decltype(&WindowsCreateStringReference)>(
+ GetProcAddress(combase, "WindowsCreateStringReference"));
+ if (!windows_create_string_reference) {
+ return result;
+ }
+ const auto windows_delete_string =
+ reinterpret_cast<decltype(&WindowsDeleteString)>(
+ GetProcAddress(combase, "WindowsDeleteString"));
+ if (!windows_delete_string) {
+ return result;
+ }
+ const auto windows_get_string_raw_buffer =
+ reinterpret_cast<decltype(&WindowsGetStringRawBuffer)>(
+ GetProcAddress(combase, "WindowsGetStringRawBuffer"));
+ if (!windows_get_string_raw_buffer) {
+ return result;
+ }
+
+ // The string returned by WindowsCreateStringReference doesn't need to be
+ // deleted.
+ HSTRING calendar_class_id;
+ HSTRING_HEADER calendar_class_id_header;
+ HRESULT hr = windows_create_string_reference(
+ RuntimeClass_Windows_Globalization_Calendar,
+ sizeof(RuntimeClass_Windows_Globalization_Calendar) / sizeof(wchar_t) - 1,
+ &calendar_class_id_header, &calendar_class_id);
+ if (FAILED(hr)) {
+ return result;
+ }
+
+ IInspectable* calendar;
+ hr = ro_activate_instance(calendar_class_id, &calendar);
+ if (FAILED(hr)) {
+ return result;
+ }
+
+ ABI::Windows::Globalization::ITimeZoneOnCalendar* time_zone;
+ hr = calendar->QueryInterface(IID_PPV_ARGS(&time_zone));
+ if (FAILED(hr)) {
+ calendar->Release();
+ return result;
+ }
+
+ HSTRING tz_hstr;
+ hr = time_zone->GetTimeZone(&tz_hstr);
+ if (SUCCEEDED(hr)) {
+ UINT32 wlen;
+ const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen);
+ if (tz_wstr) {
+ const int size =
+ WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
+ nullptr, 0, nullptr, nullptr);
+ result.resize(static_cast<size_t>(size));
+ WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
+ &result[0], size, nullptr, nullptr);
+ }
+ windows_delete_string(tz_hstr);
+ }
+ time_zone->Release();
+ calendar->Release();
+ return result;
+}
#endif
+} // namespace
std::string time_zone::name() const { return effective_impl().Name(); }
@@ -133,13 +233,89 @@ time_zone local_time_zone() {
if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) {
CFStringEncoding encoding = kCFStringEncodingUTF8;
CFIndex length = CFStringGetLength(tz_name);
- buffer.resize(CFStringGetMaximumSizeForEncoding(length, encoding) + 1);
- if (CFStringGetCString(tz_name, &buffer[0], buffer.size(), encoding)) {
+ CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, encoding) + 1;
+ buffer.resize(static_cast<size_t>(max_size));
+ if (CFStringGetCString(tz_name, &buffer[0], max_size, encoding)) {
zone = &buffer[0];
}
}
CFRelease(tz_default);
#endif
+#if defined(__Fuchsia__)
+ std::string primary_tz;
+ [&]() {
+ // Note: We can't use the synchronous FIDL API here because it doesn't
+ // allow timeouts; if the FIDL call failed, local_time_zone() would never
+ // return.
+
+ const zx::duration kTimeout = zx::msec(500);
+
+ // Don't attach to the thread because otherwise the thread's dispatcher
+ // would be set to null when the loop is destroyed, causing any other FIDL
+ // code running on the same thread to crash.
+ async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
+
+ fuchsia::intl::PropertyProviderHandle handle;
+ zx_status_t status = fdio_service_connect_by_name(
+ fuchsia::intl::PropertyProvider::Name_,
+ handle.NewRequest().TakeChannel().release());
+ if (status != ZX_OK) {
+ return;
+ }
+
+ fuchsia::intl::PropertyProviderPtr intl_provider;
+ status = intl_provider.Bind(std::move(handle), loop.dispatcher());
+ if (status != ZX_OK) {
+ return;
+ }
+
+ intl_provider->GetProfile(
+ [&loop, &primary_tz](fuchsia::intl::Profile profile) {
+ if (!profile.time_zones().empty()) {
+ primary_tz = profile.time_zones()[0].id;
+ }
+ loop.Quit();
+ });
+ loop.Run(zx::deadline_after(kTimeout));
+ }();
+
+ if (!primary_tz.empty()) {
+ zone = primary_tz.c_str();
+ }
+#endif
+#if defined(USE_WIN32_LOCAL_TIME_ZONE)
+ // Use the WinRT Calendar class to get the local time zone. This feature is
+ // available on Windows 10 and later. The library is dynamically linked to
+ // maintain binary compatibility with Windows XP - Windows 7. On Windows 8,
+ // The combase.dll API functions are available but the RoActivateInstance
+ // call will fail for the Calendar class.
+ std::string winrt_tz;
+ const HMODULE combase =
+ LoadLibraryEx(_T("combase.dll"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (combase) {
+ const auto ro_initialize = reinterpret_cast<decltype(&::RoInitialize)>(
+ GetProcAddress(combase, "RoInitialize"));
+ const auto ro_uninitialize = reinterpret_cast<decltype(&::RoUninitialize)>(
+ GetProcAddress(combase, "RoUninitialize"));
+ if (ro_initialize && ro_uninitialize) {
+ const HRESULT hr = ro_initialize(RO_INIT_MULTITHREADED);
+ // RPC_E_CHANGED_MODE means that a previous RoInitialize call specified
+ // a different concurrency model. The WinRT runtime is initialized and
+ // should work for our purpose here, but we should *not* call
+ // RoUninitialize because it's a failure.
+ if (SUCCEEDED(hr) || hr == RPC_E_CHANGED_MODE) {
+ winrt_tz = win32_local_time_zone(combase);
+ if (SUCCEEDED(hr)) {
+ ro_uninitialize();
+ }
+ }
+ }
+ FreeLibrary(combase);
+ }
+ if (!winrt_tz.empty()) {
+ zone = winrt_tz.c_str();
+ }
+#endif
// Allow ${TZ} to override to default zone.
char* tz_env = nullptr;