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
// Refer to the license.txt file included.
#include "core/file_sys/data/data_container.h"
#include "core/file_sys/data/savegame.h"
namespace Core {
Savegame::Savegame(std::vector<std::vector<u8>> partitions) {
is_good = Archive<Savegame>::Init(std::move(partitions));
Savegame::Savegame(std::vector<u8> data) {
is_good = Init(std::move(data));
}
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 {
if (header.fat_header.magic != MakeMagic('S', 'A', 'V', 'E') ||
header.fat_header.version != 0x40000) {
+3 -1
View File
@@ -10,13 +10,15 @@ namespace Core {
class Savegame final : public Archive<Savegame> {
public:
explicit Savegame(std::vector<std::vector<u8>> partitions);
/// @param data Data of the DISA archive
explicit Savegame(std::vector<u8> data);
~Savegame();
bool IsGood() const;
bool Extract(std::string path) const;
private:
bool Init(std::vector<u8> data);
bool CheckMagic() const;
bool ExtractFile(const std::string& path, std::size_t index) 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) {
NCCH_Header header;
ASSERT_MSG(data.size() >= sizeof(header), "NCCH size is too small");
std::memcpy(&header, data.data(), sizeof(header));
if (!CheckedMemcpy(&header, data, 0, sizeof(header))) {
return {};
}
const std::size_t offset = header.romfs_offset * 0x200; // 0x200: Media unit
RomFSIVFCHeader ivfc;
ASSERT_MSG(data.size() >= offset + sizeof(ivfc), "NCCH size is too small");
std::memcpy(&ivfc, data.data() + offset, sizeof(ivfc));
if (!CheckedMemcpy(&ivfc, data, offset, sizeof(ivfc))) {
return {};
}
ASSERT_MSG(ivfc.magic == MakeMagic('I', 'V', 'F', 'C'), "IVFC magic is incorrect");
ASSERT_MSG(ivfc.version == 0x10000, "IVFC version is incorrect");
if (ivfc.magic != MakeMagic('I', 'V', 'F', 'C') || ivfc.version != 0x10000) {
LOG_ERROR(Core, "IVFC magic/version is wrong");
return {};
}
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 =
offset + Common::AlignUp(sizeof(ivfc) + ivfc.master_hash_size,
std::pow(2, ivfc.levels[2].block_size));
ASSERT_MSG(data.size() >= data_offset + ivfc.levels[2].size);
std::memcpy(result.data(), data.data() + data_offset, ivfc.levels[2].size);
if (!CheckedMemcpy(result.data(), data, data_offset, ivfc.levels[2].size)) {
return {};
}
return result;
}
+4 -33
View File
@@ -100,18 +100,11 @@ bool SDMCImporter::Init() {
void SDMCImporter::LoadSystemLanguage() {
FileUtil::IOFile file(nand_config.data_path + "sysdata/00010017/00000000", "rb");
if (!file) {
LOG_ERROR(Core, "Could not open config savegame");
Savegame save(file.GetData());
if (!save.IsGood()) {
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
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) {
@@ -246,17 +239,7 @@ bool SDMCImporter::ImportSavegame(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) {
const auto path = fmt::format("title/{:08x}/{:08x}/data/", (id >> 32), (id & 0xFFFFFFFF));
DataContainer container(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));
Savegame save(sdmc_decryptor->DecryptFile(fmt::format("/{}00000001.sav", path)));
if (!save.IsGood()) {
return false;
}
@@ -271,19 +254,7 @@ bool SDMCImporter::ImportNandSavegame(u64 id,
const auto path = fmt::format("sysdata/{:08x}/00000000", (id & 0xFFFFFFFF));
FileUtil::IOFile file(nand_config.data_path + path, "rb");
std::vector<u8> data = 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));
Savegame save(file.GetData());
if (!save.IsGood()) {
return false;
}
+4 -37
View File
@@ -189,24 +189,8 @@ void UtilitiesDialog::SaveDataExtractionTool() {
// TODO: Add Progress reporting
ShowProgressDialog([sdmc_root = sdmc_root, relative_source = relative_source,
source = source, destination = destination] {
const auto size = FileUtil::GetSize(source.toStdString());
std::vector<u8> data(size);
Core::SDMCFile file(sdmc_root, relative_source, "rb");
if (file.ReadBytes(data.data(), size) != size) {
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));
Core::Savegame save(file.GetData());
if (!save.IsGood()) {
return false;
}
@@ -217,22 +201,7 @@ void UtilitiesDialog::SaveDataExtractionTool() {
// TODO: Add Progress reporting
ShowProgressDialog([source = source, destination = destination] {
FileUtil::IOFile file(source.toStdString(), "rb");
std::vector<u8> data = 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));
Core::Savegame save(file.GetData());
if (!save.IsGood()) {
return false;
}
@@ -276,12 +245,10 @@ void UtilitiesDialog::RomFSExtractionTool() {
ShowProgressDialog([source = source, destination = destination] {
FileUtil::IOFile src_file(source.toStdString(), "rb");
std::vector<u8> data = src_file.GetData();
if (data.empty()) {
const auto& shared_romfs = Core::LoadSharedRomFS(src_file.GetData());
if (shared_romfs.empty()) {
return false;
}
const auto& shared_romfs = Core::LoadSharedRomFS(data);
return FileUtil::WriteBytesToFile(destination.toStdString(), shared_romfs.data(),
shared_romfs.size());
});