mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-02 16:49:04 +00:00
Reworked Savegame to accept raw DISA archive instead
Also fixed couple issues with LoadSharedRomFS
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user