DiscIO: Replace variables with structured bindings
This commit is contained in:
parent
f8bf35e6f0
commit
d645f5b607
|
@ -96,9 +96,9 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer, DirectoryBlobReade
|
|||
|
||||
if (std::holds_alternative<ContentFile>(m_content_source))
|
||||
{
|
||||
const auto& content = std::get<ContentFile>(m_content_source);
|
||||
File::IOFile file(content.m_filename, "rb");
|
||||
if (!file.Seek(content.m_offset + offset_in_content, File::SeekOrigin::Begin) ||
|
||||
const auto& [filename, content_source_offset] = std::get<ContentFile>(m_content_source);
|
||||
File::IOFile file(filename, "rb");
|
||||
if (!file.Seek(content_source_offset + offset_in_content, File::SeekOrigin::Begin) ||
|
||||
!file.ReadBytes(*buffer, bytes_to_read))
|
||||
{
|
||||
return false;
|
||||
|
@ -111,27 +111,28 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer, DirectoryBlobReade
|
|||
}
|
||||
else if (std::holds_alternative<ContentPartition>(m_content_source))
|
||||
{
|
||||
const auto& content = std::get<ContentPartition>(m_content_source);
|
||||
const auto& [content_source_offset, partition_data_offset] =
|
||||
std::get<ContentPartition>(m_content_source);
|
||||
const u64 decrypted_size = m_size * VolumeWii::BLOCK_DATA_SIZE / VolumeWii::BLOCK_TOTAL_SIZE;
|
||||
if (!blob->EncryptPartitionData(content.m_offset + offset_in_content, bytes_to_read, *buffer,
|
||||
content.m_partition_data_offset, decrypted_size))
|
||||
if (!blob->EncryptPartitionData(content_source_offset + offset_in_content, bytes_to_read,
|
||||
*buffer, partition_data_offset, decrypted_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (std::holds_alternative<ContentVolume>(m_content_source))
|
||||
{
|
||||
const auto& source = std::get<ContentVolume>(m_content_source);
|
||||
if (!blob->GetWrappedVolume()->Read(source.m_offset + offset_in_content, bytes_to_read,
|
||||
*buffer, source.m_partition))
|
||||
const auto& [content_source_offset, partition] = std::get<ContentVolume>(m_content_source);
|
||||
if (!blob->GetWrappedVolume()->Read(content_source_offset + offset_in_content, bytes_to_read,
|
||||
*buffer, partition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (std::holds_alternative<ContentFixedByte>(m_content_source))
|
||||
{
|
||||
const ContentFixedByte& source = std::get<ContentFixedByte>(m_content_source);
|
||||
std::fill_n(*buffer, bytes_to_read, source.m_byte);
|
||||
const auto& [byte] = std::get<ContentFixedByte>(m_content_source);
|
||||
std::fill_n(*buffer, bytes_to_read, byte);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -867,8 +868,8 @@ static std::vector<u8> ExtractNodeToVector(std::vector<FSTBuilderNode>* nodes, v
|
|||
return data;
|
||||
|
||||
DiscContentContainer tmp;
|
||||
for (auto& content : it->GetFileContent())
|
||||
tmp.Add(content.m_offset, content.m_size, std::move(content.m_source));
|
||||
for (auto& [offset, size, source] : it->GetFileContent())
|
||||
tmp.Add(offset, size, std::move(source));
|
||||
data.resize(it->m_size);
|
||||
tmp.Read(0, it->m_size, data.data(), blob);
|
||||
return data;
|
||||
|
@ -1045,8 +1046,8 @@ u64 DirectoryBlobPartition::SetDOLFromFile(const std::string& path, u64 dol_addr
|
|||
u64 DirectoryBlobPartition::SetDOL(FSTBuilderNode dol_node, u64 dol_address,
|
||||
std::vector<u8>* disc_header)
|
||||
{
|
||||
for (auto& content : dol_node.GetFileContent())
|
||||
m_contents.Add(dol_address + content.m_offset, content.m_size, std::move(content.m_source));
|
||||
for (auto& [offset, size, source] : dol_node.GetFileContent())
|
||||
m_contents.Add(dol_address + offset, size, std::move(source));
|
||||
|
||||
Write32(static_cast<u32>(dol_address >> m_address_shift), 0x0420, disc_header);
|
||||
|
||||
|
@ -1222,10 +1223,9 @@ void DirectoryBlobPartition::WriteDirectory(std::vector<u8>* fst_data,
|
|||
|
||||
// write entry to virtual disc
|
||||
auto& contents = entry.GetFileContent();
|
||||
for (BuilderContentSource& content : contents)
|
||||
for (auto& [offset, size, source] : contents)
|
||||
{
|
||||
m_contents.Add(*data_offset + content.m_offset, content.m_size,
|
||||
std::move(content.m_source));
|
||||
m_contents.Add(*data_offset + offset, size, std::move(source));
|
||||
}
|
||||
|
||||
// 32 KiB aligned - many games are fine with less alignment, but not all
|
||||
|
|
|
@ -49,17 +49,17 @@ ParseRiivolutionOptions(const picojson::array& array)
|
|||
if (!option_object.is<picojson::object>())
|
||||
continue;
|
||||
|
||||
auto& option = options.emplace_back();
|
||||
auto& [section_name, option_id, option_name, choice] = options.emplace_back();
|
||||
for (const auto& [key, value] : option_object.get<picojson::object>())
|
||||
{
|
||||
if (key == "section-name" && value.is<std::string>())
|
||||
option.section_name = value.get<std::string>();
|
||||
section_name = value.get<std::string>();
|
||||
else if (key == "option-id" && value.is<std::string>())
|
||||
option.option_id = value.get<std::string>();
|
||||
option_id = value.get<std::string>();
|
||||
else if (key == "option-name" && value.is<std::string>())
|
||||
option.option_name = value.get<std::string>();
|
||||
option_name = value.get<std::string>();
|
||||
else if (key == "choice" && value.is<double>())
|
||||
option.choice = MathUtil::SaturatingCast<u32>(value.get<double>());
|
||||
choice = MathUtil::SaturatingCast<u32>(value.get<double>());
|
||||
}
|
||||
}
|
||||
return options;
|
||||
|
@ -78,15 +78,15 @@ static GameModDescriptorRiivolution ParseRiivolutionObject(const std::string& js
|
|||
if (!patch_object.is<picojson::object>())
|
||||
continue;
|
||||
|
||||
auto& patch = r.patches.emplace_back();
|
||||
auto& [xml, root, options] = r.patches.emplace_back();
|
||||
for (const auto& [key, value] : patch_object.get<picojson::object>())
|
||||
{
|
||||
if (key == "xml" && value.is<std::string>())
|
||||
patch.xml = MakeAbsolute(json_directory, value.get<std::string>());
|
||||
xml = MakeAbsolute(json_directory, value.get<std::string>());
|
||||
else if (key == "root" && value.is<std::string>())
|
||||
patch.root = MakeAbsolute(json_directory, value.get<std::string>());
|
||||
root = MakeAbsolute(json_directory, value.get<std::string>());
|
||||
else if (key == "options" && value.is<picojson::array>())
|
||||
patch.options = ParseRiivolutionOptions(value.get<picojson::array>());
|
||||
options = ParseRiivolutionOptions(value.get<picojson::array>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,26 +152,26 @@ static picojson::object
|
|||
WriteGameModDescriptorRiivolution(const GameModDescriptorRiivolution& riivolution)
|
||||
{
|
||||
picojson::array json_patches;
|
||||
for (const auto& patch : riivolution.patches)
|
||||
for (const auto& [xml, root, options] : riivolution.patches)
|
||||
{
|
||||
picojson::object json_patch;
|
||||
if (!patch.xml.empty())
|
||||
json_patch["xml"] = picojson::value(patch.xml);
|
||||
if (!patch.root.empty())
|
||||
json_patch["root"] = picojson::value(patch.root);
|
||||
if (!patch.options.empty())
|
||||
if (!xml.empty())
|
||||
json_patch["xml"] = picojson::value(xml);
|
||||
if (!root.empty())
|
||||
json_patch["root"] = picojson::value(root);
|
||||
if (!options.empty())
|
||||
{
|
||||
picojson::array json_options;
|
||||
for (const auto& option : patch.options)
|
||||
for (const auto& [section_name, option_id, option_name, choice] : options)
|
||||
{
|
||||
picojson::object json_option;
|
||||
if (!option.section_name.empty())
|
||||
json_option["section-name"] = picojson::value(option.section_name);
|
||||
if (!option.option_id.empty())
|
||||
json_option["option-id"] = picojson::value(option.option_id);
|
||||
if (!option.option_name.empty())
|
||||
json_option["option-name"] = picojson::value(option.option_name);
|
||||
json_option["choice"] = picojson::value(static_cast<double>(option.choice));
|
||||
if (!section_name.empty())
|
||||
json_option["section-name"] = picojson::value(section_name);
|
||||
if (!option_id.empty())
|
||||
json_option["option-id"] = picojson::value(option_id);
|
||||
if (!option_name.empty())
|
||||
json_option["option-name"] = picojson::value(option_name);
|
||||
json_option["choice"] = picojson::value(static_cast<double>(choice));
|
||||
json_options.emplace_back(std::move(json_option));
|
||||
}
|
||||
json_patch["options"] = picojson::value(std::move(json_options));
|
||||
|
|
|
@ -238,18 +238,18 @@ bool NANDImporter::ExtractCertificates()
|
|||
{"/rootca.pem", {{0x30, 0x82, 0x03, 0x7D}}},
|
||||
}};
|
||||
|
||||
for (const PEMCertificate& certificate : certificates)
|
||||
for (const auto& [filename, search_bytes] : certificates)
|
||||
{
|
||||
const auto search_result = std::ranges::search(content_bytes, certificate.search_bytes);
|
||||
const auto search_result = std::ranges::search(content_bytes, search_bytes);
|
||||
|
||||
if (search_result.empty())
|
||||
{
|
||||
ERROR_LOG_FMT(DISCIO, "ExtractCertificates: Could not find offset for certficate '{}'",
|
||||
certificate.filename);
|
||||
filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string pem_file_path = m_nand_root + std::string(certificate.filename);
|
||||
const std::string pem_file_path = m_nand_root + std::string(filename);
|
||||
const ptrdiff_t certificate_offset =
|
||||
std::distance(content_bytes.begin(), search_result.begin());
|
||||
constexpr int min_offset = 2;
|
||||
|
@ -271,8 +271,8 @@ bool NANDImporter::ExtractCertificates()
|
|||
certificate_size, available_size);
|
||||
return false;
|
||||
}
|
||||
INFO_LOG_FMT(DISCIO, "ExtractCertificates: '{}' offset: {:#x} size: {:#x}",
|
||||
certificate.filename, certificate_offset, certificate_size);
|
||||
INFO_LOG_FMT(DISCIO, "ExtractCertificates: '{}' offset: {:#x} size: {:#x}", filename,
|
||||
certificate_offset, certificate_size);
|
||||
|
||||
File::IOFile pem_file(pem_file_path, "wb");
|
||||
if (!pem_file.WriteBytes(&content_bytes[certificate_offset], certificate_size))
|
||||
|
|
|
@ -59,9 +59,8 @@ std::vector<NFSLBARange> NFSFileReader::GetLBARanges(const NFSHeader& header)
|
|||
|
||||
for (size_t i = 0; i < lba_range_count; ++i)
|
||||
{
|
||||
const NFSLBARange& unswapped_lba_range = header.lba_ranges[i];
|
||||
lba_ranges.push_back(NFSLBARange{Common::swap32(unswapped_lba_range.start_block),
|
||||
Common::swap32(unswapped_lba_range.num_blocks)});
|
||||
const auto& [start_block, num_blocks] = header.lba_ranges[i];
|
||||
lba_ranges.push_back(NFSLBARange{Common::swap32(start_block), Common::swap32(num_blocks)});
|
||||
}
|
||||
|
||||
return lba_ranges;
|
||||
|
@ -108,8 +107,8 @@ std::vector<File::IOFile> NFSFileReader::OpenFiles(const std::string& directory,
|
|||
u64 NFSFileReader::CalculateExpectedRawSize(const std::vector<NFSLBARange>& lba_ranges)
|
||||
{
|
||||
u64 total_blocks = 0;
|
||||
for (const NFSLBARange& range : lba_ranges)
|
||||
total_blocks += range.num_blocks;
|
||||
for (const auto& [start_block, num_blocks] : lba_ranges)
|
||||
total_blocks += num_blocks;
|
||||
|
||||
return sizeof(NFSHeader) + total_blocks * BLOCK_SIZE;
|
||||
}
|
||||
|
@ -117,8 +116,8 @@ u64 NFSFileReader::CalculateExpectedRawSize(const std::vector<NFSLBARange>& lba_
|
|||
u64 NFSFileReader::CalculateExpectedDataSize(const std::vector<NFSLBARange>& lba_ranges)
|
||||
{
|
||||
u32 greatest_block_index = 0;
|
||||
for (const NFSLBARange& range : lba_ranges)
|
||||
greatest_block_index = std::max(greatest_block_index, range.start_block + range.num_blocks);
|
||||
for (const auto& [start_block, num_blocks] : lba_ranges)
|
||||
greatest_block_index = std::max(greatest_block_index, start_block + num_blocks);
|
||||
|
||||
return u64(greatest_block_index) * BLOCK_SIZE;
|
||||
}
|
||||
|
@ -188,15 +187,14 @@ u64 NFSFileReader::ToPhysicalBlockIndex(u64 logical_block_index)
|
|||
{
|
||||
u64 physical_blocks_so_far = 0;
|
||||
|
||||
for (const NFSLBARange& range : m_lba_ranges)
|
||||
for (const auto& [start_block, num_blocks] : m_lba_ranges)
|
||||
{
|
||||
if (logical_block_index >= range.start_block &&
|
||||
logical_block_index < range.start_block + range.num_blocks)
|
||||
if (logical_block_index >= start_block && logical_block_index < start_block + num_blocks)
|
||||
{
|
||||
return physical_blocks_so_far + (logical_block_index - range.start_block);
|
||||
return physical_blocks_so_far + (logical_block_index - start_block);
|
||||
}
|
||||
|
||||
physical_blocks_so_far += range.num_blocks;
|
||||
physical_blocks_so_far += num_blocks;
|
||||
}
|
||||
|
||||
return std::numeric_limits<u64>::max();
|
||||
|
|
|
@ -118,25 +118,25 @@ std::optional<Disc> ParseString(std::string_view xml, std::string xml_path)
|
|||
{
|
||||
for (const auto& section_node : options.children("section"))
|
||||
{
|
||||
Section& section = disc.m_sections.emplace_back();
|
||||
section.m_name = section_node.attribute("name").as_string();
|
||||
auto& [section_name, section_options] = disc.m_sections.emplace_back();
|
||||
section_name = section_node.attribute("name").as_string();
|
||||
for (const auto& option_node : section_node.children("option"))
|
||||
{
|
||||
Option& option = section.m_options.emplace_back();
|
||||
option.m_id = option_node.attribute("id").as_string();
|
||||
option.m_name = option_node.attribute("name").as_string();
|
||||
option.m_selected_choice = option_node.attribute("default").as_uint(0);
|
||||
auto& [option_name, option_id, choices, selected_choice] = section_options.emplace_back();
|
||||
option_id = option_node.attribute("id").as_string();
|
||||
option_name = option_node.attribute("name").as_string();
|
||||
selected_choice = option_node.attribute("default").as_uint(0);
|
||||
auto option_params = ReadParams(option_node);
|
||||
for (const auto& choice_node : option_node.children("choice"))
|
||||
{
|
||||
Choice& choice = option.m_choices.emplace_back();
|
||||
choice.m_name = choice_node.attribute("name").as_string();
|
||||
auto& [choice_name, patch_references] = choices.emplace_back();
|
||||
choice_name = choice_node.attribute("name").as_string();
|
||||
auto choice_params = ReadParams(choice_node, option_params);
|
||||
for (const auto& patchref_node : choice_node.children("patch"))
|
||||
{
|
||||
PatchReference& patchref = choice.m_patch_references.emplace_back();
|
||||
patchref.m_id = patchref_node.attribute("id").as_string();
|
||||
patchref.m_params = ReadParams(patchref_node, choice_params);
|
||||
auto& [patch_reference_id, params] = patch_references.emplace_back();
|
||||
patch_reference_id = patchref_node.attribute("id").as_string();
|
||||
params = ReadParams(patchref_node, choice_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,17 +144,17 @@ std::optional<Disc> ParseString(std::string_view xml, std::string xml_path)
|
|||
for (const auto& macro_node : options.children("macros"))
|
||||
{
|
||||
const std::string macro_id = macro_node.attribute("id").as_string();
|
||||
for (auto& section : disc.m_sections)
|
||||
for (auto& [name, section_options] : disc.m_sections)
|
||||
{
|
||||
auto option_to_clone = std::ranges::find(section.m_options, macro_id, &Option::m_id);
|
||||
if (option_to_clone == section.m_options.end())
|
||||
auto option_to_clone = std::ranges::find(section_options, macro_id, &Option::m_id);
|
||||
if (option_to_clone == section_options.end())
|
||||
continue;
|
||||
|
||||
Option cloned_option = *option_to_clone;
|
||||
cloned_option.m_name = macro_node.attribute("name").as_string();
|
||||
for (auto& choice : cloned_option.m_choices)
|
||||
for (auto& patch_ref : choice.m_patch_references)
|
||||
patch_ref.m_params = ReadParams(macro_node, patch_ref.m_params);
|
||||
for (auto& [choice_name, patch_references] : cloned_option.m_choices)
|
||||
for (auto& [patch_reference_id, params] : patch_references)
|
||||
params = ReadParams(macro_node, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,44 +173,46 @@ std::optional<Disc> ParseString(std::string_view xml, std::string xml_path)
|
|||
const std::string_view patch_name(patch_subnode.name());
|
||||
if (patch_name == "file" || patch_name == "dolphin_sys_file")
|
||||
{
|
||||
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);
|
||||
file.m_create = patch_subnode.attribute("create").as_bool(false);
|
||||
file.m_offset = patch_subnode.attribute("offset").as_uint(0);
|
||||
file.m_fileoffset = patch_subnode.attribute("fileoffset").as_uint(0);
|
||||
file.m_length = patch_subnode.attribute("length").as_uint(0);
|
||||
auto& [patch_disc, external, resize, create, offset, fileoffset, length] =
|
||||
patch_name == "dolphin_sys_file" ? patch.m_sys_file_patches.emplace_back() :
|
||||
patch.m_file_patches.emplace_back();
|
||||
patch_disc = patch_subnode.attribute("disc").as_string();
|
||||
external = patch_subnode.attribute("external").as_string();
|
||||
resize = patch_subnode.attribute("resize").as_bool(true);
|
||||
create = patch_subnode.attribute("create").as_bool(false);
|
||||
offset = patch_subnode.attribute("offset").as_uint(0);
|
||||
fileoffset = patch_subnode.attribute("fileoffset").as_uint(0);
|
||||
length = patch_subnode.attribute("length").as_uint(0);
|
||||
}
|
||||
else if (patch_name == "folder" || patch_name == "dolphin_sys_folder")
|
||||
{
|
||||
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);
|
||||
folder.m_create = patch_subnode.attribute("create").as_bool(false);
|
||||
folder.m_recursive = patch_subnode.attribute("recursive").as_bool(true);
|
||||
folder.m_length = patch_subnode.attribute("length").as_uint(0);
|
||||
auto& [patch_disc, external, resize, create, recursive, length] =
|
||||
patch_name == "dolphin_sys_folder" ? patch.m_sys_folder_patches.emplace_back() :
|
||||
patch.m_folder_patches.emplace_back();
|
||||
patch_disc = patch_subnode.attribute("disc").as_string();
|
||||
external = patch_subnode.attribute("external").as_string();
|
||||
resize = patch_subnode.attribute("resize").as_bool(true);
|
||||
create = patch_subnode.attribute("create").as_bool(false);
|
||||
recursive = patch_subnode.attribute("recursive").as_bool(true);
|
||||
length = patch_subnode.attribute("length").as_uint(0);
|
||||
}
|
||||
else if (patch_name == "savegame")
|
||||
{
|
||||
auto& savegame = patch.m_savegame_patches.emplace_back();
|
||||
savegame.m_external = patch_subnode.attribute("external").as_string();
|
||||
savegame.m_clone = patch_subnode.attribute("clone").as_bool(true);
|
||||
auto& [external, clone] = patch.m_savegame_patches.emplace_back();
|
||||
external = patch_subnode.attribute("external").as_string();
|
||||
clone = patch_subnode.attribute("clone").as_bool(true);
|
||||
}
|
||||
else if (patch_name == "memory")
|
||||
{
|
||||
auto& memory = patch.m_memory_patches.emplace_back();
|
||||
memory.m_offset = patch_subnode.attribute("offset").as_uint(0);
|
||||
memory.m_value = ReadHexString(patch_subnode.attribute("value").as_string());
|
||||
memory.m_valuefile = patch_subnode.attribute("valuefile").as_string();
|
||||
memory.m_original = ReadHexString(patch_subnode.attribute("original").as_string());
|
||||
memory.m_ocarina = patch_subnode.attribute("ocarina").as_bool(false);
|
||||
memory.m_search = patch_subnode.attribute("search").as_bool(false);
|
||||
memory.m_align = patch_subnode.attribute("align").as_uint(1);
|
||||
auto& [offset, value, valuefile, original, ocarina, search, align] =
|
||||
patch.m_memory_patches.emplace_back();
|
||||
offset = patch_subnode.attribute("offset").as_uint(0);
|
||||
value = ReadHexString(patch_subnode.attribute("value").as_string());
|
||||
valuefile = patch_subnode.attribute("valuefile").as_string();
|
||||
original = ReadHexString(patch_subnode.attribute("original").as_string());
|
||||
ocarina = patch_subnode.attribute("ocarina").as_bool(false);
|
||||
search = patch_subnode.attribute("search").as_bool(false);
|
||||
align = patch_subnode.attribute("align").as_uint(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -273,13 +275,13 @@ std::vector<Patch> Disc::GeneratePatches(const std::string& game_id) const
|
|||
while (!sv.empty())
|
||||
{
|
||||
bool replaced = false;
|
||||
for (const auto& r : replacements)
|
||||
for (const auto& [first, second] : replacements)
|
||||
{
|
||||
if (sv.starts_with(r.first))
|
||||
if (sv.starts_with(first))
|
||||
{
|
||||
for (char c : r.second)
|
||||
for (char c : second)
|
||||
result.push_back(c);
|
||||
sv = sv.substr(r.first.size());
|
||||
sv = sv.substr(first.size());
|
||||
replaced = true;
|
||||
break;
|
||||
}
|
||||
|
@ -294,17 +296,17 @@ std::vector<Patch> Disc::GeneratePatches(const std::string& game_id) const
|
|||
|
||||
// Take only selected patches, replace placeholders in all strings, and return them.
|
||||
std::vector<Patch> active_patches;
|
||||
for (const auto& section : m_sections)
|
||||
for (const auto& [name, options] : m_sections)
|
||||
{
|
||||
for (const auto& option : section.m_options)
|
||||
for (const auto& option : options)
|
||||
{
|
||||
const u32 selected = option.m_selected_choice;
|
||||
if (selected == 0 || selected > option.m_choices.size())
|
||||
continue;
|
||||
const Choice& choice = option.m_choices[selected - 1];
|
||||
for (const auto& patch_ref : choice.m_patch_references)
|
||||
const auto& [choice_name, patch_references] = option.m_choices[selected - 1];
|
||||
for (const auto& [id, params] : patch_references)
|
||||
{
|
||||
const auto patch = std::ranges::find(m_patches, patch_ref.m_id, &Patch::m_id);
|
||||
const auto patch = std::ranges::find(m_patches, id, &Patch::m_id);
|
||||
if (patch == m_patches.end())
|
||||
continue;
|
||||
|
||||
|
@ -312,8 +314,8 @@ std::vector<Patch> Disc::GeneratePatches(const std::string& game_id) const
|
|||
replacements.emplace_back(std::pair{"{$__gameid}", game_id_no_region});
|
||||
replacements.emplace_back(std::pair{"{$__region}", game_region});
|
||||
replacements.emplace_back(std::pair{"{$__maker}", game_developer});
|
||||
for (const auto& param : patch_ref.m_params)
|
||||
replacements.emplace_back(std::pair{"{$" + param.first + "}", param.second});
|
||||
for (const auto& [first, second] : params)
|
||||
replacements.emplace_back(std::pair{"{$" + first + "}", second});
|
||||
|
||||
Patch& new_patch = active_patches.emplace_back(*patch);
|
||||
new_patch.m_root = replace_variables(new_patch.m_root, replacements);
|
||||
|
@ -327,9 +329,9 @@ std::vector<Patch> Disc::GeneratePatches(const std::string& game_id) const
|
|||
folder.m_disc = replace_variables(folder.m_disc, replacements);
|
||||
folder.m_external = replace_variables(folder.m_external, replacements);
|
||||
}
|
||||
for (auto& savegame : new_patch.m_savegame_patches)
|
||||
for (auto& [external, clone] : new_patch.m_savegame_patches)
|
||||
{
|
||||
savegame.m_external = replace_variables(savegame.m_external, replacements);
|
||||
external = replace_variables(external, replacements);
|
||||
}
|
||||
for (auto& memory : new_patch.m_memory_patches)
|
||||
{
|
||||
|
@ -347,38 +349,38 @@ std::vector<Patch> GenerateRiivolutionPatchesFromGameModDescriptor(
|
|||
std::optional<u16> revision, std::optional<u8> disc_number)
|
||||
{
|
||||
std::vector<Patch> result;
|
||||
for (const auto& patch_info : descriptor.patches)
|
||||
for (const auto& [xml, root, options] : descriptor.patches)
|
||||
{
|
||||
auto parsed = ParseFile(patch_info.xml);
|
||||
auto parsed = ParseFile(xml);
|
||||
if (!parsed || !parsed->IsValidForGame(game_id, revision, disc_number))
|
||||
continue;
|
||||
|
||||
for (auto& section : parsed->m_sections)
|
||||
for (auto& [section_name, section_options] : parsed->m_sections)
|
||||
{
|
||||
for (auto& option : section.m_options)
|
||||
for (auto& [option_name, id, choices, selected_choice] : section_options)
|
||||
{
|
||||
const auto* info = [&]() -> const GameModDescriptorRiivolutionPatchOption* {
|
||||
for (const auto& o : patch_info.options)
|
||||
for (const auto& o : options)
|
||||
{
|
||||
if (o.section_name == section.m_name)
|
||||
if (o.section_name == section_name)
|
||||
{
|
||||
if (!o.option_id.empty() && o.option_id == option.m_id)
|
||||
if (!o.option_id.empty() && o.option_id == id)
|
||||
return &o;
|
||||
if (!o.option_name.empty() && o.option_name == option.m_name)
|
||||
if (!o.option_name.empty() && o.option_name == option_name)
|
||||
return &o;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
if (info && info->choice <= option.m_choices.size())
|
||||
option.m_selected_choice = info->choice;
|
||||
if (info && info->choice <= choices.size())
|
||||
selected_choice = info->choice;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& p : parsed->GeneratePatches(game_id))
|
||||
{
|
||||
p.m_file_data_loader =
|
||||
std::make_shared<FileDataLoaderHostFS>(patch_info.root, parsed->m_xml_path, p.m_root);
|
||||
std::make_shared<FileDataLoaderHostFS>(root, parsed->m_xml_path, p.m_root);
|
||||
result.emplace_back(std::move(p));
|
||||
}
|
||||
}
|
||||
|
@ -451,9 +453,9 @@ std::optional<Config> ParseConfigString(std::string_view xml)
|
|||
const auto options = riivolution.children("option");
|
||||
for (const auto& option_node : options)
|
||||
{
|
||||
auto& option = config.m_options.emplace_back();
|
||||
option.m_id = option_node.attribute("id").as_string();
|
||||
option.m_default = option_node.attribute("default").as_uint(0);
|
||||
auto& [option_id, option_default] = config.m_options.emplace_back();
|
||||
option_id = option_node.attribute("id").as_string();
|
||||
option_default = option_node.attribute("default").as_uint(0);
|
||||
}
|
||||
|
||||
return config;
|
||||
|
@ -464,11 +466,11 @@ std::string WriteConfigString(const Config& config)
|
|||
pugi::xml_document doc;
|
||||
auto riivolution = doc.append_child("riivolution");
|
||||
riivolution.append_attribute("version").set_value(config.m_version);
|
||||
for (const auto& option : config.m_options)
|
||||
for (const auto& [option_id, option_default] : config.m_options)
|
||||
{
|
||||
auto option_node = riivolution.append_child("option");
|
||||
option_node.append_attribute("id").set_value(option.m_id.c_str());
|
||||
option_node.append_attribute("default").set_value(option.m_default);
|
||||
option_node.append_attribute("id").set_value(option_id.c_str());
|
||||
option_node.append_attribute("default").set_value(option_default);
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
|
@ -495,21 +497,21 @@ bool WriteConfigFile(const std::string& filename, const Config& config)
|
|||
|
||||
void ApplyConfigDefaults(Disc* disc, const Config& config)
|
||||
{
|
||||
for (const auto& config_option : config.m_options)
|
||||
for (const auto& [option_id, option_default] : config.m_options)
|
||||
{
|
||||
auto* matching_option = [&]() -> Option* {
|
||||
for (auto& section : disc->m_sections)
|
||||
for (auto& [name, options] : disc->m_sections)
|
||||
{
|
||||
for (auto& option : section.m_options)
|
||||
for (auto& option : options)
|
||||
{
|
||||
if (option.m_id.empty())
|
||||
{
|
||||
if ((section.m_name + option.m_name) == config_option.m_id)
|
||||
if ((name + option.m_name) == option_id)
|
||||
return &option;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option.m_id == config_option.m_id)
|
||||
if (option.m_id == option_id)
|
||||
return &option;
|
||||
}
|
||||
}
|
||||
|
@ -517,7 +519,7 @@ void ApplyConfigDefaults(Disc* disc, const Config& config)
|
|||
return nullptr;
|
||||
}();
|
||||
if (matching_option)
|
||||
matching_option->m_selected_choice = config_option.m_default;
|
||||
matching_option->m_selected_choice = option_default;
|
||||
}
|
||||
}
|
||||
} // namespace DiscIO::Riivolution
|
||||
|
|
|
@ -450,7 +450,7 @@ static void ApplyFolderPatchToFST(const Patch& patch, const Folder& folder,
|
|||
std::string_view external_path)
|
||||
{
|
||||
const auto external_files = patch.m_file_data_loader->GetFolderContents(external_path);
|
||||
for (const auto& child : external_files)
|
||||
for (const auto& [filename, is_directory] : external_files)
|
||||
{
|
||||
const auto combine_paths = [](std::string_view a, std::string_view b) {
|
||||
if (a.empty())
|
||||
|
@ -463,10 +463,10 @@ static void ApplyFolderPatchToFST(const Patch& patch, const Folder& folder,
|
|||
b.remove_prefix(1);
|
||||
return fmt::format("{}/{}", a, b);
|
||||
};
|
||||
std::string child_disc_path = combine_paths(disc_path, child.m_filename);
|
||||
std::string child_external_path = combine_paths(external_path, child.m_filename);
|
||||
std::string child_disc_path = combine_paths(disc_path, filename);
|
||||
std::string child_external_path = combine_paths(external_path, filename);
|
||||
|
||||
if (child.m_is_directory)
|
||||
if (is_directory)
|
||||
{
|
||||
if (folder.m_recursive)
|
||||
ApplyFolderPatchToFST(patch, folder, fst, dol_node, child_disc_path, child_external_path);
|
||||
|
@ -665,10 +665,10 @@ std::optional<SavegameRedirect> ExtractSavegameRedirect(std::span<const Patch> r
|
|||
{
|
||||
if (!patch.m_savegame_patches.empty())
|
||||
{
|
||||
const auto& save_patch = patch.m_savegame_patches[0];
|
||||
auto resolved = patch.m_file_data_loader->ResolveSavegameRedirectPath(save_patch.m_external);
|
||||
const auto& [external, clone] = patch.m_savegame_patches[0];
|
||||
auto resolved = patch.m_file_data_loader->ResolveSavegameRedirectPath(external);
|
||||
if (resolved)
|
||||
return SavegameRedirect{std::move(*resolved), save_patch.m_clone};
|
||||
return SavegameRedirect{std::move(*resolved), clone};
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,10 +59,9 @@ std::unique_ptr<SplitPlainFileReader> SplitPlainFileReader::Create(std::string_v
|
|||
std::unique_ptr<BlobReader> SplitPlainFileReader::CopyReader() const
|
||||
{
|
||||
std::vector<SingleFile> new_files{};
|
||||
for (const SingleFile& file : m_files)
|
||||
for (const auto& [file, offset, size] : m_files)
|
||||
{
|
||||
new_files.push_back(
|
||||
{.file = file.file.Duplicate("rb"), .offset = file.offset, .size = file.size});
|
||||
new_files.push_back({.file = file.Duplicate("rb"), .offset = offset, .size = size});
|
||||
}
|
||||
return std::unique_ptr<SplitPlainFileReader>(new SplitPlainFileReader(std::move(new_files)));
|
||||
}
|
||||
|
@ -75,16 +74,15 @@ bool SplitPlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
|
|||
u64 current_offset = offset;
|
||||
u64 rest = nbytes;
|
||||
u8* out = out_ptr;
|
||||
for (auto& file : m_files)
|
||||
for (auto& [file, file_offset, size] : m_files)
|
||||
{
|
||||
if (current_offset >= file.offset && current_offset < file.offset + file.size)
|
||||
if (current_offset >= file_offset && current_offset < file_offset + size)
|
||||
{
|
||||
auto& f = file.file;
|
||||
const u64 seek_offset = current_offset - file.offset;
|
||||
const u64 current_read = std::min(file.size - seek_offset, rest);
|
||||
if (!f.Seek(seek_offset, File::SeekOrigin::Begin) || !f.ReadBytes(out, current_read))
|
||||
const u64 seek_offset = current_offset - file_offset;
|
||||
const u64 current_read = std::min(size - seek_offset, rest);
|
||||
if (!file.Seek(seek_offset, File::SeekOrigin::Begin) || !file.ReadBytes(out, current_read))
|
||||
{
|
||||
f.ClearError();
|
||||
file.ClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -217,26 +217,27 @@ VolumeGC::ConvertedGCBanner VolumeGC::ExtractBannerInformation(const GCBanner& b
|
|||
|
||||
for (u32 i = 0; i < number_of_languages; ++i)
|
||||
{
|
||||
const GCBannerInformation& info = banner_file.information[i];
|
||||
const auto& [info_short_name, info_short_maker, info_long_name, info_long_maker,
|
||||
info_description] = banner_file.information[i];
|
||||
Language language = static_cast<Language>(static_cast<int>(start_language) + i);
|
||||
|
||||
std::string description = DecodeString(info.description);
|
||||
std::string description = DecodeString(info_description);
|
||||
if (!description.empty())
|
||||
banner.descriptions.emplace(language, description);
|
||||
|
||||
std::string short_name = DecodeString(info.short_name);
|
||||
std::string short_name = DecodeString(info_short_name);
|
||||
if (!short_name.empty())
|
||||
banner.short_names.emplace(language, short_name);
|
||||
|
||||
std::string long_name = DecodeString(info.long_name);
|
||||
std::string long_name = DecodeString(info_long_name);
|
||||
if (!long_name.empty())
|
||||
banner.long_names.emplace(language, long_name);
|
||||
|
||||
std::string short_maker = DecodeString(info.short_maker);
|
||||
std::string short_maker = DecodeString(info_short_maker);
|
||||
if (!short_maker.empty())
|
||||
banner.short_makers.emplace(language, short_maker);
|
||||
|
||||
std::string long_maker = DecodeString(info.long_maker);
|
||||
std::string long_maker = DecodeString(info_long_maker);
|
||||
if (!long_maker.empty())
|
||||
banner.long_makers.emplace(language, long_maker);
|
||||
}
|
||||
|
|
|
@ -295,12 +295,12 @@ std::vector<RedumpVerifier::PotentialMatch> RedumpVerifier::ScanDatfile(const st
|
|||
continue;
|
||||
}
|
||||
|
||||
PotentialMatch& potential_match = potential_matches.emplace_back();
|
||||
auto& [size, hashes] = potential_matches.emplace_back();
|
||||
const pugi::xml_node rom = game.child("rom");
|
||||
potential_match.size = rom.attribute("size").as_ullong();
|
||||
potential_match.hashes.crc32 = ParseHash(rom.attribute("crc").value());
|
||||
potential_match.hashes.md5 = ParseHash(rom.attribute("md5").value());
|
||||
potential_match.hashes.sha1 = ParseHash(rom.attribute("sha1").value());
|
||||
size = rom.attribute("size").as_ullong();
|
||||
hashes.crc32 = ParseHash(rom.attribute("crc").value());
|
||||
hashes.md5 = ParseHash(rom.attribute("md5").value());
|
||||
hashes.sha1 = ParseHash(rom.attribute("sha1").value());
|
||||
}
|
||||
|
||||
if (!serials_exist || !versions_exist)
|
||||
|
@ -335,10 +335,11 @@ RedumpVerifier::Result RedumpVerifier::Finish(const Hashes<std::vector<u8>>& has
|
|||
return m_result;
|
||||
|
||||
const std::vector<PotentialMatch> potential_matches = m_future.get();
|
||||
for (PotentialMatch p : potential_matches)
|
||||
for (auto [potential_match_size, potential_match_hashes] : potential_matches)
|
||||
{
|
||||
if (HashesMatch(hashes.crc32, p.hashes.crc32) && HashesMatch(hashes.md5, p.hashes.md5) &&
|
||||
HashesMatch(hashes.sha1, p.hashes.sha1) && m_size == p.size)
|
||||
if (HashesMatch(hashes.crc32, potential_match_hashes.crc32) &&
|
||||
HashesMatch(hashes.md5, potential_match_hashes.md5) &&
|
||||
HashesMatch(hashes.sha1, potential_match_hashes.sha1) && m_size == potential_match_size)
|
||||
{
|
||||
return {Status::GoodDump, Common::GetStringT("Good dump")};
|
||||
}
|
||||
|
@ -1232,15 +1233,15 @@ void VolumeVerifier::Process()
|
|||
{
|
||||
m_group_future = std::async(std::launch::async, [this, read_failed,
|
||||
group_index = m_group_index] {
|
||||
const GroupToVerify& group = m_groups[group_index];
|
||||
const auto& [partition, offset, block_index_start, block_index_end] = m_groups[group_index];
|
||||
u64 offset_in_group = 0;
|
||||
for (u64 block_index = group.block_index_start; block_index < group.block_index_end;
|
||||
for (u64 block_index = block_index_start; block_index < block_index_end;
|
||||
++block_index, offset_in_group += VolumeWii::BLOCK_TOTAL_SIZE)
|
||||
{
|
||||
const u64 block_offset = group.offset + offset_in_group;
|
||||
const u64 block_offset = offset + offset_in_group;
|
||||
|
||||
if (!read_failed && m_volume.CheckBlockIntegrity(
|
||||
block_index, m_data.data() + offset_in_group, group.partition))
|
||||
if (!read_failed &&
|
||||
m_volume.CheckBlockIntegrity(block_index, m_data.data() + offset_in_group, partition))
|
||||
{
|
||||
m_biggest_verified_offset =
|
||||
std::max(m_biggest_verified_offset, block_offset + VolumeWii::BLOCK_TOTAL_SIZE);
|
||||
|
@ -1250,12 +1251,12 @@ void VolumeVerifier::Process()
|
|||
if (m_scrubber.CanBlockBeScrubbed(block_offset))
|
||||
{
|
||||
WARN_LOG_FMT(DISCIO, "Integrity check failed for unused block at {:#x}", block_offset);
|
||||
m_unused_block_errors[group.partition]++;
|
||||
m_unused_block_errors[partition]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG_FMT(DISCIO, "Integrity check failed for block at {:#x}", block_offset);
|
||||
m_block_errors[group.partition]++;
|
||||
m_block_errors[partition]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue