diff options
| author | 2023-06-13 13:28:45 -0700 | |
|---|---|---|
| committer | 2023-06-13 13:28:45 -0700 | |
| commit | 698a3eda508ca0d3220452854b3ec977d7be5ea2 (patch) | |
| tree | fc71df2feda7bfed6f686e3f7aa0fa8629aebc5d /src/core/hle | |
| parent | Merge pull request #10760 from FearlessTobi/translations (diff) | |
| parent | tz_manager: Fix comparison to wrong integer (diff) | |
| download | yuzu-698a3eda508ca0d3220452854b3ec977d7be5ea2.tar.gz yuzu-698a3eda508ca0d3220452854b3ec977d7be5ea2.tar.xz yuzu-698a3eda508ca0d3220452854b3ec977d7be5ea2.zip | |
Merge pull request #10603 from lat9nq/tz-more-complete
core,common: Implement missing time zone data/computations
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/service/time/time_manager.cpp | 34 | ||||
| -rw-r--r-- | src/core/hle/service/time/time_manager.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/time/time_zone_content_manager.cpp | 26 | ||||
| -rw-r--r-- | src/core/hle/service/time/time_zone_manager.cpp | 150 | ||||
| -rw-r--r-- | src/core/hle/service/time/time_zone_manager.h | 8 | ||||
| -rw-r--r-- | src/core/hle/service/time/time_zone_service.cpp | 57 | ||||
| -rw-r--r-- | src/core/hle/service/time/time_zone_service.h | 3 |
7 files changed, 232 insertions, 50 deletions
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index 28667710e..fa0fd0531 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() { | |||
| 22 | return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() + | 22 | return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() + |
| 23 | Settings::values.custom_rtc_differential; | 23 | Settings::values.custom_rtc_differential; |
| 24 | } | 24 | } |
| 25 | |||
| 26 | s64 GetExternalRtcValue() { | ||
| 27 | return GetSecondsSinceEpoch() + TimeManager::GetExternalTimeZoneOffset(); | ||
| 28 | } | ||
| 29 | } // Anonymous namespace | 25 | } // Anonymous namespace |
| 30 | 26 | ||
| 31 | struct TimeManager::Impl final { | 27 | struct TimeManager::Impl final { |
| @@ -43,7 +39,7 @@ struct TimeManager::Impl final { | |||
| 43 | std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, | 39 | std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, |
| 44 | time_zone_content_manager{system} { | 40 | time_zone_content_manager{system} { |
| 45 | 41 | ||
| 46 | const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())}; | 42 | const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())}; |
| 47 | SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {}); | 43 | SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {}); |
| 48 | SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); | 44 | SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); |
| 49 | 45 | ||
| @@ -107,7 +103,7 @@ struct TimeManager::Impl final { | |||
| 107 | 103 | ||
| 108 | void SetupTimeZoneManager(std::string location_name, | 104 | void SetupTimeZoneManager(std::string location_name, |
| 109 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | 105 | Clock::SteadyClockTimePoint time_zone_updated_time_point, |
| 110 | std::size_t total_location_name_count, u128 time_zone_rule_version, | 106 | std::vector<std::string> location_names, u128 time_zone_rule_version, |
| 111 | FileSys::VirtualFile& vfs_file) { | 107 | FileSys::VirtualFile& vfs_file) { |
| 112 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( | 108 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( |
| 113 | location_name, vfs_file) != ResultSuccess) { | 109 | location_name, vfs_file) != ResultSuccess) { |
| @@ -117,20 +113,13 @@ struct TimeManager::Impl final { | |||
| 117 | 113 | ||
| 118 | time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); | 114 | time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); |
| 119 | time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( | 115 | time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( |
| 120 | total_location_name_count); | 116 | location_names.size()); |
| 117 | time_zone_content_manager.GetTimeZoneManager().SetLocationNames(location_names); | ||
| 121 | time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion( | 118 | time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion( |
| 122 | time_zone_rule_version); | 119 | time_zone_rule_version); |
| 123 | time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); | 120 | time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); |
| 124 | } | 121 | } |
| 125 | 122 | ||
| 126 | static s64 GetExternalTimeZoneOffset() { | ||
| 127 | // With "auto" timezone setting, we use the external system's timezone offset | ||
| 128 | if (Settings::GetTimeZoneString() == "auto") { | ||
| 129 | return Common::TimeZone::GetCurrentOffsetSeconds().count(); | ||
| 130 | } | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id, | 123 | void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id, |
| 135 | Clock::TimeSpanType setup_value, | 124 | Clock::TimeSpanType setup_value, |
| 136 | Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { | 125 | Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { |
| @@ -295,19 +284,10 @@ void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) { | |||
| 295 | 284 | ||
| 296 | void TimeManager::SetupTimeZoneManager(std::string location_name, | 285 | void TimeManager::SetupTimeZoneManager(std::string location_name, |
| 297 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | 286 | Clock::SteadyClockTimePoint time_zone_updated_time_point, |
| 298 | std::size_t total_location_name_count, | 287 | std::vector<std::string> location_names, |
| 299 | u128 time_zone_rule_version, | 288 | u128 time_zone_rule_version, |
| 300 | FileSys::VirtualFile& vfs_file) { | 289 | FileSys::VirtualFile& vfs_file) { |
| 301 | impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, | 290 | impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, location_names, |
| 302 | total_location_name_count, time_zone_rule_version, vfs_file); | 291 | time_zone_rule_version, vfs_file); |
| 303 | } | 292 | } |
| 304 | |||
| 305 | /*static*/ s64 TimeManager::GetExternalTimeZoneOffset() { | ||
| 306 | // With "auto" timezone setting, we use the external system's timezone offset | ||
| 307 | if (Settings::GetTimeZoneString() == "auto") { | ||
| 308 | return Common::TimeZone::GetCurrentOffsetSeconds().count(); | ||
| 309 | } | ||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 313 | } // namespace Service::Time | 293 | } // 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..84572dbfa 100644 --- a/src/core/hle/service/time/time_manager.h +++ b/src/core/hle/service/time/time_manager.h | |||
| @@ -61,11 +61,9 @@ public: | |||
| 61 | 61 | ||
| 62 | void SetupTimeZoneManager(std::string location_name, | 62 | void SetupTimeZoneManager(std::string location_name, |
| 63 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | 63 | Clock::SteadyClockTimePoint time_zone_updated_time_point, |
| 64 | std::size_t total_location_name_count, u128 time_zone_rule_version, | 64 | std::vector<std::string> location_names, u128 time_zone_rule_version, |
| 65 | FileSys::VirtualFile& vfs_file); | 65 | FileSys::VirtualFile& vfs_file); |
| 66 | 66 | ||
| 67 | static s64 GetExternalTimeZoneOffset(); | ||
| 68 | |||
| 69 | private: | 67 | private: |
| 70 | Core::System& system; | 68 | Core::System& system; |
| 71 | 69 | ||
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..5d60be67a 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <chrono> | ||
| 4 | #include <sstream> | 5 | #include <sstream> |
| 5 | 6 | ||
| 6 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| @@ -12,7 +13,11 @@ | |||
| 12 | #include "core/file_sys/registered_cache.h" | 13 | #include "core/file_sys/registered_cache.h" |
| 13 | #include "core/file_sys/romfs.h" | 14 | #include "core/file_sys/romfs.h" |
| 14 | #include "core/file_sys/system_archive/system_archive.h" | 15 | #include "core/file_sys/system_archive/system_archive.h" |
| 16 | #include "core/file_sys/vfs.h" | ||
| 17 | #include "core/file_sys/vfs_types.h" | ||
| 18 | #include "core/hle/result.h" | ||
| 15 | #include "core/hle/service/filesystem/filesystem.h" | 19 | #include "core/hle/service/filesystem/filesystem.h" |
| 20 | #include "core/hle/service/time/errors.h" | ||
| 16 | #include "core/hle/service/time/time_manager.h" | 21 | #include "core/hle/service/time/time_manager.h" |
| 17 | #include "core/hle/service/time/time_zone_content_manager.h" | 22 | #include "core/hle/service/time/time_zone_content_manager.h" |
| 18 | 23 | ||
| @@ -71,19 +76,13 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_) | |||
| 71 | : system{system_}, location_name_cache{BuildLocationNameCache(system)} {} | 76 | : system{system_}, location_name_cache{BuildLocationNameCache(system)} {} |
| 72 | 77 | ||
| 73 | void TimeZoneContentManager::Initialize(TimeManager& time_manager) { | 78 | void TimeZoneContentManager::Initialize(TimeManager& time_manager) { |
| 74 | std::string location_name; | ||
| 75 | const auto timezone_setting = Settings::GetTimeZoneString(); | 79 | const auto timezone_setting = Settings::GetTimeZoneString(); |
| 76 | if (timezone_setting == "auto" || timezone_setting == "default") { | ||
| 77 | location_name = Common::TimeZone::GetDefaultTimeZone(); | ||
| 78 | } else { | ||
| 79 | location_name = timezone_setting; | ||
| 80 | } | ||
| 81 | 80 | ||
| 82 | if (FileSys::VirtualFile vfs_file; | 81 | if (FileSys::VirtualFile vfs_file; |
| 83 | GetTimeZoneInfoFile(location_name, vfs_file) == ResultSuccess) { | 82 | GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) { |
| 84 | const auto time_point{ | 83 | const auto time_point{ |
| 85 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; | 84 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; |
| 86 | time_manager.SetupTimeZoneManager(location_name, time_point, location_name_cache.size(), {}, | 85 | time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache, {}, |
| 87 | vfs_file); | 86 | vfs_file); |
| 88 | } else { | 87 | } else { |
| 89 | time_zone_manager.MarkAsInitialized(); | 88 | time_zone_manager.MarkAsInitialized(); |
| @@ -126,8 +125,15 @@ Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_n | |||
| 126 | 125 | ||
| 127 | vfs_file = zoneinfo_dir->GetFileRelative(location_name); | 126 | vfs_file = zoneinfo_dir->GetFileRelative(location_name); |
| 128 | if (!vfs_file) { | 127 | if (!vfs_file) { |
| 129 | LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", | 128 | LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.", |
| 130 | time_zone_binary_titleid, location_name); | 129 | time_zone_binary_titleid, location_name); |
| 130 | const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()}; | ||
| 131 | vfs_file = zoneinfo_dir->GetFile(system_time_zone); | ||
| 132 | } | ||
| 133 | |||
| 134 | if (!vfs_file) { | ||
| 135 | LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", | ||
| 136 | time_zone_binary_titleid, location_name); | ||
| 131 | vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone()); | 137 | vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone()); |
| 132 | } | 138 | } |
| 133 | 139 | ||
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 973f7837a..e1728c06d 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 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <climits> | 4 | #include <climits> |
| 5 | #include <limits> | ||
| 5 | 6 | ||
| 6 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| @@ -9,6 +10,7 @@ | |||
| 9 | #include "core/file_sys/nca_metadata.h" | 10 | #include "core/file_sys/nca_metadata.h" |
| 10 | #include "core/file_sys/registered_cache.h" | 11 | #include "core/file_sys/registered_cache.h" |
| 11 | #include "core/hle/service/time/time_zone_manager.h" | 12 | #include "core/hle/service/time/time_zone_manager.h" |
| 13 | #include "core/hle/service/time/time_zone_types.h" | ||
| 12 | 14 | ||
| 13 | namespace Service::Time::TimeZone { | 15 | namespace Service::Time::TimeZone { |
| 14 | 16 | ||
| @@ -128,10 +130,10 @@ static constexpr int GetQZName(const char* name, int offset, char delimiter) { | |||
| 128 | } | 130 | } |
| 129 | 131 | ||
| 130 | static constexpr int GetTZName(const char* name, int offset) { | 132 | static constexpr int GetTZName(const char* name, int offset) { |
| 131 | for (char value{name[offset]}; | 133 | char c; |
| 132 | value != '\0' && !IsDigit(value) && value != ',' && value != '-' && value != '+'; | 134 | |
| 133 | offset++) { | 135 | while ((c = name[offset]) != '\0' && !IsDigit(c) && c != ',' && c != '-' && c != '+') { |
| 134 | value = name[offset]; | 136 | ++offset; |
| 135 | } | 137 | } |
| 136 | return offset; | 138 | return offset; |
| 137 | } | 139 | } |
| @@ -147,6 +149,7 @@ static constexpr bool GetInteger(const char* name, int& offset, int& value, int | |||
| 147 | if (value > max) { | 149 | if (value > max) { |
| 148 | return {}; | 150 | return {}; |
| 149 | } | 151 | } |
| 152 | offset++; | ||
| 150 | temp = name[offset]; | 153 | temp = name[offset]; |
| 151 | } while (IsDigit(temp)); | 154 | } while (IsDigit(temp)); |
| 152 | 155 | ||
| @@ -471,6 +474,13 @@ static bool ParsePosixName(const char* name, TimeZoneRule& rule) { | |||
| 471 | their_std_offset = their_offset; | 474 | their_std_offset = their_offset; |
| 472 | } | 475 | } |
| 473 | } | 476 | } |
| 477 | |||
| 478 | if (rule.time_count > 0) { | ||
| 479 | UNIMPLEMENTED(); | ||
| 480 | // TODO (lat9nq): Implement eggert/tz/localtime.c:tzparse:1329 | ||
| 481 | // Seems to be unused in yuzu for now: I never hit the UNIMPLEMENTED in testing | ||
| 482 | } | ||
| 483 | |||
| 474 | rule.ttis[0].gmt_offset = -std_offset; | 484 | rule.ttis[0].gmt_offset = -std_offset; |
| 475 | rule.ttis[0].is_dst = false; | 485 | rule.ttis[0].is_dst = false; |
| 476 | rule.ttis[0].abbreviation_list_index = 0; | 486 | rule.ttis[0].abbreviation_list_index = 0; |
| @@ -514,6 +524,7 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi | |||
| 514 | 524 | ||
| 515 | constexpr s32 time_zone_max_leaps{50}; | 525 | constexpr s32 time_zone_max_leaps{50}; |
| 516 | constexpr s32 time_zone_max_chars{50}; | 526 | constexpr s32 time_zone_max_chars{50}; |
| 527 | constexpr s32 time_zone_max_times{1000}; | ||
| 517 | if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps && | 528 | if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps && |
| 518 | 0 < header.type_count && header.type_count < s32(time_zone_rule.ttis.size()) && | 529 | 0 < header.type_count && header.type_count < s32(time_zone_rule.ttis.size()) && |
| 519 | 0 <= header.time_count && header.time_count < s32(time_zone_rule.ats.size()) && | 530 | 0 <= header.time_count && header.time_count < s32(time_zone_rule.ats.size()) && |
| @@ -546,7 +557,7 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi | |||
| 546 | for (int index{}; index < time_zone_rule.time_count; ++index) { | 557 | for (int index{}; index < time_zone_rule.time_count; ++index) { |
| 547 | const u8 type{*vfs_file->ReadByte(read_offset)}; | 558 | const u8 type{*vfs_file->ReadByte(read_offset)}; |
| 548 | read_offset += sizeof(u8); | 559 | read_offset += sizeof(u8); |
| 549 | if (time_zone_rule.time_count <= type) { | 560 | if (time_zone_rule.type_count <= type) { |
| 550 | return {}; | 561 | return {}; |
| 551 | } | 562 | } |
| 552 | if (time_zone_rule.types[index] != 0) { | 563 | if (time_zone_rule.types[index] != 0) { |
| @@ -624,16 +635,109 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi | |||
| 624 | std::array<char, time_zone_name_max> name{}; | 635 | std::array<char, time_zone_name_max> name{}; |
| 625 | std::memcpy(name.data(), temp_name.data() + 1, std::size_t(bytes_read - 1)); | 636 | std::memcpy(name.data(), temp_name.data() + 1, std::size_t(bytes_read - 1)); |
| 626 | 637 | ||
| 638 | // Fill in computed transition times with temp rule | ||
| 627 | TimeZoneRule temp_rule; | 639 | TimeZoneRule temp_rule; |
| 628 | if (ParsePosixName(name.data(), temp_rule)) { | 640 | if (ParsePosixName(name.data(), temp_rule)) { |
| 629 | UNIMPLEMENTED(); | 641 | int have_abbreviation = 0; |
| 642 | int char_count = time_zone_rule.char_count; | ||
| 643 | |||
| 644 | for (int i = 0; i < temp_rule.type_count; i++) { | ||
| 645 | char* temp_abbreviation = | ||
| 646 | temp_rule.chars.data() + temp_rule.ttis[i].abbreviation_list_index; | ||
| 647 | int j; | ||
| 648 | for (j = 0; j < char_count; j++) { | ||
| 649 | if (std::strcmp(time_zone_rule.chars.data() + j, temp_abbreviation) == 0) { | ||
| 650 | temp_rule.ttis[i].abbreviation_list_index = j; | ||
| 651 | have_abbreviation++; | ||
| 652 | break; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | if (j >= char_count) { | ||
| 656 | int temp_abbreviation_length = static_cast<int>(std::strlen(temp_abbreviation)); | ||
| 657 | if (j + temp_abbreviation_length < time_zone_max_chars) { | ||
| 658 | std::strcpy(time_zone_rule.chars.data() + j, temp_abbreviation); | ||
| 659 | char_count = j + temp_abbreviation_length + 1; | ||
| 660 | temp_rule.ttis[i].abbreviation_list_index = j; | ||
| 661 | have_abbreviation++; | ||
| 662 | } | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | if (have_abbreviation == temp_rule.type_count) { | ||
| 667 | time_zone_rule.char_count = char_count; | ||
| 668 | |||
| 669 | // Original comment: | ||
| 670 | /* Ignore any trailing, no-op transitions generated | ||
| 671 | by zic as they don't help here and can run afoul | ||
| 672 | of bugs in zic 2016j or earlier. */ | ||
| 673 | // This is possibly unnecessary for yuzu, since Nintendo doesn't run zic | ||
| 674 | while (1 < time_zone_rule.time_count && | ||
| 675 | (time_zone_rule.types[time_zone_rule.time_count - 1] == | ||
| 676 | time_zone_rule.types[time_zone_rule.time_count - 2])) { | ||
| 677 | time_zone_rule.time_count--; | ||
| 678 | } | ||
| 679 | |||
| 680 | for (int i = 0; | ||
| 681 | i < temp_rule.time_count && time_zone_rule.time_count < time_zone_max_times; | ||
| 682 | i++) { | ||
| 683 | const s64 transition_time = temp_rule.ats[i]; | ||
| 684 | if (0 < time_zone_rule.time_count && | ||
| 685 | transition_time <= time_zone_rule.ats[time_zone_rule.time_count - 1]) { | ||
| 686 | continue; | ||
| 687 | } | ||
| 688 | |||
| 689 | time_zone_rule.ats[time_zone_rule.time_count] = transition_time; | ||
| 690 | time_zone_rule.types[time_zone_rule.time_count] = | ||
| 691 | static_cast<s8>(time_zone_rule.type_count + temp_rule.types[i]); | ||
| 692 | time_zone_rule.time_count++; | ||
| 693 | } | ||
| 694 | for (int i = 0; i < temp_rule.type_count; i++) { | ||
| 695 | time_zone_rule.ttis[time_zone_rule.type_count++] = temp_rule.ttis[i]; | ||
| 696 | } | ||
| 697 | } | ||
| 630 | } | 698 | } |
| 631 | } | 699 | } |
| 700 | |||
| 701 | const auto typesequiv = [](TimeZoneRule& rule, int a, int b) -> bool { | ||
| 702 | if (a < 0 || a >= rule.type_count || b < 0 || b >= rule.type_count) { | ||
| 703 | return {}; | ||
| 704 | } | ||
| 705 | |||
| 706 | const struct TimeTypeInfo* ap = &rule.ttis[a]; | ||
| 707 | const struct TimeTypeInfo* bp = &rule.ttis[b]; | ||
| 708 | |||
| 709 | return (ap->gmt_offset == bp->gmt_offset && ap->is_dst == bp->is_dst && | ||
| 710 | (std::strcmp(&rule.chars[ap->abbreviation_list_index], | ||
| 711 | &rule.chars[bp->abbreviation_list_index]) == 0)); | ||
| 712 | }; | ||
| 713 | |||
| 632 | if (time_zone_rule.type_count == 0) { | 714 | if (time_zone_rule.type_count == 0) { |
| 633 | return {}; | 715 | return {}; |
| 634 | } | 716 | } |
| 635 | if (time_zone_rule.time_count > 1) { | 717 | if (time_zone_rule.time_count > 1) { |
| 636 | UNIMPLEMENTED(); | 718 | if (time_zone_rule.ats[0] <= std::numeric_limits<s64>::max() - seconds_per_repeat) { |
| 719 | s64 repeatat = time_zone_rule.ats[0] + seconds_per_repeat; | ||
| 720 | int repeatattype = time_zone_rule.types[0]; | ||
| 721 | for (int i = 1; i < time_zone_rule.time_count; ++i) { | ||
| 722 | if (time_zone_rule.ats[i] == repeatat && | ||
| 723 | typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { | ||
| 724 | time_zone_rule.go_back = true; | ||
| 725 | break; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | } | ||
| 729 | if (std::numeric_limits<s64>::min() + seconds_per_repeat <= | ||
| 730 | time_zone_rule.ats[time_zone_rule.time_count - 1]) { | ||
| 731 | s64 repeatat = time_zone_rule.ats[time_zone_rule.time_count - 1] - seconds_per_repeat; | ||
| 732 | int repeatattype = time_zone_rule.types[time_zone_rule.time_count - 1]; | ||
| 733 | for (int i = time_zone_rule.time_count; i >= 0; --i) { | ||
| 734 | if (time_zone_rule.ats[i] == repeatat && | ||
| 735 | typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { | ||
| 736 | time_zone_rule.go_ahead = true; | ||
| 737 | break; | ||
| 738 | } | ||
| 739 | } | ||
| 740 | } | ||
| 637 | } | 741 | } |
| 638 | 742 | ||
| 639 | s32 default_type{}; | 743 | s32 default_type{}; |
| @@ -1038,4 +1142,36 @@ Result TimeZoneManager::GetDeviceLocationName(LocationName& value) const { | |||
| 1038 | return ResultSuccess; | 1142 | return ResultSuccess; |
| 1039 | } | 1143 | } |
| 1040 | 1144 | ||
| 1145 | Result TimeZoneManager::GetTotalLocationNameCount(s32& count) const { | ||
| 1146 | if (!is_initialized) { | ||
| 1147 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1148 | } | ||
| 1149 | count = static_cast<u32>(total_location_name_count); | ||
| 1150 | |||
| 1151 | return ResultSuccess; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | Result TimeZoneManager::GetTimeZoneRuleVersion(u128& version) const { | ||
| 1155 | if (!is_initialized) { | ||
| 1156 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1157 | } | ||
| 1158 | version = time_zone_rule_version; | ||
| 1159 | |||
| 1160 | return ResultSuccess; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | Result TimeZoneManager::LoadLocationNameList(std::vector<LocationName>& values) const { | ||
| 1164 | if (!is_initialized) { | ||
| 1165 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | for (const auto& name : total_location_names) { | ||
| 1169 | LocationName entry{}; | ||
| 1170 | std::memcpy(entry.data(), name.c_str(), name.size()); | ||
| 1171 | values.push_back(entry); | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | return ResultSuccess; | ||
| 1175 | } | ||
| 1176 | |||
| 1041 | } // namespace Service::Time::TimeZone | 1177 | } // 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: | |||
| 21 | total_location_name_count = value; | 21 | total_location_name_count = value; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | void SetLocationNames(std::vector<std::string> location_names) { | ||
| 25 | total_location_names = location_names; | ||
| 26 | } | ||
| 27 | |||
| 24 | void SetTimeZoneRuleVersion(const u128& value) { | 28 | void SetTimeZoneRuleVersion(const u128& value) { |
| 25 | time_zone_rule_version = value; | 29 | time_zone_rule_version = value; |
| 26 | } | 30 | } |
| @@ -33,6 +37,9 @@ public: | |||
| 33 | FileSys::VirtualFile& vfs_file); | 37 | FileSys::VirtualFile& vfs_file); |
| 34 | Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value); | 38 | Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value); |
| 35 | Result GetDeviceLocationName(TimeZone::LocationName& value) const; | 39 | Result GetDeviceLocationName(TimeZone::LocationName& value) const; |
| 40 | Result GetTotalLocationNameCount(s32& count) const; | ||
| 41 | Result GetTimeZoneRuleVersion(u128& version) const; | ||
| 42 | Result LoadLocationNameList(std::vector<TimeZone::LocationName>& values) const; | ||
| 36 | Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const; | 43 | Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const; |
| 37 | Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const; | 44 | Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const; |
| 38 | Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const; | 45 | Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const; |
| @@ -46,6 +53,7 @@ private: | |||
| 46 | std::string device_location_name{"GMT"}; | 53 | std::string device_location_name{"GMT"}; |
| 47 | u128 time_zone_rule_version{}; | 54 | u128 time_zone_rule_version{}; |
| 48 | std::size_t total_location_name_count{}; | 55 | std::size_t total_location_name_count{}; |
| 56 | std::vector<std::string> total_location_names{}; | ||
| 49 | Clock::SteadyClockTimePoint time_zone_update_time_point{ | 57 | Clock::SteadyClockTimePoint time_zone_update_time_point{ |
| 50 | Clock::SteadyClockTimePoint::GetRandom()}; | 58 | Clock::SteadyClockTimePoint::GetRandom()}; |
| 51 | }; | 59 | }; |
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_, | |||
| 15 | static const FunctionInfo functions[] = { | 15 | static const FunctionInfo functions[] = { |
| 16 | {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, | 16 | {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, |
| 17 | {1, nullptr, "SetDeviceLocationName"}, | 17 | {1, nullptr, "SetDeviceLocationName"}, |
| 18 | {2, nullptr, "GetTotalLocationNameCount"}, | 18 | {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"}, |
| 19 | {3, nullptr, "LoadLocationNameList"}, | 19 | {3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"}, |
| 20 | {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, | 20 | {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, |
| 21 | {5, nullptr, "GetTimeZoneRuleVersion"}, | 21 | {5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, |
| 22 | {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"}, | 22 | {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"}, |
| 23 | {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, | 23 | {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, |
| 24 | {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | 24 | {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, |
| @@ -45,6 +45,57 @@ void ITimeZoneService::GetDeviceLocationName(HLERequestContext& ctx) { | |||
| 45 | rb.PushRaw(location_name); | 45 | rb.PushRaw(location_name); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | void ITimeZoneService::GetTotalLocationNameCount(HLERequestContext& ctx) { | ||
| 49 | LOG_DEBUG(Service_Time, "called"); | ||
| 50 | |||
| 51 | s32 count{}; | ||
| 52 | if (const Result result{ | ||
| 53 | time_zone_content_manager.GetTimeZoneManager().GetTotalLocationNameCount(count)}; | ||
| 54 | result != ResultSuccess) { | ||
| 55 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 56 | rb.Push(result); | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | |||
| 60 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 61 | rb.Push(ResultSuccess); | ||
| 62 | rb.Push(count); | ||
| 63 | } | ||
| 64 | |||
| 65 | void ITimeZoneService::LoadLocationNameList(HLERequestContext& ctx) { | ||
| 66 | LOG_DEBUG(Service_Time, "called"); | ||
| 67 | |||
| 68 | std::vector<TimeZone::LocationName> location_names{}; | ||
| 69 | if (const Result result{ | ||
| 70 | time_zone_content_manager.GetTimeZoneManager().LoadLocationNameList(location_names)}; | ||
| 71 | result != ResultSuccess) { | ||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 73 | rb.Push(result); | ||
| 74 | return; | ||
| 75 | } | ||
| 76 | |||
| 77 | ctx.WriteBuffer(location_names); | ||
| 78 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 79 | rb.Push(ResultSuccess); | ||
| 80 | rb.Push(static_cast<s32>(location_names.size())); | ||
| 81 | } | ||
| 82 | void ITimeZoneService::GetTimeZoneRuleVersion(HLERequestContext& ctx) { | ||
| 83 | LOG_DEBUG(Service_Time, "called"); | ||
| 84 | |||
| 85 | u128 rule_version{}; | ||
| 86 | if (const Result result{ | ||
| 87 | time_zone_content_manager.GetTimeZoneManager().GetTimeZoneRuleVersion(rule_version)}; | ||
| 88 | result != ResultSuccess) { | ||
| 89 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 90 | rb.Push(result); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 95 | rb.Push(ResultSuccess); | ||
| 96 | rb.PushRaw(rule_version); | ||
| 97 | } | ||
| 98 | |||
| 48 | void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) { | 99 | void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) { |
| 49 | IPC::RequestParser rp{ctx}; | 100 | IPC::RequestParser rp{ctx}; |
| 50 | const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()}; | 101 | const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()}; |
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: | |||
| 22 | 22 | ||
| 23 | private: | 23 | private: |
| 24 | void GetDeviceLocationName(HLERequestContext& ctx); | 24 | void GetDeviceLocationName(HLERequestContext& ctx); |
| 25 | void GetTotalLocationNameCount(HLERequestContext& ctx); | ||
| 26 | void LoadLocationNameList(HLERequestContext& ctx); | ||
| 27 | void GetTimeZoneRuleVersion(HLERequestContext& ctx); | ||
| 25 | void LoadTimeZoneRule(HLERequestContext& ctx); | 28 | void LoadTimeZoneRule(HLERequestContext& ctx); |
| 26 | void ToCalendarTime(HLERequestContext& ctx); | 29 | void ToCalendarTime(HLERequestContext& ctx); |
| 27 | void ToCalendarTimeWithMyRule(HLERequestContext& ctx); | 30 | void ToCalendarTimeWithMyRule(HLERequestContext& ctx); |