2019-12-22 23:49:51 +01:00
|
|
|
// 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"
|
2020-05-11 23:55:25 +02:00
|
|
|
#include "common/time_zone.h"
|
2019-12-22 23:49:51 +01:00
|
|
|
#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"
|
2020-05-11 23:55:25 +02:00
|
|
|
#include "core/settings.h"
|
2019-12-22 23:49:51 +01:00
|
|
|
|
|
|
|
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 {};
|
|
|
|
}
|
|
|
|
|
2020-03-18 23:05:23 +01:00
|
|
|
std::vector<char> raw_data(binary_list->GetSize() + 1);
|
2019-12-22 23:49:51 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-10-13 03:09:15 +02:00
|
|
|
TimeZoneContentManager::TimeZoneContentManager(Core::System& system)
|
|
|
|
: system{system}, location_name_cache{BuildLocationNameCache(system)} {}
|
2020-05-11 23:55:25 +02:00
|
|
|
|
2020-10-13 03:09:15 +02:00
|
|
|
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
|
2020-05-11 23:55:25 +02:00
|
|
|
std::string location_name;
|
|
|
|
const auto timezone_setting = Settings::GetTimeZoneString();
|
2020-08-14 16:58:55 +02:00
|
|
|
if (timezone_setting == "auto" || timezone_setting == "default") {
|
2020-05-11 23:55:25 +02:00
|
|
|
location_name = Common::TimeZone::GetDefaultTimeZone();
|
|
|
|
} else {
|
|
|
|
location_name = timezone_setting;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FileSys::VirtualFile vfs_file;
|
|
|
|
GetTimeZoneInfoFile(location_name, vfs_file) == RESULT_SUCCESS) {
|
2019-12-22 23:49:51 +01:00
|
|
|
const auto time_point{
|
|
|
|
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
|
2020-05-11 23:55:25 +02:00
|
|
|
time_manager.SetupTimeZoneManager(location_name, time_point, location_name_cache.size(), {},
|
2019-12-22 23:49:51 +01:00
|
|
|
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);
|
2020-05-11 23:55:25 +02:00
|
|
|
if (!vfs_file) {
|
|
|
|
LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
|
|
|
|
time_zone_binary_titleid, location_name);
|
|
|
|
vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
|
|
|
|
}
|
|
|
|
|
2019-12-22 23:49:51 +01:00
|
|
|
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
|