ns: Implement command 400: GetApplicationControlData
Returns the raw NACP bytes and the raw icon bytes into a title-provided buffer. Pulls from Registration Cache for control data, returning all zeros should it not exist.
This commit is contained in:
parent
5ee19add1b
commit
bdaa76c0db
|
@ -83,7 +83,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
|
||||||
return MakeResult<VirtualDir>(std::move(out));
|
return MakeResult<VirtualDir>(std::move(out));
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) {
|
VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
|
||||||
return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
|
return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ public:
|
||||||
|
|
||||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
|
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
|
||||||
|
|
||||||
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space);
|
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
||||||
|
|
||||||
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
|
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
|
||||||
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
||||||
|
|
|
@ -481,9 +481,9 @@ public:
|
||||||
// Write the data to memory
|
// Write the data to memory
|
||||||
ctx.WriteBuffer(begin, range_size);
|
ctx.WriteBuffer(begin, range_size);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(actual_entries);
|
rb.Push<u32>(static_cast<u32>(actual_entries));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -498,15 +498,6 @@ private:
|
||||||
return Common::swap64(out);
|
return Common::swap64(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::array<u8, 0x10> ArraySwap(const std::array<u8, 0x10>& in) {
|
|
||||||
std::array<u8, 0x10> out;
|
|
||||||
for (std::size_t i = 0; i < in.size(); ++i) {
|
|
||||||
out[0xF - i] = in[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindAllSaves(FileSys::SaveDataSpaceId space) {
|
void FindAllSaves(FileSys::SaveDataSpaceId space) {
|
||||||
const auto save_root = OpenSaveDataSpace(space);
|
const auto save_root = OpenSaveDataSpace(space);
|
||||||
ASSERT(save_root.Succeeded());
|
ASSERT(save_root.Succeeded());
|
||||||
|
@ -516,8 +507,9 @@ private:
|
||||||
for (const auto& save_id : type->GetSubdirectories()) {
|
for (const auto& save_id : type->GetSubdirectories()) {
|
||||||
for (const auto& user_id : save_id->GetSubdirectories()) {
|
for (const auto& user_id : save_id->GetSubdirectories()) {
|
||||||
const auto save_id_numeric = stoull_be(save_id->GetName());
|
const auto save_id_numeric = stoull_be(save_id->GetName());
|
||||||
const auto user_id_numeric =
|
auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
|
||||||
ArraySwap(Common::HexStringToArray<0x10>(user_id->GetName()));
|
std::reverse(user_id_numeric.begin(), user_id_numeric.end());
|
||||||
|
|
||||||
if (save_id_numeric != 0) {
|
if (save_id_numeric != 0) {
|
||||||
// System Save Data
|
// System Save Data
|
||||||
info.emplace_back(SaveDataInfo{
|
info.emplace_back(SaveDataInfo{
|
||||||
|
@ -560,12 +552,16 @@ private:
|
||||||
for (const auto& title_id : user_id->GetSubdirectories()) {
|
for (const auto& title_id : user_id->GetSubdirectories()) {
|
||||||
if (!title_id->GetFiles().empty() ||
|
if (!title_id->GetFiles().empty() ||
|
||||||
!title_id->GetSubdirectories().empty()) {
|
!title_id->GetSubdirectories().empty()) {
|
||||||
|
auto user_id_numeric =
|
||||||
|
Common::HexStringToArray<0x10>(user_id->GetName());
|
||||||
|
std::reverse(user_id_numeric.begin(), user_id_numeric.end());
|
||||||
|
|
||||||
info.emplace_back(SaveDataInfo{
|
info.emplace_back(SaveDataInfo{
|
||||||
0,
|
0,
|
||||||
space,
|
space,
|
||||||
FileSys::SaveDataType::TemporaryStorage,
|
FileSys::SaveDataType::TemporaryStorage,
|
||||||
{},
|
{},
|
||||||
Common::HexStringToArray<0x10, true>(user_id->GetName()),
|
user_id_numeric,
|
||||||
stoull_be(type->GetName()),
|
stoull_be(type->GetName()),
|
||||||
stoull_be(title_id->GetName()),
|
stoull_be(title_id->GetName()),
|
||||||
title_id->GetSize(),
|
title_id->GetSize(),
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/service/ns/ns.h"
|
#include "core/hle/service/ns/ns.h"
|
||||||
|
@ -118,7 +121,7 @@ public:
|
||||||
{305, nullptr, "TerminateSystemApplet"},
|
{305, nullptr, "TerminateSystemApplet"},
|
||||||
{306, nullptr, "LaunchOverlayApplet"},
|
{306, nullptr, "LaunchOverlayApplet"},
|
||||||
{307, nullptr, "TerminateOverlayApplet"},
|
{307, nullptr, "TerminateOverlayApplet"},
|
||||||
{400, nullptr, "GetApplicationControlData"},
|
{400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
|
||||||
{401, nullptr, "InvalidateAllApplicationControlCache"},
|
{401, nullptr, "InvalidateAllApplicationControlCache"},
|
||||||
{402, nullptr, "RequestDownloadApplicationControlData"},
|
{402, nullptr, "RequestDownloadApplicationControlData"},
|
||||||
{403, nullptr, "GetMaxApplicationControlCacheCount"},
|
{403, nullptr, "GetMaxApplicationControlCacheCount"},
|
||||||
|
@ -243,6 +246,65 @@ public:
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto flag = rp.PopRaw<u64>();
|
||||||
|
LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
|
||||||
|
|
||||||
|
const auto title_id = rp.PopRaw<u64>();
|
||||||
|
|
||||||
|
const auto size = ctx.GetWriteBufferSize();
|
||||||
|
|
||||||
|
const FileSys::PatchManager pm{title_id};
|
||||||
|
const auto control = pm.GetControlMetadata();
|
||||||
|
|
||||||
|
std::vector<u8> out;
|
||||||
|
|
||||||
|
if (control.first != nullptr) {
|
||||||
|
if (size < 0x4000) {
|
||||||
|
LOG_ERROR(Service_NS,
|
||||||
|
"output buffer is too small! (actual={:016X}, expected_min=0x4000)",
|
||||||
|
size);
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
// TODO(DarkLordZach): Find a better error code for this.
|
||||||
|
rb.Push(ResultCode(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.resize(0x4000);
|
||||||
|
const auto bytes = control.first->GetRawBytes();
|
||||||
|
std::memcpy(out.data(), bytes.data(), bytes.size());
|
||||||
|
} else {
|
||||||
|
LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
|
||||||
|
title_id);
|
||||||
|
out.resize(std::min<u64>(0x4000, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (control.second != nullptr) {
|
||||||
|
if (size < 0x4000 + control.second->GetSize()) {
|
||||||
|
LOG_ERROR(Service_NS,
|
||||||
|
"output buffer is too small! (actual={:016X}, expected_min={:016X})",
|
||||||
|
size, 0x4000 + control.second->GetSize());
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
// TODO(DarkLordZach): Find a better error code for this.
|
||||||
|
rb.Push(ResultCode(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.resize(0x4000 + control.second->GetSize());
|
||||||
|
control.second->Read(out.data() + 0x4000, control.second->GetSize());
|
||||||
|
} else {
|
||||||
|
LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
|
||||||
|
title_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.WriteBuffer(out);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.Push<u32>(static_cast<u32>(out.size()));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
|
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
|
||||||
|
|
Reference in New Issue