Merge pull request #10730 from AdmiralCurtiss/riivolution-sysfile-patches

Riivolution: Add custom extension to patch boot.bin, bi2.bin, and apploader.img.
This commit is contained in:
JMC47 2022-07-28 20:29:31 -04:00 committed by GitHub
commit 3bf1ddc549
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 26 deletions

View File

@ -700,8 +700,13 @@ void AddRiivolutionPatches(BootParameters* boot_params,
auto& disc = std::get<BootParameters::Disc>(boot_params->parameters); auto& disc = std::get<BootParameters::Disc>(boot_params->parameters);
disc.volume = DiscIO::CreateDisc(DiscIO::DirectoryBlobReader::Create( disc.volume = DiscIO::CreateDisc(DiscIO::DirectoryBlobReader::Create(
std::move(disc.volume), std::move(disc.volume),
[&](std::vector<DiscIO::FSTBuilderNode>* fst) {
DiscIO::Riivolution::ApplyPatchesToFiles(
riivolution_patches, DiscIO::Riivolution::PatchIndex::DolphinSysFiles, fst, nullptr);
},
[&](std::vector<DiscIO::FSTBuilderNode>* fst, DiscIO::FSTBuilderNode* dol_node) { [&](std::vector<DiscIO::FSTBuilderNode>* 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); boot_params->riivolution_patches = std::move(riivolution_patches);
} }

View File

@ -134,6 +134,12 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const
const ContentFixedByte& source = std::get<ContentFixedByte>(m_content_source); const ContentFixedByte& source = std::get<ContentFixedByte>(m_content_source);
std::fill_n(*buffer, bytes_to_read, source.m_byte); std::fill_n(*buffer, bytes_to_read, source.m_byte);
} }
else if (std::holds_alternative<ContentByteVector>(m_content_source))
{
const ContentByteVector& source = std::get<ContentByteVector>(m_content_source);
std::copy(source.m_bytes.begin() + offset_in_content,
source.m_bytes.begin() + offset_in_content + bytes_to_read, *buffer);
}
else else
{ {
PanicAlertFmt("DirectoryBlob: Invalid content source in DiscContent."); PanicAlertFmt("DirectoryBlob: Invalid content source in DiscContent.");
@ -356,6 +362,7 @@ std::unique_ptr<DirectoryBlobReader> DirectoryBlobReader::Create(const std::stri
std::unique_ptr<DirectoryBlobReader> DirectoryBlobReader::Create( std::unique_ptr<DirectoryBlobReader> DirectoryBlobReader::Create(
std::unique_ptr<DiscIO::VolumeDisc> volume, std::unique_ptr<DiscIO::VolumeDisc> volume,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>& const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>&
fst_callback) fst_callback)
{ {
@ -363,7 +370,7 @@ std::unique_ptr<DirectoryBlobReader> DirectoryBlobReader::Create(
return nullptr; return nullptr;
return std::unique_ptr<DirectoryBlobReader>( return std::unique_ptr<DirectoryBlobReader>(
new DirectoryBlobReader(std::move(volume), fst_callback)); new DirectoryBlobReader(std::move(volume), sys_callback, fst_callback));
} }
DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root,
@ -412,12 +419,14 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root,
DirectoryBlobReader::DirectoryBlobReader( DirectoryBlobReader::DirectoryBlobReader(
std::unique_ptr<DiscIO::VolumeDisc> volume, std::unique_ptr<DiscIO::VolumeDisc> volume,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>& const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>&
fst_callback) fst_callback)
: m_encryption_cache(this), m_wrapped_volume(std::move(volume)) : m_encryption_cache(this), m_wrapped_volume(std::move(volume))
{ {
DirectoryBlobPartition game_partition( DirectoryBlobPartition game_partition(m_wrapped_volume.get(),
m_wrapped_volume.get(), m_wrapped_volume->GetGamePartition(), std::nullopt, fst_callback); m_wrapped_volume->GetGamePartition(), std::nullopt,
sys_callback, fst_callback);
m_is_wii = game_partition.IsWii(); m_is_wii = game_partition.IsWii();
if (!m_is_wii) if (!m_is_wii)
@ -457,7 +466,7 @@ DirectoryBlobReader::DirectoryBlobReader(
if (type) if (type)
{ {
partitions.emplace_back( 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<PartitionType>(*type)); static_cast<PartitionType>(*type));
} }
} }
@ -814,32 +823,80 @@ DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory
BuildFSTFromFolder(m_root_directory + "files/", fst_address); BuildFSTFromFolder(m_root_directory + "files/", fst_address);
} }
static void FillSingleFileNode(FSTBuilderNode* node, std::vector<u8> data)
{
std::vector<BuilderContentSource> 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<u8> data,
void* userdata)
{
FSTBuilderNode node{std::move(filename), 0, {}, userdata};
FillSingleFileNode(&node, std::move(data));
return node;
}
static std::vector<u8> ExtractNodeToVector(std::vector<FSTBuilderNode>* nodes, void* userdata)
{
std::vector<u8> 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( DirectoryBlobPartition::DirectoryBlobPartition(
DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional<bool> is_wii, DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional<bool> is_wii,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>& const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>&
fst_callback) fst_callback)
: m_wrapped_partition(partition) : m_wrapped_partition(partition)
{ {
std::vector<FSTBuilderNode> sys_nodes;
std::vector<u8> disc_header(DISCHEADER_SIZE); std::vector<u8> disc_header(DISCHEADER_SIZE);
if (!volume->Read(DISCHEADER_ADDRESS, DISCHEADER_SIZE, disc_header.data(), partition)) if (!volume->Read(DISCHEADER_ADDRESS, DISCHEADER_SIZE, disc_header.data(), partition))
disc_header.clear(); disc_header.clear();
SetDiscHeader(std::move(disc_header)); sys_nodes.emplace_back(BuildSingleFileNode("boot.bin", std::move(disc_header), &m_disc_header));
SetDiscType(is_wii);
std::vector<u8> bi2(BI2_SIZE); std::vector<u8> bi2(BI2_SIZE);
if (!volume->Read(BI2_ADDRESS, BI2_SIZE, bi2.data(), partition)) if (!volume->Read(BI2_ADDRESS, BI2_SIZE, bi2.data(), partition))
bi2.clear(); bi2.clear();
SetBI2(std::move(bi2)); sys_nodes.emplace_back(BuildSingleFileNode("bi2.bin", std::move(bi2), &m_bi2));
std::vector<u8> apploader; std::vector<u8> apploader;
const auto apploader_size = GetApploaderSize(*volume, partition); const auto apploader_size = GetApploaderSize(*volume, partition);
auto& apploader_node =
sys_nodes.emplace_back(FSTBuilderNode{"apploader.img", 0, {}, &m_apploader});
if (apploader_size) if (apploader_size)
{ {
apploader.resize(*apploader_size); apploader.resize(*apploader_size);
if (!volume->Read(APPLOADER_ADDRESS, *apploader_size, apploader.data(), partition)) if (!volume->Read(APPLOADER_ADDRESS, *apploader_size, apploader.data(), partition))
apploader.clear(); 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, {}}; FSTBuilderNode dol_node{"main.dol", 0, {}};
const auto dol_offset = GetBootDOLOffset(*volume, partition); const auto dol_offset = GetBootDOLOffset(*volume, partition);

View File

@ -80,11 +80,18 @@ struct ContentFixedByte
u8 m_byte; u8 m_byte;
}; };
// Content chunk representing an arbitrary byte sequence that's stored within the struct itself.
struct ContentByteVector
{
std::vector<u8> m_bytes;
};
using ContentSource = std::variant<ContentFile, // File using ContentSource = std::variant<ContentFile, // File
const u8*, // Memory const u8*, // Memory
ContentPartition, // Partition ContentPartition, // Partition
ContentVolume, // Volume ContentVolume, // Volume
ContentFixedByte // Fixed value padding ContentFixedByte, // Fixed value padding
ContentByteVector // Byte sequence
>; >;
struct BuilderContentSource struct BuilderContentSource
@ -183,10 +190,11 @@ class DirectoryBlobPartition
public: public:
DirectoryBlobPartition() = default; DirectoryBlobPartition() = default;
DirectoryBlobPartition(const std::string& root_directory, std::optional<bool> is_wii); DirectoryBlobPartition(const std::string& root_directory, std::optional<bool> is_wii);
DirectoryBlobPartition(DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, DirectoryBlobPartition(
std::optional<bool> is_wii, DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional<bool> is_wii,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
FSTBuilderNode* dol_node)>& fst_callback); const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>&
fst_callback);
// We do not allow copying, because it might mess up the pointers inside DiscContents // We do not allow copying, because it might mess up the pointers inside DiscContents
DirectoryBlobPartition(const DirectoryBlobPartition&) = delete; DirectoryBlobPartition(const DirectoryBlobPartition&) = delete;
@ -258,6 +266,7 @@ public:
static std::unique_ptr<DirectoryBlobReader> Create(const std::string& dol_path); static std::unique_ptr<DirectoryBlobReader> Create(const std::string& dol_path);
static std::unique_ptr<DirectoryBlobReader> Create( static std::unique_ptr<DirectoryBlobReader> Create(
std::unique_ptr<DiscIO::VolumeDisc> volume, std::unique_ptr<DiscIO::VolumeDisc> volume,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>& const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>&
fst_callback); fst_callback);
@ -296,9 +305,11 @@ private:
explicit DirectoryBlobReader(const std::string& game_partition_root, explicit DirectoryBlobReader(const std::string& game_partition_root,
const std::string& true_root); const std::string& true_root);
explicit DirectoryBlobReader(std::unique_ptr<DiscIO::VolumeDisc> volume, explicit DirectoryBlobReader(
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, std::unique_ptr<DiscIO::VolumeDisc> volume,
FSTBuilderNode* dol_node)>& fst_callback); const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>&
fst_callback);
const DirectoryBlobPartition* GetPartition(u64 offset, u64 size, u64 partition_data_offset) const; const DirectoryBlobPartition* GetPartition(u64 offset, u64 size, u64 partition_data_offset) const;

View File

@ -172,9 +172,10 @@ std::optional<Disc> ParseString(std::string_view xml, std::string xml_path)
for (const auto& patch_subnode : patch_node.children()) for (const auto& patch_subnode : patch_node.children())
{ {
const std::string_view patch_name(patch_subnode.name()); 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_disc = patch_subnode.attribute("disc").as_string();
file.m_external = patch_subnode.attribute("external").as_string(); file.m_external = patch_subnode.attribute("external").as_string();
file.m_resize = patch_subnode.attribute("resize").as_bool(true); file.m_resize = patch_subnode.attribute("resize").as_bool(true);
@ -183,9 +184,11 @@ std::optional<Disc> ParseString(std::string_view xml, std::string xml_path)
file.m_fileoffset = patch_subnode.attribute("fileoffset").as_uint(0); file.m_fileoffset = patch_subnode.attribute("fileoffset").as_uint(0);
file.m_length = patch_subnode.attribute("length").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_disc = patch_subnode.attribute("disc").as_string();
folder.m_external = patch_subnode.attribute("external").as_string(); folder.m_external = patch_subnode.attribute("external").as_string();
folder.m_resize = patch_subnode.attribute("resize").as_bool(true); folder.m_resize = patch_subnode.attribute("resize").as_bool(true);

View File

@ -166,6 +166,8 @@ struct Patch
std::vector<File> m_file_patches; std::vector<File> m_file_patches;
std::vector<Folder> m_folder_patches; std::vector<Folder> m_folder_patches;
std::vector<File> m_sys_file_patches;
std::vector<Folder> m_sys_folder_patches;
std::vector<Savegame> m_savegame_patches; std::vector<Savegame> m_savegame_patches;
std::vector<Memory> m_memory_patches; std::vector<Memory> m_memory_patches;

View File

@ -397,7 +397,7 @@ static void ApplyFilePatchToFST(const Patch& patch, const File& file,
if (node) if (node)
ApplyPatchToFile(patch, file, 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. // Special case: If the filename is "main.dol", we want to patch the main executable.
ApplyPatchToFile(patch, file, dol_node); ApplyPatchToFile(patch, file, dol_node);
@ -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); ApplyFolderPatchToFST(patch, folder, fst, dol_node, folder.m_disc, folder.m_external);
} }
void ApplyPatchesToFiles(const std::vector<Patch>& patches, void ApplyPatchesToFiles(const std::vector<Patch>& patches, PatchIndex index,
std::vector<DiscIO::FSTBuilderNode>* fst, DiscIO::FSTBuilderNode* dol_node) std::vector<DiscIO::FSTBuilderNode>* fst, DiscIO::FSTBuilderNode* dol_node)
{ {
for (const auto& patch : patches) 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); 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); ApplyFolderPatchToFST(patch, folder, fst, dol_node);
} }
} }

View File

@ -65,7 +65,13 @@ private:
std::string m_patch_root; std::string m_patch_root;
}; };
void ApplyPatchesToFiles(const std::vector<Patch>& patches, enum class PatchIndex
{
FileSystem,
DolphinSysFiles,
};
void ApplyPatchesToFiles(const std::vector<Patch>& patches, PatchIndex index,
std::vector<DiscIO::FSTBuilderNode>* fst, std::vector<DiscIO::FSTBuilderNode>* fst,
DiscIO::FSTBuilderNode* dol_node); DiscIO::FSTBuilderNode* dol_node);
void ApplyGeneralMemoryPatches(const std::vector<Patch>& patches); void ApplyGeneralMemoryPatches(const std::vector<Patch>& patches);