From 9e5bc98496ef59bd2e30e7157b1d33a363ac538f Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 8 Jun 2022 23:07:15 +0200 Subject: [PATCH 1/4] DiscIO/RiivolutionPatcher: Skip main.dol patches if no main.dol was given. --- Source/Core/DiscIO/RiivolutionPatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index e3d3d88af9..a9593dddcd 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -397,7 +397,7 @@ static void ApplyFilePatchToFST(const Patch& patch, const File& file, if (node) ApplyPatchToFile(patch, file, node); } - else if (CaseInsensitiveEquals(file.m_disc, "main.dol")) + else if (dol_node && CaseInsensitiveEquals(file.m_disc, "main.dol")) { // Special case: If the filename is "main.dol", we want to patch the main executable. ApplyPatchToFile(patch, file, dol_node); From f5c132580ced295a5e795be8cf4c65de7d4624a3 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Thu, 9 Jun 2022 00:17:20 +0200 Subject: [PATCH 2/4] DiscIO/DirectoryBlob: Add ContentSource that stores data locally in std::vector. --- Source/Core/DiscIO/DirectoryBlob.cpp | 6 ++++++ Source/Core/DiscIO/DirectoryBlob.h | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 86de55595a..c8facd37de 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -134,6 +134,12 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const const ContentFixedByte& source = std::get(m_content_source); std::fill_n(*buffer, bytes_to_read, source.m_byte); } + else if (std::holds_alternative(m_content_source)) + { + const ContentByteVector& source = std::get(m_content_source); + std::copy(source.m_bytes.begin() + offset_in_content, + source.m_bytes.begin() + offset_in_content + bytes_to_read, *buffer); + } else { PanicAlertFmt("DirectoryBlob: Invalid content source in DiscContent."); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 3e8c4d9292..31e3650b08 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -80,11 +80,18 @@ struct ContentFixedByte u8 m_byte; }; +// Content chunk representing an arbitrary byte sequence that's stored within the struct itself. +struct ContentByteVector +{ + std::vector m_bytes; +}; + using ContentSource = std::variant; struct BuilderContentSource From cc315cb7afa26693979d6faf43bedd6dd50722e1 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Thu, 9 Jun 2022 00:25:11 +0200 Subject: [PATCH 3/4] DiscIO/Riivolution: Add dolphin-specific extensions "dolphin_sys_file" and "dolphin_sys_folder" to patch sys files like you would patch regular files. --- Source/Core/Core/Boot/Boot.cpp | 3 ++- Source/Core/DiscIO/RiivolutionParser.cpp | 11 +++++++---- Source/Core/DiscIO/RiivolutionParser.h | 2 ++ Source/Core/DiscIO/RiivolutionPatcher.cpp | 11 ++++++++--- Source/Core/DiscIO/RiivolutionPatcher.h | 8 +++++++- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 86ea8e2179..94b66bd687 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -701,7 +701,8 @@ void AddRiivolutionPatches(BootParameters* boot_params, disc.volume = DiscIO::CreateDisc(DiscIO::DirectoryBlobReader::Create( std::move(disc.volume), [&](std::vector* fst, DiscIO::FSTBuilderNode* dol_node) { - DiscIO::Riivolution::ApplyPatchesToFiles(riivolution_patches, fst, dol_node); + DiscIO::Riivolution::ApplyPatchesToFiles( + riivolution_patches, DiscIO::Riivolution::PatchIndex::FileSystem, fst, dol_node); })); boot_params->riivolution_patches = std::move(riivolution_patches); } diff --git a/Source/Core/DiscIO/RiivolutionParser.cpp b/Source/Core/DiscIO/RiivolutionParser.cpp index 283e5876df..dacbbbcfc5 100644 --- a/Source/Core/DiscIO/RiivolutionParser.cpp +++ b/Source/Core/DiscIO/RiivolutionParser.cpp @@ -172,9 +172,10 @@ std::optional ParseString(std::string_view xml, std::string xml_path) for (const auto& patch_subnode : patch_node.children()) { const std::string_view patch_name(patch_subnode.name()); - if (patch_name == "file") + if (patch_name == "file" || patch_name == "dolphin_sys_file") { - auto& file = patch.m_file_patches.emplace_back(); + auto& file = patch_name == "dolphin_sys_file" ? patch.m_sys_file_patches.emplace_back() : + patch.m_file_patches.emplace_back(); file.m_disc = patch_subnode.attribute("disc").as_string(); file.m_external = patch_subnode.attribute("external").as_string(); file.m_resize = patch_subnode.attribute("resize").as_bool(true); @@ -183,9 +184,11 @@ std::optional ParseString(std::string_view xml, std::string xml_path) file.m_fileoffset = patch_subnode.attribute("fileoffset").as_uint(0); file.m_length = patch_subnode.attribute("length").as_uint(0); } - else if (patch_name == "folder") + else if (patch_name == "folder" || patch_name == "dolphin_sys_folder") { - auto& folder = patch.m_folder_patches.emplace_back(); + auto& folder = patch_name == "dolphin_sys_folder" ? + patch.m_sys_folder_patches.emplace_back() : + patch.m_folder_patches.emplace_back(); folder.m_disc = patch_subnode.attribute("disc").as_string(); folder.m_external = patch_subnode.attribute("external").as_string(); folder.m_resize = patch_subnode.attribute("resize").as_bool(true); diff --git a/Source/Core/DiscIO/RiivolutionParser.h b/Source/Core/DiscIO/RiivolutionParser.h index f9f03f67c1..9ec6c92959 100644 --- a/Source/Core/DiscIO/RiivolutionParser.h +++ b/Source/Core/DiscIO/RiivolutionParser.h @@ -166,6 +166,8 @@ struct Patch std::vector m_file_patches; std::vector m_folder_patches; + std::vector m_sys_file_patches; + std::vector m_sys_folder_patches; std::vector m_savegame_patches; std::vector m_memory_patches; diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index a9593dddcd..8ad65f8c57 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -458,15 +458,20 @@ static void ApplyFolderPatchToFST(const Patch& patch, const Folder& folder, ApplyFolderPatchToFST(patch, folder, fst, dol_node, folder.m_disc, folder.m_external); } -void ApplyPatchesToFiles(const std::vector& patches, +void ApplyPatchesToFiles(const std::vector& patches, PatchIndex index, std::vector* fst, DiscIO::FSTBuilderNode* dol_node) { for (const auto& patch : patches) { - for (const auto& file : patch.m_file_patches) + const auto& file_patches = + index == PatchIndex::DolphinSysFiles ? patch.m_sys_file_patches : patch.m_file_patches; + const auto& folder_patches = + index == PatchIndex::DolphinSysFiles ? patch.m_sys_folder_patches : patch.m_folder_patches; + + for (const auto& file : file_patches) ApplyFilePatchToFST(patch, file, fst, dol_node); - for (const auto& folder : patch.m_folder_patches) + for (const auto& folder : folder_patches) ApplyFolderPatchToFST(patch, folder, fst, dol_node); } } diff --git a/Source/Core/DiscIO/RiivolutionPatcher.h b/Source/Core/DiscIO/RiivolutionPatcher.h index 0f3de33caf..0a83ba9d13 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.h +++ b/Source/Core/DiscIO/RiivolutionPatcher.h @@ -65,7 +65,13 @@ private: std::string m_patch_root; }; -void ApplyPatchesToFiles(const std::vector& patches, +enum class PatchIndex +{ + FileSystem, + DolphinSysFiles, +}; + +void ApplyPatchesToFiles(const std::vector& patches, PatchIndex index, std::vector* fst, DiscIO::FSTBuilderNode* dol_node); void ApplyGeneralMemoryPatches(const std::vector& patches); From ec3cfc01c1d87b038c72f162cefaa631cb788981 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Thu, 9 Jun 2022 00:33:30 +0200 Subject: [PATCH 4/4] DiscIO/DirectoryBlob: Add callback to modify sys files before they're added to the disc. --- Source/Core/Core/Boot/Boot.cpp | 4 ++ Source/Core/DiscIO/DirectoryBlob.cpp | 67 ++++++++++++++++++++++++---- Source/Core/DiscIO/DirectoryBlob.h | 18 +++++--- 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 94b66bd687..ba1e901d61 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -700,6 +700,10 @@ void AddRiivolutionPatches(BootParameters* boot_params, auto& disc = std::get(boot_params->parameters); disc.volume = DiscIO::CreateDisc(DiscIO::DirectoryBlobReader::Create( std::move(disc.volume), + [&](std::vector* fst) { + DiscIO::Riivolution::ApplyPatchesToFiles( + riivolution_patches, DiscIO::Riivolution::PatchIndex::DolphinSysFiles, fst, nullptr); + }, [&](std::vector* fst, DiscIO::FSTBuilderNode* dol_node) { DiscIO::Riivolution::ApplyPatchesToFiles( riivolution_patches, DiscIO::Riivolution::PatchIndex::FileSystem, fst, dol_node); diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index c8facd37de..7decaac2e3 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -362,6 +362,7 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri std::unique_ptr DirectoryBlobReader::Create( std::unique_ptr volume, + const std::function* fst_nodes)>& sys_callback, const std::function* fst_nodes, FSTBuilderNode* dol_node)>& fst_callback) { @@ -369,7 +370,7 @@ std::unique_ptr DirectoryBlobReader::Create( return nullptr; return std::unique_ptr( - new DirectoryBlobReader(std::move(volume), fst_callback)); + new DirectoryBlobReader(std::move(volume), sys_callback, fst_callback)); } DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, @@ -418,12 +419,14 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, DirectoryBlobReader::DirectoryBlobReader( std::unique_ptr volume, + const std::function* fst_nodes)>& sys_callback, const std::function* fst_nodes, FSTBuilderNode* dol_node)>& fst_callback) : m_encryption_cache(this), m_wrapped_volume(std::move(volume)) { - DirectoryBlobPartition game_partition( - m_wrapped_volume.get(), m_wrapped_volume->GetGamePartition(), std::nullopt, fst_callback); + DirectoryBlobPartition game_partition(m_wrapped_volume.get(), + m_wrapped_volume->GetGamePartition(), std::nullopt, + sys_callback, fst_callback); m_is_wii = game_partition.IsWii(); if (!m_is_wii) @@ -463,7 +466,7 @@ DirectoryBlobReader::DirectoryBlobReader( if (type) { partitions.emplace_back( - DirectoryBlobPartition(m_wrapped_volume.get(), partition, m_is_wii, nullptr), + DirectoryBlobPartition(m_wrapped_volume.get(), partition, m_is_wii, nullptr, nullptr), static_cast(*type)); } } @@ -820,32 +823,80 @@ DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory BuildFSTFromFolder(m_root_directory + "files/", fst_address); } +static void FillSingleFileNode(FSTBuilderNode* node, std::vector data) +{ + std::vector contents; + const size_t size = data.size(); + contents.emplace_back(BuilderContentSource{0, size, ContentByteVector{std::move(data)}}); + node->m_size = size; + node->m_content = std::move(contents); +} + +static FSTBuilderNode BuildSingleFileNode(std::string filename, std::vector data, + void* userdata) +{ + FSTBuilderNode node{std::move(filename), 0, {}, userdata}; + FillSingleFileNode(&node, std::move(data)); + return node; +} + +static std::vector ExtractNodeToVector(std::vector* nodes, void* userdata) +{ + std::vector data; + const auto it = + std::find_if(nodes->begin(), nodes->end(), [&userdata](const FSTBuilderNode& node) { + return node.m_user_data == userdata; + }); + if (it == nodes->end() || !it->IsFile()) + return data; + + DiscContentContainer tmp; + for (auto& content : it->GetFileContent()) + tmp.Add(content.m_offset, content.m_size, std::move(content.m_source)); + data.resize(it->m_size); + tmp.Read(0, it->m_size, data.data()); + return data; +} + DirectoryBlobPartition::DirectoryBlobPartition( DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional is_wii, + const std::function* fst_nodes)>& sys_callback, const std::function* fst_nodes, FSTBuilderNode* dol_node)>& fst_callback) : m_wrapped_partition(partition) { + std::vector sys_nodes; + std::vector disc_header(DISCHEADER_SIZE); if (!volume->Read(DISCHEADER_ADDRESS, DISCHEADER_SIZE, disc_header.data(), partition)) disc_header.clear(); - SetDiscHeader(std::move(disc_header)); - SetDiscType(is_wii); + sys_nodes.emplace_back(BuildSingleFileNode("boot.bin", std::move(disc_header), &m_disc_header)); std::vector bi2(BI2_SIZE); if (!volume->Read(BI2_ADDRESS, BI2_SIZE, bi2.data(), partition)) bi2.clear(); - SetBI2(std::move(bi2)); + sys_nodes.emplace_back(BuildSingleFileNode("bi2.bin", std::move(bi2), &m_bi2)); std::vector apploader; const auto apploader_size = GetApploaderSize(*volume, partition); + auto& apploader_node = + sys_nodes.emplace_back(FSTBuilderNode{"apploader.img", 0, {}, &m_apploader}); if (apploader_size) { apploader.resize(*apploader_size); if (!volume->Read(APPLOADER_ADDRESS, *apploader_size, apploader.data(), partition)) apploader.clear(); + FillSingleFileNode(&apploader_node, std::move(apploader)); } - const u64 new_dol_address = SetApploader(apploader, "apploader"); + + if (sys_callback) + sys_callback(&sys_nodes); + + SetDiscHeader(ExtractNodeToVector(&sys_nodes, &m_disc_header)); + SetDiscType(is_wii); + SetBI2(ExtractNodeToVector(&sys_nodes, &m_bi2)); + const u64 new_dol_address = + SetApploader(ExtractNodeToVector(&sys_nodes, &m_apploader), "apploader"); FSTBuilderNode dol_node{"main.dol", 0, {}}; const auto dol_offset = GetBootDOLOffset(*volume, partition); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 31e3650b08..a06e60688f 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -190,10 +190,11 @@ class DirectoryBlobPartition public: DirectoryBlobPartition() = default; DirectoryBlobPartition(const std::string& root_directory, std::optional is_wii); - DirectoryBlobPartition(DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, - std::optional is_wii, - const std::function* fst_nodes, - FSTBuilderNode* dol_node)>& fst_callback); + DirectoryBlobPartition( + DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional is_wii, + const std::function* fst_nodes)>& sys_callback, + const std::function* fst_nodes, FSTBuilderNode* dol_node)>& + fst_callback); // We do not allow copying, because it might mess up the pointers inside DiscContents DirectoryBlobPartition(const DirectoryBlobPartition&) = delete; @@ -265,6 +266,7 @@ public: static std::unique_ptr Create(const std::string& dol_path); static std::unique_ptr Create( std::unique_ptr volume, + const std::function* fst_nodes)>& sys_callback, const std::function* fst_nodes, FSTBuilderNode* dol_node)>& fst_callback); @@ -303,9 +305,11 @@ private: explicit DirectoryBlobReader(const std::string& game_partition_root, const std::string& true_root); - explicit DirectoryBlobReader(std::unique_ptr volume, - const std::function* fst_nodes, - FSTBuilderNode* dol_node)>& fst_callback); + explicit DirectoryBlobReader( + std::unique_ptr volume, + const std::function* fst_nodes)>& sys_callback, + const std::function* fst_nodes, FSTBuilderNode* dol_node)>& + fst_callback); const DirectoryBlobPartition* GetPartition(u64 offset, u64 size, u64 partition_data_offset) const;