From c378cbbc2dbd626e8def2c47f52ea21447dd705e Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sun, 21 May 2023 00:36:58 -0400 Subject: tz_content_manager: Detect system time zone Uses C++20 tzdb to determine the system timezone. The switch uses the 597 posix time zones, so this needs tests if the system time zone isn't posix-compliant. --- src/core/hle/service/time/time_zone_content_manager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp index afbfe9715..ae41116b6 100644 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ b/src/core/hle/service/time/time_zone_content_manager.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include "common/logging/log.h" @@ -12,7 +13,11 @@ #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/file_sys/system_archive/system_archive.h" +#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_types.h" +#include "core/hle/result.h" #include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/time/errors.h" #include "core/hle/service/time/time_manager.h" #include "core/hle/service/time/time_zone_content_manager.h" @@ -73,7 +78,12 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_) void TimeZoneContentManager::Initialize(TimeManager& time_manager) { std::string location_name; const auto timezone_setting = Settings::GetTimeZoneString(); - if (timezone_setting == "auto" || timezone_setting == "default") { + if (timezone_setting == "auto") { + const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); + const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); + std::string_view current_zone_name = current_zone->name(); + location_name = current_zone_name; + } else if (timezone_setting == "default") { location_name = Common::TimeZone::GetDefaultTimeZone(); } else { location_name = timezone_setting; -- cgit v1.2.3 From 9e2164be74d9049877092771155ba306140a320b Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sun, 21 May 2023 02:43:15 -0400 Subject: time_manager: Don't offset RTC by system time zone This causes the emulated system's universal time to be on the user's clock, and the user time to be off if they set a time zone. time_manager: Remove GetExternalRtcTime --- src/core/hle/service/time/time_manager.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index 28667710e..d5c9e6b5e 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp @@ -22,10 +22,6 @@ s64 GetSecondsSinceEpoch() { return std::chrono::duration_cast(time_since_epoch).count() + Settings::values.custom_rtc_differential; } - -s64 GetExternalRtcValue() { - return GetSecondsSinceEpoch() + TimeManager::GetExternalTimeZoneOffset(); -} } // Anonymous namespace struct TimeManager::Impl final { @@ -43,7 +39,7 @@ struct TimeManager::Impl final { std::make_shared()}, time_zone_content_manager{system} { - const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())}; + const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())}; SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {}); SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); -- cgit v1.2.3 From a39b9134db9c205e4a01105f5a610142428c347e Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sun, 21 May 2023 15:44:34 -0400 Subject: time: Remove auto timezone consideration GetTimeZoneString no longer reports a setting unique to yuzu, so we can assume a valid timezone string in core. --- src/core/hle/service/time/time_manager.cpp | 17 ----------------- src/core/hle/service/time/time_manager.h | 2 -- src/core/hle/service/time/time_zone_content_manager.cpp | 17 +++-------------- 3 files changed, 3 insertions(+), 33 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index d5c9e6b5e..20012afd9 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp @@ -119,14 +119,6 @@ struct TimeManager::Impl final { time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); } - static s64 GetExternalTimeZoneOffset() { - // With "auto" timezone setting, we use the external system's timezone offset - if (Settings::GetTimeZoneString() == "auto") { - return Common::TimeZone::GetCurrentOffsetSeconds().count(); - } - return 0; - } - void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id, Clock::TimeSpanType setup_value, Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { @@ -297,13 +289,4 @@ void TimeManager::SetupTimeZoneManager(std::string location_name, impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, total_location_name_count, time_zone_rule_version, vfs_file); } - -/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() { - // With "auto" timezone setting, we use the external system's timezone offset - if (Settings::GetTimeZoneString() == "auto") { - return Common::TimeZone::GetCurrentOffsetSeconds().count(); - } - return 0; -} - } // namespace Service::Time diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h index 4f046f266..3848da8bc 100644 --- a/src/core/hle/service/time/time_manager.h +++ b/src/core/hle/service/time/time_manager.h @@ -64,8 +64,6 @@ public: std::size_t total_location_name_count, u128 time_zone_rule_version, FileSys::VirtualFile& vfs_file); - static s64 GetExternalTimeZoneOffset(); - private: Core::System& system; diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp index ae41116b6..5fab7fa7b 100644 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ b/src/core/hle/service/time/time_zone_content_manager.cpp @@ -76,25 +76,14 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_) : system{system_}, location_name_cache{BuildLocationNameCache(system)} {} void TimeZoneContentManager::Initialize(TimeManager& time_manager) { - std::string location_name; const auto timezone_setting = Settings::GetTimeZoneString(); - if (timezone_setting == "auto") { - const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); - const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); - std::string_view current_zone_name = current_zone->name(); - location_name = current_zone_name; - } else if (timezone_setting == "default") { - location_name = Common::TimeZone::GetDefaultTimeZone(); - } else { - location_name = timezone_setting; - } if (FileSys::VirtualFile vfs_file; - GetTimeZoneInfoFile(location_name, vfs_file) == ResultSuccess) { + GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) { const auto time_point{ time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; - time_manager.SetupTimeZoneManager(location_name, time_point, location_name_cache.size(), {}, - vfs_file); + time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache.size(), + {}, vfs_file); } else { time_zone_manager.MarkAsInitialized(); } -- cgit v1.2.3 From 5d9dd883876a242577093e9351d1ab2653f230f8 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 23 May 2023 18:33:34 -0400 Subject: tz_content_manager: Try the system time zone first If we can't find the normal time zone string, try searching for the closest one. --- src/core/hle/service/time/time_zone_content_manager.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp index 5fab7fa7b..86a5acc54 100644 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ b/src/core/hle/service/time/time_zone_content_manager.cpp @@ -125,8 +125,15 @@ Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_n vfs_file = zoneinfo_dir->GetFileRelative(location_name); if (!vfs_file) { - LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", - time_zone_binary_titleid, location_name); + LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.", + time_zone_binary_titleid, location_name); + const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()}; + vfs_file = zoneinfo_dir->GetFile(system_time_zone); + } + + if (!vfs_file) { + LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", + time_zone_binary_titleid, location_name); vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone()); } -- cgit v1.2.3 From 8d52dc163a0034596722ce2a50cfd9e645929a05 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Fri, 26 May 2023 04:40:04 -0400 Subject: time_zone_manager: Implement go_ahead/go_back --- src/core/hle/service/time/time_zone_manager.cpp | 40 ++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 973f7837a..805ffb902 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include "common/assert.h" #include "common/logging/log.h" @@ -9,6 +10,7 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" #include "core/hle/service/time/time_zone_manager.h" +#include "core/hle/service/time/time_zone_types.h" namespace Service::Time::TimeZone { @@ -629,11 +631,47 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi UNIMPLEMENTED(); } } + + const auto typesequiv = [](TimeZoneRule& rule, int a, int b) -> bool { + if (a < 0 || a >= rule.type_count || b < 0 || b >= rule.type_count) { + return {}; + } + + const struct TimeTypeInfo* ap = &rule.ttis[a]; + const struct TimeTypeInfo* bp = &rule.ttis[b]; + + return (ap->gmt_offset == bp->gmt_offset && ap->is_dst == bp->is_dst && + (std::strcmp(&rule.chars[ap->abbreviation_list_index], + &rule.chars[bp->abbreviation_list_index]) == 0)); + }; + if (time_zone_rule.type_count == 0) { return {}; } if (time_zone_rule.time_count > 1) { - UNIMPLEMENTED(); + if (time_zone_rule.ats[0] <= std::numeric_limits::max() - seconds_per_repeat) { + s64 repeatat = time_zone_rule.ats[0] + seconds_per_repeat; + int repeatattype = time_zone_rule.types[0]; + for (int i = 1; i < time_zone_rule.time_count; ++i) { + if (time_zone_rule.ats[i] == repeatat && + typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { + time_zone_rule.go_back = true; + break; + } + } + } + if (std::numeric_limits::min() + seconds_per_repeat <= + time_zone_rule.ats[time_zone_rule.time_count - 1]) { + s64 repeatat = time_zone_rule.ats[time_zone_rule.time_count - 1] - seconds_per_repeat; + int repeatattype = time_zone_rule.types[time_zone_rule.time_count - 1]; + for (int i = time_zone_rule.time_count; i >= 0; --i) { + if (time_zone_rule.ats[i] == repeatat && + typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { + time_zone_rule.go_ahead = true; + break; + } + } + } } s32 default_type{}; -- cgit v1.2.3 From a40e0fdf9e287d962108731ebb515ee0fa4ee155 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 14 Jul 2022 10:37:03 -0500 Subject: time: Implement missing services Implements GetTotalLocationNameCount LoadLocationNameList and GetTimeZoneRuleVersion. tz-manager: Fix sign issue --- src/core/hle/service/time/time_manager.cpp | 11 +++-- src/core/hle/service/time/time_manager.h | 2 +- .../hle/service/time/time_zone_content_manager.cpp | 4 +- src/core/hle/service/time/time_zone_manager.cpp | 32 ++++++++++++ src/core/hle/service/time/time_zone_manager.h | 8 +++ src/core/hle/service/time/time_zone_service.cpp | 57 ++++++++++++++++++++-- src/core/hle/service/time/time_zone_service.h | 3 ++ 7 files changed, 106 insertions(+), 11 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index 20012afd9..fa0fd0531 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp @@ -103,7 +103,7 @@ struct TimeManager::Impl final { void SetupTimeZoneManager(std::string location_name, Clock::SteadyClockTimePoint time_zone_updated_time_point, - std::size_t total_location_name_count, u128 time_zone_rule_version, + std::vector location_names, u128 time_zone_rule_version, FileSys::VirtualFile& vfs_file) { if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( location_name, vfs_file) != ResultSuccess) { @@ -113,7 +113,8 @@ struct TimeManager::Impl final { time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( - total_location_name_count); + location_names.size()); + time_zone_content_manager.GetTimeZoneManager().SetLocationNames(location_names); time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion( time_zone_rule_version); time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); @@ -283,10 +284,10 @@ void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) { void TimeManager::SetupTimeZoneManager(std::string location_name, Clock::SteadyClockTimePoint time_zone_updated_time_point, - std::size_t total_location_name_count, + std::vector location_names, u128 time_zone_rule_version, FileSys::VirtualFile& vfs_file) { - impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, - total_location_name_count, time_zone_rule_version, vfs_file); + impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, location_names, + time_zone_rule_version, vfs_file); } } // namespace Service::Time diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h index 3848da8bc..84572dbfa 100644 --- a/src/core/hle/service/time/time_manager.h +++ b/src/core/hle/service/time/time_manager.h @@ -61,7 +61,7 @@ public: void SetupTimeZoneManager(std::string location_name, Clock::SteadyClockTimePoint time_zone_updated_time_point, - std::size_t total_location_name_count, u128 time_zone_rule_version, + std::vector location_names, u128 time_zone_rule_version, FileSys::VirtualFile& vfs_file); private: diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp index 86a5acc54..5d60be67a 100644 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ b/src/core/hle/service/time/time_zone_content_manager.cpp @@ -82,8 +82,8 @@ void TimeZoneContentManager::Initialize(TimeManager& time_manager) { GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) { const auto time_point{ time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; - time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache.size(), - {}, vfs_file); + time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache, {}, + vfs_file); } else { time_zone_manager.MarkAsInitialized(); } diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 805ffb902..5e507dff2 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -1076,4 +1076,36 @@ Result TimeZoneManager::GetDeviceLocationName(LocationName& value) const { return ResultSuccess; } +Result TimeZoneManager::GetTotalLocationNameCount(s32& count) const { + if (!is_initialized) { + return ERROR_UNINITIALIZED_CLOCK; + } + count = static_cast(total_location_name_count); + + return ResultSuccess; +} + +Result TimeZoneManager::GetTimeZoneRuleVersion(u128& version) const { + if (!is_initialized) { + return ERROR_UNINITIALIZED_CLOCK; + } + version = time_zone_rule_version; + + return ResultSuccess; +} + +Result TimeZoneManager::LoadLocationNameList(std::vector& values) const { + if (!is_initialized) { + return ERROR_UNINITIALIZED_CLOCK; + } + + for (const auto& name : total_location_names) { + LocationName entry{}; + std::memcpy(entry.data(), name.c_str(), name.size()); + values.push_back(entry); + } + + return ResultSuccess; +} + } // namespace Service::Time::TimeZone diff --git a/src/core/hle/service/time/time_zone_manager.h b/src/core/hle/service/time/time_zone_manager.h index 5ebd4035e..8664f28d1 100644 --- a/src/core/hle/service/time/time_zone_manager.h +++ b/src/core/hle/service/time/time_zone_manager.h @@ -21,6 +21,10 @@ public: total_location_name_count = value; } + void SetLocationNames(std::vector location_names) { + total_location_names = location_names; + } + void SetTimeZoneRuleVersion(const u128& value) { time_zone_rule_version = value; } @@ -33,6 +37,9 @@ public: FileSys::VirtualFile& vfs_file); Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value); Result GetDeviceLocationName(TimeZone::LocationName& value) const; + Result GetTotalLocationNameCount(s32& count) const; + Result GetTimeZoneRuleVersion(u128& version) const; + Result LoadLocationNameList(std::vector& values) const; Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const; Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const; Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const; @@ -46,6 +53,7 @@ private: std::string device_location_name{"GMT"}; u128 time_zone_rule_version{}; std::size_t total_location_name_count{}; + std::vector total_location_names{}; Clock::SteadyClockTimePoint time_zone_update_time_point{ Clock::SteadyClockTimePoint::GetRandom()}; }; diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp index cda8d8343..e8273e152 100644 --- a/src/core/hle/service/time/time_zone_service.cpp +++ b/src/core/hle/service/time/time_zone_service.cpp @@ -15,10 +15,10 @@ ITimeZoneService::ITimeZoneService(Core::System& system_, static const FunctionInfo functions[] = { {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, {1, nullptr, "SetDeviceLocationName"}, - {2, nullptr, "GetTotalLocationNameCount"}, - {3, nullptr, "LoadLocationNameList"}, + {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"}, + {3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"}, {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, - {5, nullptr, "GetTimeZoneRuleVersion"}, + {5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"}, {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, @@ -45,6 +45,57 @@ void ITimeZoneService::GetDeviceLocationName(HLERequestContext& ctx) { rb.PushRaw(location_name); } +void ITimeZoneService::GetTotalLocationNameCount(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called"); + + s32 count{}; + if (const Result result{ + time_zone_content_manager.GetTimeZoneManager().GetTotalLocationNameCount(count)}; + result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(count); +} + +void ITimeZoneService::LoadLocationNameList(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called"); + + std::vector location_names{}; + if (const Result result{ + time_zone_content_manager.GetTimeZoneManager().LoadLocationNameList(location_names)}; + result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + ctx.WriteBuffer(location_names); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(location_names.size())); +} +void ITimeZoneService::GetTimeZoneRuleVersion(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called"); + + u128 rule_version{}; + if (const Result result{ + time_zone_content_manager.GetTimeZoneManager().GetTimeZoneRuleVersion(rule_version)}; + result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(rule_version); +} + void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto raw_location_name{rp.PopRaw>()}; diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h index ea83b5714..952fcb0e2 100644 --- a/src/core/hle/service/time/time_zone_service.h +++ b/src/core/hle/service/time/time_zone_service.h @@ -22,6 +22,9 @@ public: private: void GetDeviceLocationName(HLERequestContext& ctx); + void GetTotalLocationNameCount(HLERequestContext& ctx); + void LoadLocationNameList(HLERequestContext& ctx); + void GetTimeZoneRuleVersion(HLERequestContext& ctx); void LoadTimeZoneRule(HLERequestContext& ctx); void ToCalendarTime(HLERequestContext& ctx); void ToCalendarTimeWithMyRule(HLERequestContext& ctx); -- cgit v1.2.3 From 63c51abe42c95b5248eb1a14ffbe295ac27b1a71 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sat, 3 Jun 2023 20:20:35 -0400 Subject: tz_manager: Fix off-by-one error --- src/core/hle/service/time/time_zone_manager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 5e507dff2..3d293d025 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -130,10 +130,10 @@ static constexpr int GetQZName(const char* name, int offset, char delimiter) { } static constexpr int GetTZName(const char* name, int offset) { - for (char value{name[offset]}; - value != '\0' && !IsDigit(value) && value != ',' && value != '-' && value != '+'; - offset++) { - value = name[offset]; + char c; + + while ((c = name[offset]) != '\0' && !IsDigit(c) && c != ',' && c != '-' && c != '+') { + ++offset; } return offset; } -- cgit v1.2.3 From dea61f5d00d0281ba66321564bdcc55e14925af4 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sat, 3 Jun 2023 22:35:19 -0400 Subject: tz_manager: Fix character offset not advancing --- src/core/hle/service/time/time_zone_manager.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 3d293d025..de5c3b407 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -149,6 +149,7 @@ static constexpr bool GetInteger(const char* name, int& offset, int& value, int if (value > max) { return {}; } + offset++; temp = name[offset]; } while (IsDigit(temp)); -- cgit v1.2.3 From 78a47f1ee8458abbf94504344d8b46f4b13ccada Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sat, 3 Jun 2023 20:53:25 -0400 Subject: tz_manager: Warn on unimplemented code --- src/core/hle/service/time/time_zone_manager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index de5c3b407..54c9ecf40 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -474,6 +474,13 @@ static bool ParsePosixName(const char* name, TimeZoneRule& rule) { their_std_offset = their_offset; } } + + if (rule.time_count > 0) { + UNIMPLEMENTED(); + // TODO (lat9nq): Implement eggert/tz/localtime.c:tzparse:1329 + // Seems to be unused in yuzu for now: I never hit the UNIMPLEMENTED in testing + } + rule.ttis[0].gmt_offset = -std_offset; rule.ttis[0].is_dst = false; rule.ttis[0].abbreviation_list_index = 0; -- cgit v1.2.3 From 3218313c227c2cb6eff145d32c7f4ac01b534cf4 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sat, 3 Jun 2023 20:52:51 -0400 Subject: tz_manager: Implement missing transition times time_zone_manager: Use s64 storage --- src/core/hle/service/time/time_zone_manager.cpp | 60 ++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 54c9ecf40..24a9aa55d 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -524,6 +524,7 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi constexpr s32 time_zone_max_leaps{50}; constexpr s32 time_zone_max_chars{50}; + constexpr s32 time_zone_max_times{1000}; if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps && 0 < header.type_count && header.type_count < s32(time_zone_rule.ttis.size()) && 0 <= header.time_count && header.time_count < s32(time_zone_rule.ats.size()) && @@ -634,9 +635,66 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi std::array name{}; std::memcpy(name.data(), temp_name.data() + 1, std::size_t(bytes_read - 1)); + // Fill in computed transition times with temp rule TimeZoneRule temp_rule; if (ParsePosixName(name.data(), temp_rule)) { - UNIMPLEMENTED(); + int have_abbreviation = 0; + int char_count = time_zone_rule.char_count; + + for (int i = 0; i < temp_rule.type_count; i++) { + char* temp_abbreviation = + temp_rule.chars.data() + temp_rule.ttis[i].abbreviation_list_index; + int j; + for (j = 0; j < char_count; j++) { + if (std::strcmp(time_zone_rule.chars.data() + j, temp_abbreviation) == 0) { + temp_rule.ttis[i].abbreviation_list_index = j; + have_abbreviation++; + break; + } + } + if (j >= char_count) { + int temp_abbreviation_length = static_cast(std::strlen(temp_abbreviation)); + if (j + temp_abbreviation_length < time_zone_max_chars) { + std::strcpy(time_zone_rule.chars.data() + j, temp_abbreviation); + char_count = j + temp_abbreviation_length + 1; + temp_rule.ttis[i].abbreviation_list_index = j; + have_abbreviation++; + } + } + } + + if (have_abbreviation == temp_rule.type_count) { + time_zone_rule.char_count = char_count; + + // Original comment: + /* Ignore any trailing, no-op transitions generated + by zic as they don't help here and can run afoul + of bugs in zic 2016j or earlier. */ + // This is possibly unnecessary for yuzu, since Nintendo doesn't run zic + while (1 < time_zone_rule.time_count && + (time_zone_rule.types[time_zone_rule.time_count - 1] == + time_zone_rule.types[time_zone_rule.time_count - 2])) { + time_zone_rule.time_count--; + } + + for (int i = 0; + i < temp_rule.time_count && time_zone_rule.time_count < time_zone_max_times; + i++) { + const s64 transition_time = temp_rule.ats[i]; + if (0 < time_zone_rule.time_count && + transition_time <= time_zone_rule.ats[time_zone_rule.time_count - 1]) { + continue; + } + + time_zone_rule.ats[time_zone_rule.time_count] = transition_time; + time_zone_rule.types[time_zone_rule.time_count] = + static_cast(time_zone_rule.type_count + temp_rule.types[i]); + time_zone_rule.time_count++; + } + for (int i = 0; i < temp_rule.type_count; i++) { + time_zone_rule.ttis[time_zone_rule.type_count++] = temp_rule.ttis[i]; + } + } } } -- cgit v1.2.3 From 8f9afbcd91444c5e0653da458e44de37388c6d79 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sat, 3 Jun 2023 22:18:52 -0400 Subject: tz_manager: Fix comparison to wrong integer --- src/core/hle/service/time/time_zone_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 24a9aa55d..e1728c06d 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -557,7 +557,7 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi for (int index{}; index < time_zone_rule.time_count; ++index) { const u8 type{*vfs_file->ReadByte(read_offset)}; read_offset += sizeof(u8); - if (time_zone_rule.time_count <= type) { + if (time_zone_rule.type_count <= type) { return {}; } if (time_zone_rule.types[index] != 0) { -- cgit v1.2.3