diff --git a/src/core/file_sys/data/savegame.cpp b/src/core/file_sys/data/savegame.cpp index 45ed6bf..dc17e40 100644 --- a/src/core/file_sys/data/savegame.cpp +++ b/src/core/file_sys/data/savegame.cpp @@ -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> partitions) { - is_good = Archive::Init(std::move(partitions)); +Savegame::Savegame(std::vector data) { + is_good = Init(std::move(data)); } Savegame::~Savegame() = default; +bool Savegame::Init(std::vector data) { + if (data.empty()) { + return false; + } + + DataContainer container(std::move(data)); + + std::vector> partitions; + if (!container.IsGood() || !container.GetIVFCLevel4Data(partitions)) { + return false; + } + + return Archive::Init(std::move(partitions)); +} + bool Savegame::CheckMagic() const { if (header.fat_header.magic != MakeMagic('S', 'A', 'V', 'E') || header.fat_header.version != 0x40000) { diff --git a/src/core/file_sys/data/savegame.h b/src/core/file_sys/data/savegame.h index 327e4e4..0713481 100644 --- a/src/core/file_sys/data/savegame.h +++ b/src/core/file_sys/data/savegame.h @@ -10,13 +10,15 @@ namespace Core { class Savegame final : public Archive { public: - explicit Savegame(std::vector> partitions); + /// @param data Data of the DISA archive + explicit Savegame(std::vector data); ~Savegame(); bool IsGood() const; bool Extract(std::string path) const; private: + bool Init(std::vector data); bool CheckMagic() const; bool ExtractFile(const std::string& path, std::size_t index) const; ArchiveFormatInfo GetFormatInfo() const; diff --git a/src/core/file_sys/ncch_container.cpp b/src/core/file_sys/ncch_container.cpp index 516b522..df06b2b 100644 --- a/src/core/file_sys/ncch_container.cpp +++ b/src/core/file_sys/ncch_container.cpp @@ -589,16 +589,20 @@ static_assert(sizeof(RomFSIVFCHeader) == 0x60, "Size of RomFSIVFCHeader is incor std::vector LoadSharedRomFS(const std::vector& 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 result(ivfc.levels[2].size); @@ -606,8 +610,9 @@ std::vector LoadSharedRomFS(const std::vector& 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; } diff --git a/src/core/importer.cpp b/src/core/importer.cpp index 642f536..d8e704d 100644 --- a/src/core/importer.cpp +++ b/src/core/importer.cpp @@ -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> 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> 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 data = file.GetData(); - if (data.empty()) { - LOG_ERROR(Core, "Failed to read from {}", path); - return false; - } - - DataContainer container(std::move(data)); - std::vector> container_data; - if (!container.GetIVFCLevel4Data(container_data)) { - return false; - } - - Savegame save(std::move(container_data)); + Savegame save(file.GetData()); if (!save.IsGood()) { return false; } diff --git a/src/frontend/utilities.cpp b/src/frontend/utilities.cpp index 77dd1e7..e25b568 100644 --- a/src/frontend/utilities.cpp +++ b/src/frontend/utilities.cpp @@ -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 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> 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 data = file.GetData(); - if (data.empty()) { - return false; - } - - Core::DataContainer container(data); - if (!container.IsGood()) { - return false; - } - - std::vector> 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 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()); });