Merge pull request #1879 from DarkLordZach/am-save-data-size
am: Implement GetSaveDataSize and ExtendSaveData using files
This commit is contained in:
commit
c4515d305b
15 changed files with 199 additions and 32 deletions
|
@ -36,18 +36,20 @@ std::string LanguageEntry::GetDeveloperName() const {
|
||||||
developer_name.size());
|
developer_name.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
|
NACP::NACP() = default;
|
||||||
file->ReadObject(raw.get());
|
|
||||||
|
NACP::NACP(VirtualFile file) {
|
||||||
|
file->ReadObject(&raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
NACP::~NACP() = default;
|
NACP::~NACP() = default;
|
||||||
|
|
||||||
const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
|
const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
|
||||||
if (language != Language::Default) {
|
if (language != Language::Default) {
|
||||||
return raw->language_entries.at(static_cast<u8>(language));
|
return raw.language_entries.at(static_cast<u8>(language));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& language_entry : raw->language_entries) {
|
for (const auto& language_entry : raw.language_entries) {
|
||||||
if (!language_entry.GetApplicationName().empty())
|
if (!language_entry.GetApplicationName().empty())
|
||||||
return language_entry;
|
return language_entry;
|
||||||
}
|
}
|
||||||
|
@ -65,21 +67,29 @@ std::string NACP::GetDeveloperName(Language language) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NACP::GetTitleId() const {
|
u64 NACP::GetTitleId() const {
|
||||||
return raw->title_id;
|
return raw.title_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NACP::GetDLCBaseTitleId() const {
|
u64 NACP::GetDLCBaseTitleId() const {
|
||||||
return raw->dlc_base_title_id;
|
return raw.dlc_base_title_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NACP::GetVersionString() const {
|
std::string NACP::GetVersionString() const {
|
||||||
return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
|
return Common::StringFromFixedZeroTerminatedBuffer(raw.version_string.data(),
|
||||||
raw->version_string.size());
|
raw.version_string.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 NACP::GetDefaultNormalSaveSize() const {
|
||||||
|
return raw.normal_save_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 NACP::GetDefaultJournalSaveSize() const {
|
||||||
|
return raw.journal_sava_data_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> NACP::GetRawBytes() const {
|
std::vector<u8> NACP::GetRawBytes() const {
|
||||||
std::vector<u8> out(sizeof(RawNACP));
|
std::vector<u8> out(sizeof(RawNACP));
|
||||||
std::memcpy(out.data(), raw.get(), sizeof(RawNACP));
|
std::memcpy(out.data(), &raw, sizeof(RawNACP));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -28,17 +28,30 @@ static_assert(sizeof(LanguageEntry) == 0x300, "LanguageEntry has incorrect size.
|
||||||
// The raw file format of a NACP file.
|
// The raw file format of a NACP file.
|
||||||
struct RawNACP {
|
struct RawNACP {
|
||||||
std::array<LanguageEntry, 16> language_entries;
|
std::array<LanguageEntry, 16> language_entries;
|
||||||
INSERT_PADDING_BYTES(0x38);
|
std::array<u8, 0x25> isbn;
|
||||||
|
u8 startup_user_account;
|
||||||
|
INSERT_PADDING_BYTES(2);
|
||||||
|
u32_le application_attribute;
|
||||||
|
u32_le supported_languages;
|
||||||
|
u32_le parental_control;
|
||||||
|
bool screenshot_enabled;
|
||||||
|
u8 video_capture_mode;
|
||||||
|
bool data_loss_confirmation;
|
||||||
|
INSERT_PADDING_BYTES(1);
|
||||||
u64_le title_id;
|
u64_le title_id;
|
||||||
INSERT_PADDING_BYTES(0x20);
|
std::array<u8, 0x20> rating_age;
|
||||||
std::array<char, 0x10> version_string;
|
std::array<char, 0x10> version_string;
|
||||||
u64_le dlc_base_title_id;
|
u64_le dlc_base_title_id;
|
||||||
u64_le title_id_2;
|
u64_le title_id_2;
|
||||||
INSERT_PADDING_BYTES(0x28);
|
u64_le normal_save_data_size;
|
||||||
|
u64_le journal_sava_data_size;
|
||||||
|
INSERT_PADDING_BYTES(0x18);
|
||||||
u64_le product_code;
|
u64_le product_code;
|
||||||
u64_le title_id_3;
|
std::array<u64_le, 0x8> local_communication;
|
||||||
std::array<u64_le, 0x7> title_id_array;
|
u8 logo_type;
|
||||||
INSERT_PADDING_BYTES(0x8);
|
u8 logo_handling;
|
||||||
|
bool runtime_add_on_content_install;
|
||||||
|
INSERT_PADDING_BYTES(5);
|
||||||
u64_le title_id_update;
|
u64_le title_id_update;
|
||||||
std::array<u8, 0x40> bcat_passphrase;
|
std::array<u8, 0x40> bcat_passphrase;
|
||||||
INSERT_PADDING_BYTES(0xEC0);
|
INSERT_PADDING_BYTES(0xEC0);
|
||||||
|
@ -72,6 +85,7 @@ extern const std::array<const char*, 15> LANGUAGE_NAMES;
|
||||||
// These store application name, dev name, title id, and other miscellaneous data.
|
// These store application name, dev name, title id, and other miscellaneous data.
|
||||||
class NACP {
|
class NACP {
|
||||||
public:
|
public:
|
||||||
|
explicit NACP();
|
||||||
explicit NACP(VirtualFile file);
|
explicit NACP(VirtualFile file);
|
||||||
~NACP();
|
~NACP();
|
||||||
|
|
||||||
|
@ -81,10 +95,12 @@ public:
|
||||||
u64 GetTitleId() const;
|
u64 GetTitleId() const;
|
||||||
u64 GetDLCBaseTitleId() const;
|
u64 GetDLCBaseTitleId() const;
|
||||||
std::string GetVersionString() const;
|
std::string GetVersionString() const;
|
||||||
|
u64 GetDefaultNormalSaveSize() const;
|
||||||
|
u64 GetDefaultJournalSaveSize() const;
|
||||||
std::vector<u8> GetRawBytes() const;
|
std::vector<u8> GetRawBytes() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<RawNACP> raw;
|
RawNACP raw{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
|
constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
|
||||||
|
|
||||||
std::string SaveDataDescriptor::DebugInfo() const {
|
std::string SaveDataDescriptor::DebugInfo() const {
|
||||||
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
|
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
|
||||||
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
|
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
|
||||||
|
@ -132,4 +134,32 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||||
|
u128 user_id) const {
|
||||||
|
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||||
|
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
|
||||||
|
|
||||||
|
const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME);
|
||||||
|
if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize))
|
||||||
|
return {0, 0};
|
||||||
|
|
||||||
|
SaveDataSize out;
|
||||||
|
if (size_file->ReadObject(&out) != sizeof(SaveDataSize))
|
||||||
|
return {0, 0};
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||||
|
SaveDataSize new_value) {
|
||||||
|
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||||
|
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
|
||||||
|
|
||||||
|
const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
|
||||||
|
if (size_file == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_file->Resize(sizeof(SaveDataSize));
|
||||||
|
size_file->WriteObject(new_value);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -46,6 +46,11 @@ struct SaveDataDescriptor {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size.");
|
static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size.");
|
||||||
|
|
||||||
|
struct SaveDataSize {
|
||||||
|
u64 normal;
|
||||||
|
u64 journal;
|
||||||
|
};
|
||||||
|
|
||||||
/// File system interface to the SaveData archive
|
/// File system interface to the SaveData archive
|
||||||
class SaveDataFactory {
|
class SaveDataFactory {
|
||||||
public:
|
public:
|
||||||
|
@ -60,6 +65,9 @@ public:
|
||||||
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
||||||
u128 user_id, u64 save_id);
|
u128 user_id, u64 save_id);
|
||||||
|
|
||||||
|
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
|
||||||
|
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VirtualDir dir;
|
VirtualDir dir;
|
||||||
};
|
};
|
||||||
|
|
|
@ -150,7 +150,7 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) {
|
std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) {
|
||||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||||
return Write(data, number_elements * sizeof(T), offset);
|
return Write(reinterpret_cast<const u8*>(data), number_elements * sizeof(T), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes size bytes starting at memory location data to offset in file.
|
// Writes size bytes starting at memory location data to offset in file.
|
||||||
|
@ -166,7 +166,7 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::size_t WriteObject(const T& data, std::size_t offset = 0) {
|
std::size_t WriteObject(const T& data, std::size_t offset = 0) {
|
||||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||||
return Write(&data, sizeof(T), offset);
|
return Write(reinterpret_cast<const u8*>(&data), sizeof(T), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renames the file to name. Returns whether or not the operation was successsful.
|
// Renames the file to name. Returns whether or not the operation was successsful.
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include "audio_core/audio_renderer.h"
|
#include "audio_core/audio_renderer.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/savedata_factory.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
@ -865,8 +866,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
|
||||||
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
|
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
|
||||||
{23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
|
{23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
|
||||||
{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||||
{25, nullptr, "ExtendSaveData"},
|
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
|
||||||
{26, nullptr, "GetSaveDataSize"},
|
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
|
||||||
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
|
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
|
||||||
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
|
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
|
||||||
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
|
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
|
||||||
|
@ -1043,6 +1044,48 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
|
||||||
rb.Push<u64>(0);
|
rb.Push<u64>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto type{rp.PopRaw<FileSys::SaveDataType>()};
|
||||||
|
rp.Skip(1, false);
|
||||||
|
const auto user_id{rp.PopRaw<u128>()};
|
||||||
|
const auto new_normal_size{rp.PopRaw<u64>()};
|
||||||
|
const auto new_journal_size{rp.PopRaw<u64>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AM,
|
||||||
|
"called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
|
||||||
|
"new_journal={:016X}",
|
||||||
|
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
|
||||||
|
|
||||||
|
FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id,
|
||||||
|
{new_normal_size, new_journal_size});
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
|
// The following value is used upon failure to help the system recover.
|
||||||
|
// Since we always succeed, this should be 0.
|
||||||
|
rb.Push<u64>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto type{rp.PopRaw<FileSys::SaveDataType>()};
|
||||||
|
rp.Skip(1, false);
|
||||||
|
const auto user_id{rp.PopRaw<u128>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
|
||||||
|
user_id[1], user_id[0]);
|
||||||
|
|
||||||
|
const auto size =
|
||||||
|
FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 6};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.Push(size.normal);
|
||||||
|
rb.Push(size.journal);
|
||||||
|
}
|
||||||
|
|
||||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
|
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
|
||||||
auto message_queue = std::make_shared<AppletMessageQueue>();
|
auto message_queue = std::make_shared<AppletMessageQueue>();
|
||||||
|
|
|
@ -206,6 +206,8 @@ private:
|
||||||
void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx);
|
void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx);
|
||||||
void NotifyRunning(Kernel::HLERequestContext& ctx);
|
void NotifyRunning(Kernel::HLERequestContext& ctx);
|
||||||
void GetPseudoDeviceId(Kernel::HLERequestContext& ctx);
|
void GetPseudoDeviceId(Kernel::HLERequestContext& ctx);
|
||||||
|
void ExtendSaveData(Kernel::HLERequestContext& ctx);
|
||||||
|
void GetSaveDataSize(Kernel::HLERequestContext& ctx);
|
||||||
void BeginBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
|
void BeginBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
|
||||||
void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
|
void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
|
||||||
void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx);
|
void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx);
|
||||||
|
|
|
@ -8,18 +8,23 @@
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/file_sys/bis_factory.h"
|
#include "core/file_sys/bis_factory.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
#include "core/file_sys/mode.h"
|
#include "core/file_sys/mode.h"
|
||||||
|
#include "core/file_sys/partition_filesystem.h"
|
||||||
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/file_sys/registered_cache.h"
|
#include "core/file_sys/registered_cache.h"
|
||||||
#include "core/file_sys/romfs_factory.h"
|
#include "core/file_sys/romfs_factory.h"
|
||||||
#include "core/file_sys/savedata_factory.h"
|
#include "core/file_sys/savedata_factory.h"
|
||||||
#include "core/file_sys/sdmc_factory.h"
|
#include "core/file_sys/sdmc_factory.h"
|
||||||
#include "core/file_sys/vfs.h"
|
#include "core/file_sys/vfs.h"
|
||||||
#include "core/file_sys/vfs_offset.h"
|
#include "core/file_sys/vfs_offset.h"
|
||||||
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/filesystem/fsp_ldr.h"
|
#include "core/hle/service/filesystem/fsp_ldr.h"
|
||||||
#include "core/hle/service/filesystem/fsp_pr.h"
|
#include "core/hle/service/filesystem/fsp_pr.h"
|
||||||
#include "core/hle/service/filesystem/fsp_srv.h"
|
#include "core/hle/service/filesystem/fsp_srv.h"
|
||||||
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
namespace Service::FileSystem {
|
||||||
|
|
||||||
|
@ -28,6 +33,10 @@ namespace Service::FileSystem {
|
||||||
// TODO(DarkLordZach): Eventually make this configurable in settings.
|
// TODO(DarkLordZach): Eventually make this configurable in settings.
|
||||||
constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
|
constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
|
||||||
|
|
||||||
|
// A default size for normal/journal save data size if application control metadata cannot be found.
|
||||||
|
// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
|
||||||
|
constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
|
||||||
|
|
||||||
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
||||||
std::string_view dir_name_) {
|
std::string_view dir_name_) {
|
||||||
std::string dir_name(FileUtil::SanitizePath(dir_name_));
|
std::string dir_name(FileUtil::SanitizePath(dir_name_));
|
||||||
|
@ -341,6 +350,44 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
|
||||||
return sdmc_factory->Open();
|
return sdmc_factory->Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) {
|
||||||
|
if (save_data_factory == nullptr) {
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id);
|
||||||
|
|
||||||
|
if (value.normal == 0 && value.journal == 0) {
|
||||||
|
FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE};
|
||||||
|
|
||||||
|
FileSys::NACP nacp;
|
||||||
|
const auto res = Core::System::GetInstance().GetAppLoader().ReadControlData(nacp);
|
||||||
|
|
||||||
|
if (res != Loader::ResultStatus::Success) {
|
||||||
|
FileSys::PatchManager pm{Core::CurrentProcess()->GetTitleID()};
|
||||||
|
auto [nacp_unique, discard] = pm.GetControlMetadata();
|
||||||
|
|
||||||
|
if (nacp_unique != nullptr) {
|
||||||
|
new_size = {nacp_unique->GetDefaultNormalSaveSize(),
|
||||||
|
nacp_unique->GetDefaultJournalSaveSize()};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()};
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteSaveDataSize(type, title_id, user_id, new_size);
|
||||||
|
return new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||||
|
FileSys::SaveDataSize new_value) {
|
||||||
|
if (save_data_factory != nullptr)
|
||||||
|
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
FileSys::RegisteredCacheUnion GetUnionContents() {
|
FileSys::RegisteredCacheUnion GetUnionContents() {
|
||||||
return FileSys::RegisteredCacheUnion{
|
return FileSys::RegisteredCacheUnion{
|
||||||
{GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
|
{GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
|
||||||
|
|
|
@ -21,9 +21,11 @@ class SDMCFactory;
|
||||||
enum class ContentRecordType : u8;
|
enum class ContentRecordType : u8;
|
||||||
enum class Mode : u32;
|
enum class Mode : u32;
|
||||||
enum class SaveDataSpaceId : u8;
|
enum class SaveDataSpaceId : u8;
|
||||||
|
enum class SaveDataType : u8;
|
||||||
enum class StorageId : u8;
|
enum class StorageId : u8;
|
||||||
|
|
||||||
struct SaveDataDescriptor;
|
struct SaveDataDescriptor;
|
||||||
|
struct SaveDataSize;
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
@ -48,6 +50,10 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
|
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
|
||||||
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||||
|
|
||||||
|
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id);
|
||||||
|
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||||
|
FileSys::SaveDataSize new_value);
|
||||||
|
|
||||||
FileSys::RegisteredCacheUnion GetUnionContents();
|
FileSys::RegisteredCacheUnion GetUnionContents();
|
||||||
|
|
||||||
FileSys::RegisteredCache* GetSystemNANDContents();
|
FileSys::RegisteredCache* GetSystemNANDContents();
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/vfs.h"
|
#include "core/file_sys/vfs.h"
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
class NACP;
|
||||||
|
} // namespace FileSys
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
struct AddressMapping;
|
struct AddressMapping;
|
||||||
class Process;
|
class Process;
|
||||||
|
@ -245,11 +249,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the developer of the application
|
* Get the control data (CNMT) of the application
|
||||||
* @param developer Reference to store the application developer into
|
* @param control Reference to store the application control data into
|
||||||
* @return ResultStatus result of function
|
* @return ResultStatus result of function
|
||||||
*/
|
*/
|
||||||
virtual ResultStatus ReadDeveloper(std::string& developer) {
|
virtual ResultStatus ReadControlData(FileSys::NACP& control) {
|
||||||
return ResultStatus::ErrorNotImplemented;
|
return ResultStatus::ErrorNotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,10 +152,10 @@ ResultStatus AppLoader_NSP::ReadTitle(std::string& title) {
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NSP::ReadDeveloper(std::string& developer) {
|
ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
|
||||||
if (nacp_file == nullptr)
|
if (nacp_file == nullptr)
|
||||||
return ResultStatus::ErrorNoControl;
|
return ResultStatus::ErrorNoControl;
|
||||||
developer = nacp_file->GetDeveloperName();
|
nacp = *nacp_file;
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||||
ResultStatus ReadTitle(std::string& title) override;
|
ResultStatus ReadTitle(std::string& title) override;
|
||||||
ResultStatus ReadDeveloper(std::string& developer) override;
|
ResultStatus ReadControlData(FileSys::NACP& nacp) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<FileSys::NSP> nsp;
|
std::unique_ptr<FileSys::NSP> nsp;
|
||||||
|
|
|
@ -121,10 +121,11 @@ ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_XCI::ReadDeveloper(std::string& developer) {
|
ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
|
||||||
if (nacp_file == nullptr)
|
if (nacp_file == nullptr)
|
||||||
return ResultStatus::ErrorNoControl;
|
return ResultStatus::ErrorNoControl;
|
||||||
developer = nacp_file->GetDeveloperName();
|
control = *nacp_file;
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||||
ResultStatus ReadTitle(std::string& title) override;
|
ResultStatus ReadTitle(std::string& title) override;
|
||||||
ResultStatus ReadDeveloper(std::string& developer) override;
|
ResultStatus ReadControlData(FileSys::NACP& control) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<FileSys::XCI> xci;
|
std::unique_ptr<FileSys::XCI> xci;
|
||||||
|
|
|
@ -108,9 +108,9 @@ void ConfigurePerGameGeneral::loadConfiguration() {
|
||||||
if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
|
if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
|
||||||
ui->display_name->setText(QString::fromStdString(title));
|
ui->display_name->setText(QString::fromStdString(title));
|
||||||
|
|
||||||
std::string developer;
|
FileSys::NACP nacp;
|
||||||
if (loader->ReadDeveloper(developer) == Loader::ResultStatus::Success)
|
if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success)
|
||||||
ui->display_developer->setText(QString::fromStdString(developer));
|
ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName()));
|
||||||
|
|
||||||
ui->display_version->setText(QStringLiteral("1.0.0"));
|
ui->display_version->setText(QStringLiteral("1.0.0"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue