mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-21 23:30:06 +00:00
boss: Implement some NsData header and read commands. (#7283)
* boss: Implement some NsData header and read commands. Co-authored-by: Rokkubro <lachlanb03@gmail.com> * boss: Move opening ext data to common function and improve logging. --------- Co-authored-by: Rokkubro <lachlanb03@gmail.com>
This commit is contained in:
parent
3113ae6616
commit
602f4f60d8
@ -631,34 +631,51 @@ void Module::Interface::DeleteNsData(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
void Module::Interface::GetNsDataHeaderInfo(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataHeaderInfo(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
const u32 ns_data_id = rp.Pop<u32>();
|
const auto ns_data_id = rp.Pop<u32>();
|
||||||
const u8 type = rp.Pop<u8>();
|
const auto type = rp.PopEnum<NsDataHeaderInfoType>();
|
||||||
const u32 size = rp.Pop<u32>();
|
const auto size = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto result = online_service->GetNsDataHeaderInfo(ns_data_id, type, size, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(result);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010x}, type={:#04x}, size={:#010x}",
|
LOG_DEBUG(Service_BOSS, "called, ns_data_id={:#010x}, type={:#04x}, size={:#010x}", ns_data_id,
|
||||||
ns_data_id, type, size);
|
type, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::ReadNsData(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::ReadNsData(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
const u32 ns_data_id = rp.Pop<u32>();
|
const auto ns_data_id = rp.Pop<u32>();
|
||||||
const u64 offset = rp.Pop<u64>();
|
const auto offset = rp.Pop<u64>();
|
||||||
const u32 size = rp.Pop<u32>();
|
const auto size = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
const auto online_service = GetSessionService(ctx);
|
||||||
rb.Push(RESULT_SUCCESS);
|
if (online_service == nullptr) {
|
||||||
rb.Push<u32>(size); /// Should be actual read size
|
return;
|
||||||
rb.Push<u32>(0); /// unknown
|
}
|
||||||
rb.PushMappedBuffer(buffer);
|
const auto result = online_service->ReadNsData(ns_data_id, offset, size, buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010x}, offset={:#018x}, size={:#010x}",
|
if (result.Succeeded()) {
|
||||||
ns_data_id, offset, size);
|
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
||||||
|
rb.Push(result.Code());
|
||||||
|
rb.Push<u32>(static_cast<u32>(result.Unwrap()));
|
||||||
|
rb.Push<u32>(0); /// unknown
|
||||||
|
rb.PushMappedBuffer(buffer);
|
||||||
|
} else {
|
||||||
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
rb.Push(result.Code());
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_BOSS, "called, ns_data_id={:#010x}, offset={:#018x}, size={:#010x}",
|
||||||
|
ns_data_id, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::SetNsDataAdditionalInfo(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::SetNsDataAdditionalInfo(Kernel::HLERequestContext& ctx) {
|
||||||
@ -710,14 +727,27 @@ void Module::Interface::GetNsDataNewFlag(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
void Module::Interface::GetNsDataLastUpdate(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataLastUpdate(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
const u32 unk_param1 = rp.Pop<u32>();
|
const u32 ns_data_id = rp.Pop<u32>();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto entry = online_service->GetNsDataEntryFromId(ns_data_id);
|
||||||
|
if (!entry.has_value()) {
|
||||||
|
// TODO: Proper error code.
|
||||||
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
rb.Push(RESULT_UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(0); // stub 0 (32bit value)
|
rb.Push<u32>(0);
|
||||||
rb.Push<u32>(0); // stub 0 (32bit value)
|
rb.Push<u32>(entry->header.download_date); // return the download date from the ns data
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010x}", unk_param1);
|
LOG_DEBUG(Service_BOSS, "called, ns_data_id={:#010X}", ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetErrorCode(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetErrorCode(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -73,12 +73,14 @@ ResultCode OnlineService::InitializeSession(u64 init_program_id) {
|
|||||||
auto create_archive_result = systemsavedata_factory.Open(archive_path, 0);
|
auto create_archive_result = systemsavedata_factory.Open(archive_path, 0);
|
||||||
if (!create_archive_result.Succeeded()) {
|
if (!create_archive_result.Succeeded()) {
|
||||||
LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
|
LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
|
||||||
return ResultCode(1);
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
boss_system_save_data_archive = std::move(create_archive_result).Unwrap();
|
boss_system_save_data_archive = std::move(create_archive_result).Unwrap();
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
|
LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
|
||||||
return ResultCode(1);
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSys::Mode open_mode = {};
|
FileSys::Mode open_mode = {};
|
||||||
@ -151,14 +153,16 @@ void OnlineService::RegisterTask(const u32 size, Kernel::MappedBuffer& buffer) {
|
|||||||
ResultCode OnlineService::UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer) {
|
ResultCode OnlineService::UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer) {
|
||||||
if (size > TASK_ID_SIZE) {
|
if (size > TASK_ID_SIZE) {
|
||||||
LOG_WARNING(Service_BOSS, "TaskId cannot be longer than 8");
|
LOG_WARNING(Service_BOSS, "TaskId cannot be longer than 8");
|
||||||
return ResultCode(1);
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string task_id(size, 0);
|
std::string task_id(size, 0);
|
||||||
buffer.Read(task_id.data(), 0, size);
|
buffer.Read(task_id.data(), 0, size);
|
||||||
if (task_id_list.erase(task_id) == 0) {
|
if (task_id_list.erase(task_id) == 0) {
|
||||||
LOG_WARNING(Service_BOSS, "TaskId not in list");
|
LOG_WARNING(Service_BOSS, "TaskId not in list");
|
||||||
return ResultCode(1);
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
@ -187,20 +191,32 @@ void OnlineService::GetTaskIdList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FileSys::Entry> OnlineService::GetBossExtDataFiles() {
|
FileSys::Path OnlineService::GetBossDataDir() {
|
||||||
|
const u32 high = static_cast<u32>(extdata_id >> 32);
|
||||||
|
const u32 low = static_cast<u32>(extdata_id & 0xFFFFFFFF);
|
||||||
|
return FileSys::ConstructExtDataBinaryPath(1, high, low);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<FileSys::ArchiveBackend> OnlineService::OpenBossExtData() {
|
||||||
FileSys::ArchiveFactory_ExtSaveData boss_extdata_archive_factory(
|
FileSys::ArchiveFactory_ExtSaveData boss_extdata_archive_factory(
|
||||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::ExtSaveDataType::Boss);
|
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::ExtSaveDataType::Boss);
|
||||||
const FileSys::Path boss_path{GetBossDataDir()};
|
const FileSys::Path boss_path{GetBossDataDir()};
|
||||||
auto archive_result = boss_extdata_archive_factory.Open(boss_path, 0);
|
auto archive_result = boss_extdata_archive_factory.Open(boss_path, 0);
|
||||||
if (!archive_result.Succeeded()) {
|
if (!archive_result.Succeeded()) {
|
||||||
LOG_WARNING(Service_BOSS, "Extdata opening failed");
|
LOG_WARNING(Service_BOSS, "Failed to open SpotPass ext data archive with ID '{:#010x}'.",
|
||||||
return {};
|
extdata_id);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return std::move(archive_result).Unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
auto boss_archive = std::move(archive_result).Unwrap();
|
std::vector<FileSys::Entry> OnlineService::GetBossExtDataFiles(
|
||||||
|
FileSys::ArchiveBackend* boss_archive) {
|
||||||
auto dir_result = boss_archive->OpenDirectory("/");
|
auto dir_result = boss_archive->OpenDirectory("/");
|
||||||
if (!dir_result.Succeeded()) {
|
if (!dir_result.Succeeded()) {
|
||||||
LOG_WARNING(Service_BOSS, "Extdata directory opening failed");
|
LOG_WARNING(Service_BOSS,
|
||||||
|
"Failed to open root directory of SpotPass ext data with ID '{:#010x}'.",
|
||||||
|
extdata_id);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto dir = std::move(dir_result).Unwrap();
|
auto dir = std::move(dir_result).Unwrap();
|
||||||
@ -219,29 +235,20 @@ std::vector<FileSys::Entry> OnlineService::GetBossExtDataFiles() {
|
|||||||
return boss_files;
|
return boss_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSys::Path OnlineService::GetBossDataDir() {
|
|
||||||
const u32 high = static_cast<u32>(extdata_id >> 32);
|
|
||||||
const u32 low = static_cast<u32>(extdata_id & 0xFFFFFFFF);
|
|
||||||
return FileSys::ConstructExtDataBinaryPath(1, high, low);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<NsDataEntry> OnlineService::GetNsDataEntries() {
|
std::vector<NsDataEntry> OnlineService::GetNsDataEntries() {
|
||||||
FileSys::ArchiveFactory_ExtSaveData boss_extdata_archive_factory(
|
auto boss_archive = OpenBossExtData();
|
||||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::ExtSaveDataType::Boss);
|
if (!boss_archive) {
|
||||||
const FileSys::Path boss_path{GetBossDataDir()};
|
|
||||||
auto archive_result = boss_extdata_archive_factory.Open(boss_path, 0);
|
|
||||||
if (!archive_result.Succeeded()) {
|
|
||||||
LOG_WARNING(Service_BOSS, "Extdata opening failed");
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto boss_archive = std::move(archive_result).Unwrap().get();
|
|
||||||
|
|
||||||
std::vector<NsDataEntry> ns_data;
|
std::vector<NsDataEntry> ns_data;
|
||||||
std::vector<FileSys::Entry> boss_files = GetBossExtDataFiles();
|
const auto boss_files = GetBossExtDataFiles(boss_archive.get());
|
||||||
for (const auto& current_file : boss_files) {
|
for (const auto& current_file : boss_files) {
|
||||||
constexpr u32 boss_header_length = 0x34;
|
constexpr u32 boss_header_length = 0x34;
|
||||||
if (current_file.is_directory || current_file.file_size < boss_header_length) {
|
if (current_file.is_directory || current_file.file_size < boss_header_length) {
|
||||||
LOG_WARNING(Service_BOSS, "SpotPass extdata contains directory or file is too short");
|
LOG_WARNING(Service_BOSS,
|
||||||
|
"SpotPass extdata contains directory or file is too short: '{}'",
|
||||||
|
Common::UTF16ToUTF8(current_file.filename));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,6 +322,129 @@ u16 OnlineService::GetNsDataIdList(const u32 filter, const u32 max_entries,
|
|||||||
return static_cast<u16>(output_entries.size());
|
return static_cast<u16>(output_entries.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<NsDataEntry> OnlineService::GetNsDataEntryFromId(const u32 ns_data_id) {
|
||||||
|
std::vector<NsDataEntry> ns_data = GetNsDataEntries();
|
||||||
|
const auto entry_iter = std::find_if(ns_data.begin(), ns_data.end(), [ns_data_id](auto entry) {
|
||||||
|
return entry.header.ns_data_id == ns_data_id;
|
||||||
|
});
|
||||||
|
if (entry_iter == ns_data.end()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Could not find NsData with ID {:#010X}", ns_data_id);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return *entry_iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode OnlineService::GetNsDataHeaderInfo(const u32 ns_data_id, const NsDataHeaderInfoType type,
|
||||||
|
const u32 size, Kernel::MappedBuffer& buffer) {
|
||||||
|
const auto entry = GetNsDataEntryFromId(ns_data_id);
|
||||||
|
if (!entry.has_value()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Failed to find NsData entry for ID {:#010X}", ns_data_id);
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::array EXPECTED_NS_DATA_HEADER_INFO_SIZES = {
|
||||||
|
sizeof(u64), // Program ID
|
||||||
|
sizeof(u32), // Unknown
|
||||||
|
sizeof(u32), // Data Type
|
||||||
|
sizeof(u32), // Payload Size
|
||||||
|
sizeof(u32), // NsData ID
|
||||||
|
sizeof(u32), // Version
|
||||||
|
sizeof(NsDataHeaderInfo), // Everything
|
||||||
|
};
|
||||||
|
if (size != EXPECTED_NS_DATA_HEADER_INFO_SIZES[static_cast<u8>(type)]) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Invalid size {} for type {}", size, type);
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case NsDataHeaderInfoType::ProgramId:
|
||||||
|
buffer.Write(&entry->header.program_id, 0, size);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
case NsDataHeaderInfoType::Unknown: {
|
||||||
|
// TODO: Figure out what this is. Stubbed to zero for now.
|
||||||
|
const u32 zero = 0;
|
||||||
|
buffer.Write(&zero, 0, size);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
case NsDataHeaderInfoType::Datatype:
|
||||||
|
buffer.Write(&entry->header.datatype, 0, size);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
case NsDataHeaderInfoType::PayloadSize:
|
||||||
|
buffer.Write(&entry->header.payload_size, 0, size);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
case NsDataHeaderInfoType::NsDataId:
|
||||||
|
buffer.Write(&entry->header.ns_data_id, 0, size);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
case NsDataHeaderInfoType::Version:
|
||||||
|
buffer.Write(&entry->header.version, 0, size);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
case NsDataHeaderInfoType::Everything: {
|
||||||
|
const NsDataHeaderInfo info = {
|
||||||
|
.program_id = entry->header.program_id,
|
||||||
|
.datatype = entry->header.datatype,
|
||||||
|
.payload_size = entry->header.payload_size,
|
||||||
|
.ns_data_id = entry->header.ns_data_id,
|
||||||
|
.version = entry->header.version,
|
||||||
|
};
|
||||||
|
buffer.Write(&info, 0, size);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG_WARNING(Service_BOSS, "Unknown header info type {}", type);
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultVal<size_t> OnlineService::ReadNsData(const u32 ns_data_id, const u64 offset, const u32 size,
|
||||||
|
Kernel::MappedBuffer& buffer) {
|
||||||
|
std::optional<NsDataEntry> entry = GetNsDataEntryFromId(ns_data_id);
|
||||||
|
if (!entry.has_value()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Failed to find NsData entry for ID {:#010X}", ns_data_id);
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->header.payload_size < size + offset) {
|
||||||
|
LOG_WARNING(Service_BOSS,
|
||||||
|
"Invalid request to read {:#010X} bytes at offset {:#010X}, payload "
|
||||||
|
"length is {:#010X}",
|
||||||
|
size, offset, static_cast<u32>(entry->header.payload_size));
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto boss_archive = OpenBossExtData();
|
||||||
|
if (!boss_archive) {
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::Path file_path = fmt::format("/{}", entry->filename);
|
||||||
|
FileSys::Mode mode{};
|
||||||
|
mode.read_flag.Assign(1);
|
||||||
|
auto file_result = boss_archive->OpenFile(file_path, mode);
|
||||||
|
if (!file_result.Succeeded()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Failed to open SpotPass extdata file '{}'.", entry->filename);
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto file = std::move(file_result).Unwrap();
|
||||||
|
std::vector<u8> ns_data_array(size);
|
||||||
|
auto read_result = file->Read(sizeof(BossHeader) + offset, size, ns_data_array.data());
|
||||||
|
if (!read_result.Succeeded()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Failed to read SpotPass extdata file '{}'.", entry->filename);
|
||||||
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Write(ns_data_array.data(), 0, size);
|
||||||
|
return read_result;
|
||||||
|
}
|
||||||
|
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
struct overload : Ts... {
|
struct overload : Ts... {
|
||||||
using Ts::operator()...;
|
using Ts::operator()...;
|
||||||
@ -325,8 +455,9 @@ overload(Ts...) -> overload<Ts...>;
|
|||||||
ResultCode OnlineService::SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer) {
|
ResultCode OnlineService::SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer) {
|
||||||
const auto property_id = static_cast<PropertyID>(id);
|
const auto property_id = static_cast<PropertyID>(id);
|
||||||
if (!current_props.properties.contains(property_id)) {
|
if (!current_props.properties.contains(property_id)) {
|
||||||
LOG_ERROR(Service_BOSS, "Unknown property with id {:#06x}", property_id);
|
LOG_ERROR(Service_BOSS, "Unknown property with ID {:#06x} and size {}", property_id, size);
|
||||||
return ResultCode(1);
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& prop = current_props.properties[property_id];
|
auto& prop = current_props.properties[property_id];
|
||||||
@ -365,8 +496,9 @@ ResultCode OnlineService::ReceiveProperty(const u16 id, const u32 size,
|
|||||||
Kernel::MappedBuffer& buffer) {
|
Kernel::MappedBuffer& buffer) {
|
||||||
const auto property_id = static_cast<PropertyID>(id);
|
const auto property_id = static_cast<PropertyID>(id);
|
||||||
if (!current_props.properties.contains(property_id)) {
|
if (!current_props.properties.contains(property_id)) {
|
||||||
LOG_ERROR(Service_BOSS, "Unknown property with id {:#06x}", property_id);
|
LOG_ERROR(Service_BOSS, "Unknown property with ID {:#06x} and size {}", property_id, size);
|
||||||
return ResultCode(1);
|
// TODO: Proper error code.
|
||||||
|
return RESULT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto write_pod = [&]<typename T>(T& cur_prop) {
|
auto write_pod = [&]<typename T>(T& cur_prop) {
|
||||||
|
@ -17,6 +17,7 @@ class MappedBuffer;
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
class ArchiveBackend;
|
||||||
struct Entry;
|
struct Entry;
|
||||||
class Path;
|
class Path;
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
@ -67,6 +68,27 @@ struct NsDataEntry {
|
|||||||
BossHeader header;
|
BossHeader header;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class NsDataHeaderInfoType : u8 {
|
||||||
|
ProgramId = 0,
|
||||||
|
Unknown = 1,
|
||||||
|
Datatype = 2,
|
||||||
|
PayloadSize = 3,
|
||||||
|
NsDataId = 4,
|
||||||
|
Version = 5,
|
||||||
|
Everything = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NsDataHeaderInfo {
|
||||||
|
u64 program_id;
|
||||||
|
INSERT_PADDING_BYTES(4);
|
||||||
|
u32 datatype;
|
||||||
|
u32 payload_size;
|
||||||
|
u32 ns_data_id;
|
||||||
|
u32 version;
|
||||||
|
INSERT_PADDING_BYTES(4);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NsDataHeaderInfo) == 0x20, "NsDataHeaderInfo has incorrect size");
|
||||||
|
|
||||||
enum class PropertyID : u16 {
|
enum class PropertyID : u16 {
|
||||||
Interval = 0x03,
|
Interval = 0x03,
|
||||||
Duration = 0x04,
|
Duration = 0x04,
|
||||||
@ -144,11 +166,17 @@ public:
|
|||||||
ResultCode UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer);
|
ResultCode UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
void GetTaskIdList();
|
void GetTaskIdList();
|
||||||
u16 GetNsDataIdList(const u32 filter, const u32 max_entries, Kernel::MappedBuffer& buffer);
|
u16 GetNsDataIdList(const u32 filter, const u32 max_entries, Kernel::MappedBuffer& buffer);
|
||||||
|
std::optional<NsDataEntry> GetNsDataEntryFromId(const u32 ns_data_id);
|
||||||
|
ResultCode GetNsDataHeaderInfo(const u32 ns_data_id, const NsDataHeaderInfoType type,
|
||||||
|
const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
|
ResultVal<size_t> ReadNsData(const u32 ns_data_id, const u64 offset, const u32 size,
|
||||||
|
Kernel::MappedBuffer& buffer);
|
||||||
ResultCode SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
|
ResultCode SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
ResultCode ReceiveProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
|
ResultCode ReceiveProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<FileSys::Entry> GetBossExtDataFiles();
|
std::unique_ptr<FileSys::ArchiveBackend> OpenBossExtData();
|
||||||
|
std::vector<FileSys::Entry> GetBossExtDataFiles(FileSys::ArchiveBackend* boss_archive);
|
||||||
FileSys::Path GetBossDataDir();
|
FileSys::Path GetBossDataDir();
|
||||||
std::vector<NsDataEntry> GetNsDataEntries();
|
std::vector<NsDataEntry> GetNsDataEntries();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user