Reworked Savegame to accept raw DISA archive instead

Also fixed couple issues with LoadSharedRomFS
This commit is contained in:
Pengfei
2021-09-01 18:51:31 +08:00
parent 34d352b3cc
commit 26df204814
5 changed files with 42 additions and 81 deletions
+18 -2
View File
@@ -2,16 +2,32 @@
// 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 "core/file_sys/data/data_container.h"
#include "core/file_sys/data/savegame.h" #include "core/file_sys/data/savegame.h"
namespace Core { namespace Core {
Savegame::Savegame(std::vector<std::vector<u8>> partitions) { Savegame::Savegame(std::vector<u8> data) {
is_good = Archive<Savegame>::Init(std::move(partitions)); is_good = Init(std::move(data));
} }
Savegame::~Savegame() = default; Savegame::~Savegame() = default;
bool Savegame::Init(std::vector<u8> data) {
if (data.empty()) {
return false;
}
DataContainer container(std::move(data));
std::vector<std::vector<u8>> partitions;
if (!container.IsGood() || !container.GetIVFCLevel4Data(partitions)) {
return false;
}
return Archive<Savegame>::Init(std::move(partitions));
}
bool Savegame::CheckMagic() const { bool Savegame::CheckMagic() const {
if (header.fat_header.magic != MakeMagic('S', 'A', 'V', 'E') || if (header.fat_header.magic != MakeMagic('S', 'A', 'V', 'E') ||
header.fat_header.version != 0x40000) { header.fat_header.version != 0x40000) {
+3 -1
View File
@@ -10,13 +10,15 @@ namespace Core {
class Savegame final : public Archive<Savegame> { class Savegame final : public Archive<Savegame> {
public: public:
explicit Savegame(std::vector<std::vector<u8>> partitions); /// @param data Data of the DISA archive
explicit Savegame(std::vector<u8> data);
~Savegame(); ~Savegame();
bool IsGood() const; bool IsGood() const;
bool Extract(std::string path) const; bool Extract(std::string path) const;
private: private:
bool Init(std::vector<u8> data);
bool CheckMagic() const; bool CheckMagic() const;
bool ExtractFile(const std::string& path, std::size_t index) const; bool ExtractFile(const std::string& path, std::size_t index) const;
ArchiveFormatInfo GetFormatInfo() const; ArchiveFormatInfo GetFormatInfo() const;
+13 -8
View File
@@ -589,16 +589,20 @@ static_assert(sizeof(RomFSIVFCHeader) == 0x60, "Size of RomFSIVFCHeader is incor
std::vector<u8> LoadSharedRomFS(const std::vector<u8>& data) { std::vector<u8> LoadSharedRomFS(const std::vector<u8>& data) {
NCCH_Header header; NCCH_Header header;
ASSERT_MSG(data.size() >= sizeof(header), "NCCH size is too small"); if (!CheckedMemcpy(&header, data, 0, sizeof(header))) {
std::memcpy(&header, data.data(), sizeof(header)); return {};
}
const std::size_t offset = header.romfs_offset * 0x200; // 0x200: Media unit const std::size_t offset = header.romfs_offset * 0x200; // 0x200: Media unit
RomFSIVFCHeader ivfc; RomFSIVFCHeader ivfc;
ASSERT_MSG(data.size() >= offset + sizeof(ivfc), "NCCH size is too small"); if (!CheckedMemcpy(&ivfc, data, offset, sizeof(ivfc))) {
std::memcpy(&ivfc, data.data() + offset, sizeof(ivfc)); return {};
}
ASSERT_MSG(ivfc.magic == MakeMagic('I', 'V', 'F', 'C'), "IVFC magic is incorrect"); if (ivfc.magic != MakeMagic('I', 'V', 'F', 'C') || ivfc.version != 0x10000) {
ASSERT_MSG(ivfc.version == 0x10000, "IVFC version is incorrect"); LOG_ERROR(Core, "IVFC magic/version is wrong");
return {};
}
std::vector<u8> result(ivfc.levels[2].size); std::vector<u8> result(ivfc.levels[2].size);
@@ -606,8 +610,9 @@ std::vector<u8> LoadSharedRomFS(const std::vector<u8>& data) {
const std::size_t data_offset = const std::size_t data_offset =
offset + Common::AlignUp(sizeof(ivfc) + ivfc.master_hash_size, offset + Common::AlignUp(sizeof(ivfc) + ivfc.master_hash_size,
std::pow(2, ivfc.levels[2].block_size)); std::pow(2, ivfc.levels[2].block_size));
ASSERT_MSG(data.size() >= data_offset + ivfc.levels[2].size); if (!CheckedMemcpy(result.data(), data, data_offset, ivfc.levels[2].size)) {
std::memcpy(result.data(), data.data() + data_offset, ivfc.levels[2].size); return {};
}
return result; return result;
} }
+4 -33
View File
@@ -100,18 +100,11 @@ bool SDMCImporter::Init() {
void SDMCImporter::LoadSystemLanguage() { void SDMCImporter::LoadSystemLanguage() {
FileUtil::IOFile file(nand_config.data_path + "sysdata/00010017/00000000", "rb"); FileUtil::IOFile file(nand_config.data_path + "sysdata/00010017/00000000", "rb");
if (!file) { Savegame save(file.GetData());
LOG_ERROR(Core, "Could not open config savegame"); if (!save.IsGood()) {
return; return;
} }
DataContainer container(file.GetData());
std::vector<std::vector<u8>> raw_data;
if (!container.IsGood() || !container.GetIVFCLevel4Data(raw_data)) {
return;
}
Savegame save(raw_data);
// Find index of the 'config' file // Find index of the 'config' file
for (std::size_t i = 0; i < save.file_entry_table.size(); ++i) { for (std::size_t i = 0; i < save.file_entry_table.size(); ++i) {
if (std::strncmp(save.file_entry_table[i].name.data(), "config", 16) != 0) { if (std::strncmp(save.file_entry_table[i].name.data(), "config", 16) != 0) {
@@ -246,17 +239,7 @@ bool SDMCImporter::ImportSavegame(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) { [[maybe_unused]] const Common::ProgressCallback& callback) {
const auto path = fmt::format("title/{:08x}/{:08x}/data/", (id >> 32), (id & 0xFFFFFFFF)); const auto path = fmt::format("title/{:08x}/{:08x}/data/", (id >> 32), (id & 0xFFFFFFFF));
DataContainer container(sdmc_decryptor->DecryptFile(fmt::format("/{}00000001.sav", path))); Savegame save(sdmc_decryptor->DecryptFile(fmt::format("/{}00000001.sav", path)));
if (!container.IsGood()) {
return false;
}
std::vector<std::vector<u8>> container_data;
if (!container.GetIVFCLevel4Data(container_data)) {
return false;
}
Savegame save(std::move(container_data));
if (!save.IsGood()) { if (!save.IsGood()) {
return false; return false;
} }
@@ -271,19 +254,7 @@ bool SDMCImporter::ImportNandSavegame(u64 id,
const auto path = fmt::format("sysdata/{:08x}/00000000", (id & 0xFFFFFFFF)); const auto path = fmt::format("sysdata/{:08x}/00000000", (id & 0xFFFFFFFF));
FileUtil::IOFile file(nand_config.data_path + path, "rb"); FileUtil::IOFile file(nand_config.data_path + path, "rb");
std::vector<u8> data = file.GetData(); Savegame save(file.GetData());
if (data.empty()) {
LOG_ERROR(Core, "Failed to read from {}", path);
return false;
}
DataContainer container(std::move(data));
std::vector<std::vector<u8>> container_data;
if (!container.GetIVFCLevel4Data(container_data)) {
return false;
}
Savegame save(std::move(container_data));
if (!save.IsGood()) { if (!save.IsGood()) {
return false; return false;
} }
+4 -37
View File
@@ -189,24 +189,8 @@ void UtilitiesDialog::SaveDataExtractionTool() {
// TODO: Add Progress reporting // TODO: Add Progress reporting
ShowProgressDialog([sdmc_root = sdmc_root, relative_source = relative_source, ShowProgressDialog([sdmc_root = sdmc_root, relative_source = relative_source,
source = source, destination = destination] { source = source, destination = destination] {
const auto size = FileUtil::GetSize(source.toStdString());
std::vector<u8> data(size);
Core::SDMCFile file(sdmc_root, relative_source, "rb"); Core::SDMCFile file(sdmc_root, relative_source, "rb");
if (file.ReadBytes(data.data(), size) != size) { Core::Savegame save(file.GetData());
return false;
}
Core::DataContainer container(data);
if (!container.IsGood()) {
return false;
}
std::vector<std::vector<u8>> container_data;
if (!container.GetIVFCLevel4Data(container_data)) {
return false;
}
Core::Savegame save(std::move(container_data));
if (!save.IsGood()) { if (!save.IsGood()) {
return false; return false;
} }
@@ -217,22 +201,7 @@ void UtilitiesDialog::SaveDataExtractionTool() {
// TODO: Add Progress reporting // TODO: Add Progress reporting
ShowProgressDialog([source = source, destination = destination] { ShowProgressDialog([source = source, destination = destination] {
FileUtil::IOFile file(source.toStdString(), "rb"); FileUtil::IOFile file(source.toStdString(), "rb");
std::vector<u8> data = file.GetData(); Core::Savegame save(file.GetData());
if (data.empty()) {
return false;
}
Core::DataContainer container(data);
if (!container.IsGood()) {
return false;
}
std::vector<std::vector<u8>> container_data;
if (!container.GetIVFCLevel4Data(container_data)) {
return false;
}
Core::Savegame save(std::move(container_data));
if (!save.IsGood()) { if (!save.IsGood()) {
return false; return false;
} }
@@ -276,12 +245,10 @@ void UtilitiesDialog::RomFSExtractionTool() {
ShowProgressDialog([source = source, destination = destination] { ShowProgressDialog([source = source, destination = destination] {
FileUtil::IOFile src_file(source.toStdString(), "rb"); FileUtil::IOFile src_file(source.toStdString(), "rb");
std::vector<u8> data = src_file.GetData(); const auto& shared_romfs = Core::LoadSharedRomFS(src_file.GetData());
if (data.empty()) { if (shared_romfs.empty()) {
return false; return false;
} }
const auto& shared_romfs = Core::LoadSharedRomFS(data);
return FileUtil::WriteBytesToFile(destination.toStdString(), shared_romfs.data(), return FileUtil::WriteBytesToFile(destination.toStdString(), shared_romfs.data(),
shared_romfs.size()); shared_romfs.size());
}); });