summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/time/time_zone_content_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
new file mode 100644
index 000000000..57b1a2bca
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -0,0 +1,125 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <sstream>
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/romfs.h"
+#include "core/file_sys/system_archive/system_archive.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/time/time_manager.h"
+#include "core/hle/service/time/time_zone_content_manager.h"
+
+namespace Service::Time::TimeZone {
+
+constexpr u64 time_zone_binary_titleid{0x010000000000080E};
+
+static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) {
+ const auto* nand{system.GetFileSystemController().GetSystemNANDContents()};
+ const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)};
+
+ FileSys::VirtualFile romfs;
+ if (nca) {
+ romfs = nca->GetRomFS();
+ }
+
+ if (!romfs) {
+ romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid);
+ }
+
+ if (!romfs) {
+ LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid);
+ return {};
+ }
+
+ return FileSys::ExtractRomFS(romfs);
+}
+
+static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
+ const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)};
+ if (!extracted_romfs) {
+ LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
+ return {};
+ }
+
+ const FileSys::VirtualFile binary_list{extracted_romfs->GetFile("binaryList.txt")};
+ if (!binary_list) {
+ LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid);
+ return {};
+ }
+
+ std::vector<char> raw_data(binary_list->GetSize());
+ binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize());
+
+ std::stringstream data_stream{raw_data.data()};
+ std::string name;
+ std::vector<std::string> location_name_cache;
+ while (std::getline(data_stream, name)) {
+ name.pop_back(); // Remove carriage return
+ location_name_cache.emplace_back(std::move(name));
+ }
+ return location_name_cache;
+}
+
+TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system)
+ : system{system}, location_name_cache{BuildLocationNameCache(system)} {
+ if (FileSys::VirtualFile vfs_file; GetTimeZoneInfoFile("GMT", vfs_file) == RESULT_SUCCESS) {
+ const auto time_point{
+ time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
+ time_manager.SetupTimeZoneManager("GMT", time_point, location_name_cache.size(), {},
+ vfs_file);
+ } else {
+ time_zone_manager.MarkAsInitialized();
+ }
+}
+
+ResultCode TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules,
+ const std::string& location_name) const {
+ FileSys::VirtualFile vfs_file;
+ if (const ResultCode result{GetTimeZoneInfoFile(location_name, vfs_file)};
+ result != RESULT_SUCCESS) {
+ return result;
+ }
+
+ return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file);
+}
+
+bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const {
+ return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) !=
+ location_name_cache.end();
+}
+
+ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name,
+ FileSys::VirtualFile& vfs_file) const {
+ if (!IsLocationNameValid(location_name)) {
+ return ERROR_TIME_NOT_FOUND;
+ }
+
+ const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)};
+ if (!extracted_romfs) {
+ LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
+ return ERROR_TIME_NOT_FOUND;
+ }
+
+ const FileSys::VirtualDir zoneinfo_dir{extracted_romfs->GetSubdirectory("zoneinfo")};
+ if (!zoneinfo_dir) {
+ LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid);
+ return ERROR_TIME_NOT_FOUND;
+ }
+
+ vfs_file = zoneinfo_dir->GetFile(location_name);
+ if (!vfs_file) {
+ LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid,
+ location_name);
+ return ERROR_TIME_NOT_FOUND;
+ }
+
+ return RESULT_SUCCESS;
+}
+
+} // namespace Service::Time::TimeZone