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:
Zach Hilman 2018-10-29 16:20:10 -04:00
parent 5ee19add1b
commit bdaa76c0db
4 changed files with 75 additions and 17 deletions

View File

@ -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));
} }

View File

@ -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,

View File

@ -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(),

View File

@ -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> {