DiscIO: pointer and size instead of spans, loops instead of STL algorithms

Names, game IDs, patch lists, LBA ranges and hash exceptions are passed
as pointer plus count. min/max/fill/copy become ternaries, memset and
memcpy; FST entries sort with an in-place heap sort, partitions with an
insertion sort. WAD content checks decrypt and hash in 2 KiB chunks
straight from the borrowed input; banner names read onto the stack.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-11-07 12:55:07 +01:00
1 parent 23b8d27c35
commit c033a61899
35 files changed
+442 -253

No files matched your search

+8 -4
View File
@@ -646,7 +646,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
if (!std::visit(BootTitle(system, guard, boot->riivolution_patches), boot->parameters))
return false;
DiscIO::Riivolution::ApplyGeneralMemoryPatches(guard, boot->riivolution_patches);
DiscIO::Riivolution::ApplyGeneralMemoryPatches(guard, boot->riivolution_patches.data(),
boot->riivolution_patches.size());
return true;
}
@@ -752,11 +753,14 @@ void AddRiivolutionPatches(BootParameters* boot_params,
std::move(disc.volume),
[&](std::vector<DiscIO::FSTBuilderNode>* fst) {
DiscIO::Riivolution::ApplyPatchesToFiles(
riivolution_patches, DiscIO::Riivolution::PatchIndex::DolphinSysFiles, fst, nullptr);
riivolution_patches.data(), riivolution_patches.size(),
DiscIO::Riivolution::PatchIndex::DolphinSysFiles, fst, nullptr);
},
[&](std::vector<DiscIO::FSTBuilderNode>* fst, DiscIO::FSTBuilderNode* dol_node) {
DiscIO::Riivolution::ApplyPatchesToFiles(
riivolution_patches, DiscIO::Riivolution::PatchIndex::FileSystem, fst, dol_node);
DiscIO::Riivolution::ApplyPatchesToFiles(riivolution_patches.data(),
riivolution_patches.size(),
DiscIO::Riivolution::PatchIndex::FileSystem, fst,
dol_node);
}));
boot_params->riivolution_patches = std::move(riivolution_patches);
}
+2 -1
View File
@@ -210,7 +210,8 @@ bool CBoot::RunApploader(Core::System& system, const Core::CPUThreadGuard& guard
ram_address, length);
DVDRead(system, volume, dvd_offset, ram_address, length, partition);
DiscIO::Riivolution::ApplyApploaderMemoryPatches(guard, riivolution_patches, ram_address,
DiscIO::Riivolution::ApplyApploaderMemoryPatches(guard, riivolution_patches.data(),
riivolution_patches.size(), ram_address,
length);
ppc_state.gpr[3] = 0x81300004;
+2 -1
View File
@@ -564,7 +564,8 @@ void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot,
std::optional<DiscIO::Riivolution::SavegameRedirect> savegame_redirect = std::nullopt;
if (system.IsWii())
savegame_redirect = DiscIO::Riivolution::ExtractSavegameRedirect(boot->riivolution_patches);
savegame_redirect = DiscIO::Riivolution::ExtractSavegameRedirect(boot->riivolution_patches.data(),
boot->riivolution_patches.size());
{
ASSERT(IsCPUThread());
+21 -15
View File
@@ -3,7 +3,7 @@
#include "DiscIO/Blob.h"
#include <algorithm>
#include <cstring>
#include <memory>
#include <string>
#include <utility>
@@ -62,7 +62,7 @@ std::string GetName(BlobType blob_type, bool translate)
void SectorReader::SetSectorSize(int blocksize)
{
m_block_size = std::max(blocksize, 0);
m_block_size = blocksize > 0 ? blocksize : 0;
for (auto& cache_entry : m_cache)
{
cache_entry.Reset();
@@ -72,7 +72,7 @@ void SectorReader::SetSectorSize(int blocksize)
void SectorReader::SetChunkSize(int block_cnt)
{
m_chunk_blocks = std::max(block_cnt, 1);
m_chunk_blocks = block_cnt > 1 ? block_cnt : 1;
// Clear cache and resize the data arrays
SetSectorSize(m_block_size);
}
@@ -81,13 +81,14 @@ SectorReader::~SectorReader() = default;
const SectorReader::Cache* SectorReader::FindCacheLine(u64 block_num)
{
auto itr =
std::ranges::find_if(m_cache, [&](const Cache& entry) { return entry.Contains(block_num); });
if (itr == m_cache.end())
return nullptr;
itr->MarkUsed();
return &*itr;
for (Cache& entry : m_cache)
{
if (!entry.Contains(block_num))
continue;
entry.MarkUsed();
return &entry;
}
return nullptr;
}
SectorReader::Cache* SectorReader::GetEmptyCacheLine()
@@ -148,9 +149,9 @@ bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr)
// Cache entries are aligned chunks, we may not want to read from the start
u32 read_offset = static_cast<u32>(block - cache->block_idx) * m_block_size + position_in_block;
u32 can_read = m_block_size * cache->num_blocks - read_offset;
u32 was_read = static_cast<u32>(std::min<u64>(can_read, remain));
u32 was_read = static_cast<u32>(can_read < remain ? u64(can_read) : remain);
std::copy_n(cache->data.begin() + read_offset, was_read, out_ptr);
std::memcpy(out_ptr, cache->data.data() + read_offset, was_read);
offset += was_read;
out_ptr += was_read;
@@ -181,13 +182,18 @@ u32 SectorReader::ReadChunk(u8* buffer, u64 chunk_num)
// read a whole chunk. We need to clamp down in that case.
u64 end_block = (GetDataSize() + m_block_size - 1) / m_block_size;
if (end_block)
cnt_blocks = static_cast<u32>(std::min<u64>(m_chunk_blocks, end_block - block_num));
{
const u64 blocks_left = end_block - block_num;
cnt_blocks = static_cast<u32>(u64(m_chunk_blocks) < blocks_left ? u64(m_chunk_blocks) :
blocks_left);
}
if (ReadMultipleAlignedBlocks(block_num, cnt_blocks, buffer))
{
if (cnt_blocks < m_chunk_blocks)
{
std::fill(buffer + cnt_blocks * m_block_size, buffer + m_chunk_blocks * m_block_size, 0u);
std::memset(buffer + cnt_blocks * m_block_size, 0,
(m_chunk_blocks - cnt_blocks) * m_block_size);
}
return cnt_blocks;
}
@@ -200,7 +206,7 @@ u32 SectorReader::ReadChunk(u8* buffer, u64 chunk_num)
{
if (!GetBlock(block_num + i, buffer))
{
std::fill_n(buffer, (cnt_blocks - i) * m_block_size, 0u);
std::memset(buffer, 0, (cnt_blocks - i) * m_block_size);
return i;
}
buffer += m_block_size;
+4 -3
View File
@@ -3,7 +3,7 @@
#include "DiscIO/CISOBlob.h"
#include <algorithm>
#include <cstring>
#include <memory>
#include <utility>
@@ -61,7 +61,8 @@ bool CISOFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
{
u64 const block = offset / m_block_size;
u64 const data_offset = offset % m_block_size;
u64 const bytes_to_read = std::min(m_block_size - data_offset, nbytes);
u64 const block_left = m_block_size - data_offset;
u64 const bytes_to_read = block_left < nbytes ? block_left : nbytes;
if (block < CISO_MAP_SIZE && UNUSED_BLOCK_ID != m_ciso_map[block])
{
@@ -73,7 +74,7 @@ bool CISOFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
}
else
{
std::fill_n(out_ptr, bytes_to_read, 0);
std::memset(out_ptr, 0, bytes_to_read);
}
out_ptr += bytes_to_read;
+2 -1
View File
@@ -102,7 +102,8 @@ private:
// Returns CLUSTER_SIZE or smaller at the end of the file.
const auto get_read_size = [&](u64 pos) {
return std::min<u64>(total_size - pos, DiscScrubber::CLUSTER_SIZE);
const u64 left = total_size - pos;
return left < u64(DiscScrubber::CLUSTER_SIZE) ? left : u64(DiscScrubber::CLUSTER_SIZE);
};
// Used for periodic progress logging.
+1 -2
View File
@@ -3,7 +3,6 @@
#include "DiscIO/CompressedBlob.h"
#include <algorithm>
#include <cstring>
#include <expected>
#include <memory>
@@ -178,7 +177,7 @@ bool CompressedBlobReader::GetBlock(u64 block_num, u8* out_ptr)
if (uncompressed)
{
std::copy_n(m_zlib_buffer.begin(), m_header.block_size, out_ptr);
std::memcpy(out_ptr, m_zlib_buffer.data(), m_header.block_size);
}
else
{
+81 -23
View File
@@ -3,7 +3,6 @@
#include "DiscIO/DirectoryBlob.h"
#include <algorithm>
#include <cstring>
#include <map>
#include <memory>
@@ -288,7 +287,8 @@ u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, const std::string& path)
u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path)
{
const u64 size = std::min(File::GetSize(path), max_size);
const u64 file_size = File::GetSize(path);
const u64 size = file_size < max_size ? file_size : max_size;
Add(offset, size, ContentFile(path, 0));
return size;
}
@@ -301,7 +301,9 @@ bool DiscContentContainer::ReadContent(const DiscContent* content, u64* offset,
if (offset_in_content >= content->size)
return true;
bytes_to_read = std::min(content->size - offset_in_content, *length);
bytes_to_read = content->size - offset_in_content;
if (*length < bytes_to_read)
bytes_to_read = *length;
switch (content->type)
{
@@ -397,7 +399,10 @@ static std::optional<PartitionType> ParsePartitionDirectoryName(const std::strin
}
// e.g. "P0"
if (std::all_of(name.cbegin() + 1, name.cend(), [](char c) { return c >= '0' && c <= '9'; }))
size_t digits = 1;
while (digits < name.size() && name[digits] >= '0' && name[digits] <= '9')
digits++;
if (digits == name.size())
{
u32 result;
if (TryParse(name.substr(1), &result))
@@ -887,7 +892,8 @@ void DirectoryBlobReader::SetWiiRegionData(const u8* wii_region_data, size_t siz
std::memset(region_data + 0x10, 0x80, WII_REGION_DATA_SIZE - 0x10);
Write32(INVALID_REGION, 0, region_data);
std::memcpy(region_data, wii_region_data, std::min<size_t>(size, WII_REGION_DATA_SIZE));
std::memcpy(region_data, wii_region_data,
size < WII_REGION_DATA_SIZE ? size_t(size) : size_t(WII_REGION_DATA_SIZE));
if (size < 0x4)
ERROR_LOG_FMT(DISCIO, "Couldn't read region from {}", log_path);
@@ -898,17 +904,26 @@ void DirectoryBlobReader::SetWiiRegionData(const u8* wii_region_data, size_t siz
ContentMemory(blob, 0));
}
static bool PartitionLess(const DirectoryBlobReader::PartitionWithType& lhs,
const DirectoryBlobReader::PartitionWithType& rhs)
{
if (lhs.type == rhs.type)
return lhs.partition.GetRootDirectory() < rhs.partition.GetRootDirectory();
// Ascending sort by partition type, except Update (1) comes before before Game (0)
return (lhs.type > PartitionType::Update || rhs.type > PartitionType::Update) ?
lhs.type < rhs.type :
lhs.type > rhs.type;
}
void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partitions)
{
std::ranges::sort(partitions, [](const PartitionWithType& lhs, const PartitionWithType& rhs) {
if (lhs.type == rhs.type)
return lhs.partition.GetRootDirectory() < rhs.partition.GetRootDirectory();
// Ascending sort by partition type, except Update (1) comes before before Game (0)
return (lhs.type > PartitionType::Update || rhs.type > PartitionType::Update) ?
lhs.type < rhs.type :
lhs.type > rhs.type;
});
// a handful of partitions: insertion sort
for (size_t i = 1; i < partitions.size(); i++)
{
for (size_t j = i; j > 0 && PartitionLess(partitions[j], partitions[j - 1]); j--)
std::swap(partitions[j], partitions[j - 1]);
}
u32 subtable_1_size = 0;
while (subtable_1_size < partitions.size() && subtable_1_size < 3 &&
@@ -945,7 +960,10 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partiti
offset_in_table = PARTITION_SUBTABLE2_OFFSET;
if (partitions[i].type == PartitionType::Game)
partition_address = std::max(partition_address, STANDARD_GAME_PARTITION_ADDRESS);
{
if (partition_address < STANDARD_GAME_PARTITION_ADDRESS)
partition_address = STANDARD_GAME_PARTITION_ADDRESS;
}
Write32(static_cast<u32>(partition_address >> 2), u32(offset_in_table), partition_table);
offset_in_table += 4;
@@ -1360,7 +1378,8 @@ u64 DirectoryBlobPartition::SetApploader(ContentBlob* apploader, const std::stri
if (apploader)
{
if (header)
std::memcpy(ContentBlobData(header), ContentBlobData(apploader), size_t(std::min<u64>(size, 0x20)));
std::memcpy(ContentBlobData(header), ContentBlobData(apploader),
size < 0x20 ? size_t(size) : size_t(0x20));
ContentBlobRelease(apploader);
}
apploader = header;
@@ -1438,13 +1457,17 @@ static void ConvertUTF8NamesToSHIFTJIS(std::vector<FSTBuilderNode>* fst)
}
}
static u32 ComputeNameSize(std::span<const FSTBuilderNode> files)
static u32 ComputeNameSize(const FSTBuilderNode* files, size_t count)
{
u32 name_size = 0;
for (const FSTBuilderNode& entry : files)
for (size_t i = 0; i < count; i++)
{
const FSTBuilderNode& entry = files[i];
if (entry.IsFolder())
name_size += ComputeNameSize(entry.GetFolderContent());
{
const std::vector<FSTBuilderNode>& children = entry.GetFolderContent();
name_size += ComputeNameSize(children.data(), children.size());
}
name_size += static_cast<u32>(entry.m_filename.length() + 1);
}
return name_size;
@@ -1471,6 +1494,38 @@ static bool NameLess(const FSTBuilderNode& one, const FSTBuilderNode& two)
return one.m_filename < two.m_filename;
}
// In-place heap sort: no allocation, O(n log n); names are unique so
// stability does not matter.
static void SiftDown(FSTBuilderNode* nodes, size_t root, size_t count)
{
for (;;)
{
size_t child = root * 2 + 1;
if (child >= count)
return;
if (child + 1 < count && NameLess(nodes[child], nodes[child + 1]))
child++;
if (!NameLess(nodes[root], nodes[child]))
return;
std::swap(nodes[root], nodes[child]);
root = child;
}
}
static void SortByName(FSTBuilderNode* nodes, size_t count)
{
size_t i;
if (count < 2)
return;
for (i = count / 2; i > 0; i--)
SiftDown(nodes, i - 1, count);
for (i = count - 1; i > 0; i--)
{
std::swap(nodes[0], nodes[i]);
SiftDown(nodes, 0, i);
}
}
static size_t RecalculateFolderSizes(std::vector<FSTBuilderNode>* fst)
{
size_t size = 0;
@@ -1491,7 +1546,7 @@ void DirectoryBlobPartition::BuildFST(std::vector<FSTBuilderNode> root_nodes, u6
{
ConvertUTF8NamesToSHIFTJIS(&root_nodes);
u32 name_table_size = Common::AlignUp(ComputeNameSize(root_nodes), 1ull << m_address_shift);
u32 name_table_size = Common::AlignUp(ComputeNameSize(root_nodes.data(), root_nodes.size()), 1ull << m_address_shift);
// 1 extra for the root entry
u64 total_entries = RecalculateFolderSizes(&root_nodes) + 1;
@@ -1563,7 +1618,7 @@ void DirectoryBlobPartition::WriteDirectory(u8* fst_data,
std::vector<FSTBuilderNode>& sorted_entries = *parent_entries;
// Sort for determinism
std::ranges::sort(sorted_entries, NameLess);
SortByName(sorted_entries.data(), sorted_entries.size());
for (FSTBuilderNode& entry : sorted_entries)
{
@@ -1614,7 +1669,8 @@ void DirectoryBlobPartition::WriteDirectory(u8* fst_data,
static size_t ReadFileToBuffer(const std::string& path, u8* buffer, size_t size)
{
File::DirectIOFile file(path, File::AccessMode::Read);
const size_t n = size_t(std::min<u64>(file.GetSize(), size));
const u64 file_size = file.GetSize();
const size_t n = file_size < size ? size_t(file_size) : size;
return n && file.OffsetRead(0, buffer, n) ? n : 0;
}
@@ -1622,7 +1678,9 @@ static void PadToAddress(u64 start_address, u64* address, u64* length, u8** buff
{
if (start_address > *address && *length > 0)
{
u64 padBytes = std::min(start_address - *address, *length);
u64 padBytes = start_address - *address;
if (*length < padBytes)
padBytes = *length;
memset(*buffer, 0, (size_t)padBytes);
*length -= padBytes;
*buffer += padBytes;
+2 -1
View File
@@ -342,7 +342,6 @@ public:
std::string GetCompressionMethod() const override { return {}; }
std::optional<int> GetCompressionLevel() const override { return std::nullopt; }
private:
struct PartitionWithType
{
PartitionWithType(DirectoryBlobPartition&& partition_, PartitionType type_)
@@ -354,6 +353,8 @@ private:
PartitionType type;
};
private:
explicit DirectoryBlobReader(const std::string& game_partition_root,
const std::string& true_root);
explicit DirectoryBlobReader(
+3 -3
View File
@@ -3,7 +3,6 @@
#include "DiscIO/DiscExtractor.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstring>
@@ -28,7 +27,8 @@ u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* f
if (!file_info || file_info->IsDirectory() || offset_in_file >= file_info->GetSize())
return 0;
const u64 read_length = std::min(max_buffer_size, file_info->GetSize() - offset_in_file);
const u64 file_left = file_info->GetSize() - offset_in_file;
const u64 read_length = max_buffer_size < file_left ? max_buffer_size : file_left;
DEBUG_LOG_FMT(DISCIO, "Reading {:x} bytes at {:x} from file {}. Offset: {:x} Size: {:x}",
read_length, offset_in_file, file_info->GetPath(), file_info->GetOffset(),
@@ -61,7 +61,7 @@ bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u6
while (size)
{
// Limit read size to 128 MB
const size_t read_size = static_cast<size_t>(std::min<u64>(size, 0x08000000));
const size_t read_size = static_cast<size_t>(size < 0x08000000 ? size : 0x08000000);
std::vector<u8> buffer(read_size);
+36 -16
View File
@@ -3,9 +3,7 @@
#include "DiscIO/DiscUtils.h"
#include <algorithm>
#include <optional>
#include <span>
#include <string>
#include <vector>
@@ -40,7 +38,10 @@ std::string NameForPartitionType(u32 partition_type, bool include_prefix)
static_cast<char>((partition_type >> 16) & 0xFF),
static_cast<char>((partition_type >> 8) & 0xFF),
static_cast<char>(partition_type & 0xFF)};
if (std::ranges::all_of(type_as_game_id, Common::IsAlnum))
bool all_alnum = true;
for (const char c : type_as_game_id)
all_alnum = all_alnum && Common::IsAlnum(c);
if (all_alnum)
{
return include_prefix ? "P-" + type_as_game_id : type_as_game_id;
}
@@ -89,7 +90,8 @@ std::optional<u32> GetBootDOLSize(const Volume& volume, const Partition& partiti
const std::optional<u32> size = volume.ReadSwapped<u32>(dol_offset + 0x90 + i * 4, partition);
if (!offset || !size)
return {};
dol_size = std::max(*offset + *size, dol_size);
if (*offset + *size > dol_size)
dol_size = *offset + *size;
}
// Iterate through the 11 data segments
@@ -99,7 +101,8 @@ std::optional<u32> GetBootDOLSize(const Volume& volume, const Partition& partiti
const std::optional<u32> size = volume.ReadSwapped<u32>(dol_offset + 0xac + i * 4, partition);
if (!offset || !size)
return {};
dol_size = std::max(*offset + *size, dol_size);
if (*offset + *size > dol_size)
dol_size = *offset + *size;
}
return dol_size;
@@ -123,6 +126,9 @@ std::optional<u64> GetFSTSize(const Volume& volume, const Partition& partition)
return volume.ReadSwappedAndShifted(0x428, partition);
}
static u64 GetBiggestReferencedOffset(const Volume& volume, const Partition* partitions,
size_t partition_count);
u64 GetBiggestReferencedOffset(const Volume& volume)
{
std::vector<Partition> partitions = volume.GetPartitions();
@@ -131,14 +137,18 @@ u64 GetBiggestReferencedOffset(const Volume& volume)
// This can happen when certain programs that create WBFS files scrub the entirety of
// the Masterpiece partitions in Super Smash Bros. Brawl without removing them from
// the partition table. https://bugs.dolphin-emu.org/issues/8733
std::erase_if(partitions, [&](const Partition& partition) {
return volume.ReadSwapped<u32>(0x18, partition) != WII_DISC_MAGIC;
});
size_t kept = 0;
for (size_t i = 0; i < partitions.size(); i++)
{
if (volume.ReadSwapped<u32>(0x18, partitions[i]) == WII_DISC_MAGIC)
partitions[kept++] = partitions[i];
}
partitions.resize(kept);
if (partitions.empty())
partitions.push_back(PARTITION_NONE);
return GetBiggestReferencedOffset(volume, partitions);
return GetBiggestReferencedOffset(volume, partitions.data(), partitions.size());
}
static u64 GetBiggestReferencedOffset(const Volume& volume, const FileInfo& file_info)
@@ -147,7 +157,11 @@ static u64 GetBiggestReferencedOffset(const Volume& volume, const FileInfo& file
{
u64 biggest_offset = 0;
for (const FileInfo& f : file_info)
biggest_offset = std::max(biggest_offset, GetBiggestReferencedOffset(volume, f));
{
const u64 offset = GetBiggestReferencedOffset(volume, f);
if (offset > biggest_offset)
biggest_offset = offset;
}
return biggest_offset;
}
else
@@ -156,16 +170,19 @@ static u64 GetBiggestReferencedOffset(const Volume& volume, const FileInfo& file
}
}
u64 GetBiggestReferencedOffset(const Volume& volume, std::span<const Partition> partitions)
static u64 GetBiggestReferencedOffset(const Volume& volume, const Partition* partitions,
size_t partition_count)
{
const u64 disc_header_size = volume.GetVolumeType() == Platform::GameCubeDisc ? 0x460 : 0x50000;
u64 biggest_offset = disc_header_size;
for (const Partition& partition : partitions)
for (size_t i = 0; i < partition_count; i++)
{
const Partition& partition = partitions[i];
if (partition != PARTITION_NONE)
{
const u64 offset = volume.PartitionOffsetToRawOffset(0x440, partition);
biggest_offset = std::max(biggest_offset, offset);
if (offset > biggest_offset)
biggest_offset = offset;
}
const std::optional<u64> dol_offset = GetBootDOLOffset(volume, partition);
@@ -175,7 +192,8 @@ u64 GetBiggestReferencedOffset(const Volume& volume, std::span<const Partition>
if (dol_size)
{
const u64 offset = volume.PartitionOffsetToRawOffset(*dol_offset + *dol_size, partition);
biggest_offset = std::max(biggest_offset, offset);
if (offset > biggest_offset)
biggest_offset = offset;
}
}
@@ -184,7 +202,8 @@ u64 GetBiggestReferencedOffset(const Volume& volume, std::span<const Partition>
if (fst_offset && fst_size)
{
const u64 offset = volume.PartitionOffsetToRawOffset(*fst_offset + *fst_size, partition);
biggest_offset = std::max(biggest_offset, offset);
if (offset > biggest_offset)
biggest_offset = offset;
}
const FileSystem* fs = volume.GetFileSystem(partition);
@@ -192,7 +211,8 @@ u64 GetBiggestReferencedOffset(const Volume& volume, std::span<const Partition>
{
const u64 offset_in_partition = GetBiggestReferencedOffset(volume, fs->GetRoot());
const u64 offset = volume.PartitionOffsetToRawOffset(offset_in_partition, partition);
biggest_offset = std::max(biggest_offset, offset);
if (offset > biggest_offset)
biggest_offset = offset;
}
}
return biggest_offset;
-2
View File
@@ -4,7 +4,6 @@
#pragma once
#include <optional>
#include <span>
#include <string>
#include "Common/CommonTypes.h"
@@ -84,7 +83,6 @@ std::optional<u64> GetFSTOffset(const Volume& volume, const Partition& partition
std::optional<u64> GetFSTSize(const Volume& volume, const Partition& partition);
u64 GetBiggestReferencedOffset(const Volume& volume);
u64 GetBiggestReferencedOffset(const Volume& volume, std::span<const Partition> partitions);
bool IsGCZBlockSizeLegacyCompatible(int block_size, u64 file_size);
bool IsDiscImageBlockSizeValid(int block_size, BlobType format);
-1
View File
@@ -3,7 +3,6 @@
#include "DiscIO/FileBlob.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
+8 -3
View File
@@ -3,7 +3,6 @@
#include "DiscIO/FileSystemGCWii.h"
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <map>
@@ -141,8 +140,14 @@ bool FileInfoGCWii::NameCaseInsensitiveEquals(std::string_view other) const
{
// other is in UTF-8 and this is in Shift-JIS, so we convert so that we can compare correctly
const std::string this_utf8 = SHIFTJISToUTF8(this_ptr);
return std::equal(this_utf8.cbegin(), this_utf8.cend(), other.cbegin() + i, other.cend(),
[](char a, char b) { return Common::ToLower(a) == Common::ToLower(b); });
if (this_utf8.size() != other.size() - i)
return false;
for (size_t j = 0; j < this_utf8.size(); j++)
{
if (Common::ToLower(this_utf8[j]) != Common::ToLower(other[i + j]))
return false;
}
return true;
}
else if (Common::ToLower(*this_ptr) != Common::ToLower(*other_ptr))
{
+13 -11
View File
@@ -2,7 +2,6 @@
#include "DiscIO/LaggedFibonacciGenerator.h"
#include <algorithm>
#include <cstddef>
#include <cstring>
@@ -68,18 +67,20 @@ bool LaggedFibonacciGenerator::GetSeed(const u32* data, size_t size, size_t data
return false;
// If the data doesn't look like something we can regenerate, return early to save time
if (!std::all_of(data, data + LFG_K, [](u32 x) {
return (Common::swap32(x) & 0x00C00000) == (Common::swap32(x) >> 2 & 0x00C00000);
}))
for (size_t i = 0; i < LFG_K; i++)
{
return false;
const u32 x = Common::swap32(data[i]);
if ((x & 0x00C00000) != (x >> 2 & 0x00C00000))
return false;
}
const size_t data_offset_mod_k = data_offset % LFG_K;
const size_t data_offset_div_k = data_offset / LFG_K;
std::copy_n(data, LFG_K - data_offset_mod_k, lfg->m_buffer.data() + data_offset_mod_k);
std::copy_n(data + LFG_K - data_offset_mod_k, data_offset_mod_k, lfg->m_buffer.data());
std::memcpy(lfg->m_buffer.data() + data_offset_mod_k, data,
(LFG_K - data_offset_mod_k) * sizeof(u32));
std::memcpy(lfg->m_buffer.data(), data + LFG_K - data_offset_mod_k,
data_offset_mod_k * sizeof(u32));
lfg->Backward(0, data_offset_mod_k);
@@ -99,7 +100,8 @@ void LaggedFibonacciGenerator::GetBytes(size_t count, u8* out)
{
while (count > 0)
{
const size_t length = std::min(count, LFG_K * sizeof(u32) - m_position_bytes);
const size_t buffer_left = LFG_K * sizeof(u32) - m_position_bytes;
const size_t length = count < buffer_left ? count : buffer_left;
std::memcpy(out, reinterpret_cast<u8*>(m_buffer.data()) + m_position_bytes, length);
@@ -151,11 +153,11 @@ void LaggedFibonacciGenerator::Forward()
void LaggedFibonacciGenerator::Backward(size_t start_word, size_t end_word)
{
const size_t loop_end = std::max(LFG_J, start_word);
for (size_t i = std::min(end_word, LFG_K); i > loop_end; --i)
const size_t loop_end = LFG_J > start_word ? LFG_J : start_word;
for (size_t i = end_word < LFG_K ? end_word : LFG_K; i > loop_end; --i)
m_buffer[i - 1] ^= m_buffer[i - 1 - LFG_J];
for (size_t i = std::min(end_word, LFG_J); i > start_word; --i)
for (size_t i = end_word < LFG_J ? end_word : LFG_J; i > start_word; --i)
m_buffer[i - 1] ^= m_buffer[i - 1 + LFG_K - LFG_J];
}
+16 -11
View File
@@ -3,7 +3,6 @@
#include "DiscIO/NFSBlob.h"
#include <algorithm>
#include <array>
#include <cstring>
#include <memory>
@@ -51,8 +50,9 @@ bool NFSFileReader::ReadKey(const std::string& path, const std::string& director
std::vector<NFSLBARange> NFSFileReader::GetLBARanges(const NFSHeader& header)
{
const size_t stored_count = Common::swap32(header.lba_range_count);
const size_t lba_range_count =
std::min<size_t>(Common::swap32(header.lba_range_count), header.lba_ranges.size());
stored_count < header.lba_ranges.size() ? stored_count : header.lba_ranges.size();
std::vector<NFSLBARange> lba_ranges;
lba_ranges.reserve(lba_range_count);
@@ -105,20 +105,24 @@ std::vector<File::DirectIOFile> NFSFileReader::OpenFiles(const std::string& dire
return files;
}
u64 NFSFileReader::CalculateExpectedRawSize(std::span<const NFSLBARange> lba_ranges)
u64 NFSFileReader::CalculateExpectedRawSize(const NFSLBARange* lba_ranges, size_t count)
{
u64 total_blocks = 0;
for (const NFSLBARange& range : lba_ranges)
total_blocks += range.num_blocks;
for (size_t i = 0; i < count; i++)
total_blocks += lba_ranges[i].num_blocks;
return sizeof(NFSHeader) + total_blocks * BLOCK_SIZE;
}
u64 NFSFileReader::CalculateExpectedDataSize(std::span<const NFSLBARange> lba_ranges)
u64 NFSFileReader::CalculateExpectedDataSize(const NFSLBARange* lba_ranges, size_t count)
{
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 (size_t i = 0; i < count; i++)
{
const u32 end = lba_ranges[i].start_block + lba_ranges[i].num_blocks;
if (end > greatest_block_index)
greatest_block_index = end;
}
return u64(greatest_block_index) * BLOCK_SIZE;
}
@@ -141,7 +145,7 @@ std::unique_ptr<NFSFileReader> NFSFileReader::Create(File::DirectIOFile first_fi
std::vector<NFSLBARange> lba_ranges = GetLBARanges(header);
const u64 expected_raw_size = CalculateExpectedRawSize(lba_ranges);
const u64 expected_raw_size = CalculateExpectedRawSize(lba_ranges.data(), lba_ranges.size());
u64 raw_size;
std::vector<File::DirectIOFile> files =
@@ -159,7 +163,7 @@ NFSFileReader::NFSFileReader(std::vector<NFSLBARange> lba_ranges,
: m_lba_ranges(std::move(lba_ranges)), m_files(std::move(files)),
m_aes_context(Common::AES::CreateContextDecrypt(key.data())), m_raw_size(raw_size), m_key(key)
{
m_data_size = CalculateExpectedDataSize(m_lba_ranges);
m_data_size = CalculateExpectedDataSize(m_lba_ranges.data(), m_lba_ranges.size());
}
std::unique_ptr<BlobReader> NFSFileReader::CopyReader() const
@@ -285,7 +289,8 @@ bool NFSFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
m_current_logical_block_index = logical_block_index;
}
const u64 bytes_to_copy = std::min(nbytes, BLOCK_SIZE - offset_in_block);
const u64 block_left = BLOCK_SIZE - offset_in_block;
const u64 bytes_to_copy = nbytes < block_left ? nbytes : block_left;
std::memcpy(out_ptr, m_current_block_decrypted.data() + offset_in_block, bytes_to_copy);
offset += bytes_to_copy;
+2 -3
View File
@@ -6,7 +6,6 @@
#include <array>
#include <limits>
#include <memory>
#include <span>
#include <string>
#include <vector>
@@ -69,8 +68,8 @@ private:
static std::vector<File::DirectIOFile> OpenFiles(const std::string& directory,
File::DirectIOFile first_file,
u64 expected_raw_size, u64* raw_size_out);
static u64 CalculateExpectedRawSize(std::span<const NFSLBARange> lba_ranges);
static u64 CalculateExpectedDataSize(std::span<const NFSLBARange> lba_ranges);
static u64 CalculateExpectedRawSize(const NFSLBARange* lba_ranges, size_t count);
static u64 CalculateExpectedDataSize(const NFSLBARange* lba_ranges, size_t count);
NFSFileReader(std::vector<NFSLBARange> lba_ranges, std::vector<File::DirectIOFile> files, Key key,
u64 raw_size);
+21 -6
View File
@@ -3,7 +3,6 @@
#include "DiscIO/RiivolutionParser.h"
#include <algorithm>
#include <sstream>
#include <string>
#include <string_view>
@@ -146,8 +145,16 @@ std::optional<Disc> ParseString(std::string_view xml, std::string xml_path)
const std::string macro_id = macro_node.attribute("id").as_string();
for (auto& section : 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())
const Option* option_to_clone = nullptr;
for (const Option& option : section.m_options)
{
if (option.m_id == macro_id)
{
option_to_clone = &option;
break;
}
}
if (!option_to_clone)
continue;
Option cloned_option = *option_to_clone;
@@ -218,7 +225,7 @@ std::optional<Disc> ParseString(std::string_view xml, std::string xml_path)
return disc;
}
static bool CheckRegion(std::span<const std::string> xml_regions, std::string_view game_region)
static bool CheckRegion(const std::vector<std::string>& xml_regions, std::string_view game_region)
{
if (xml_regions.empty())
return true;
@@ -304,8 +311,16 @@ std::vector<Patch> Disc::GeneratePatches(const std::string& game_id) const
const Choice& choice = option.m_choices[selected - 1];
for (const auto& patch_ref : choice.m_patch_references)
{
const auto patch = std::ranges::find(m_patches, patch_ref.m_id, &Patch::m_id);
if (patch == m_patches.end())
const Patch* patch = nullptr;
for (const Patch& candidate : m_patches)
{
if (candidate.m_id == patch_ref.m_id)
{
patch = &candidate;
break;
}
}
if (!patch)
continue;
std::vector<std::pair<std::string, std::string_view>> replacements;
+68 -42
View File
@@ -3,7 +3,6 @@
#include "DiscIO/RiivolutionPatcher.h"
#include <algorithm>
#include <string>
#include <string_view>
#include <vector>
@@ -102,7 +101,7 @@ FileDataLoaderHostFS::MakeAbsoluteFromRelative(std::string_view external_relativ
result.pop_back();
result.pop_back();
}
else if (std::ranges::all_of(element, [](char c) { return c == '.'; }))
else if (element.find_first_not_of('.') == std::string_view::npos)
{
// This is a triple, quadruple, etc. dot.
// Some file systems treat this as several 'up' path traversals, but Riivolution does not.
@@ -243,14 +242,17 @@ static void ApplyPatchToFile(const Patch& patch, FSTBuilderNode* file_node,
auto& content = std::get<std::vector<BuilderContentSource>>(file_node->m_content);
const u64 raw_external_filesize = *f;
const u64 external_file_offset = std::min(raw_external_file_offset, raw_external_filesize);
const u64 external_file_offset = raw_external_file_offset < raw_external_filesize ?
raw_external_file_offset :
raw_external_filesize;
const u64 external_filesize = raw_external_filesize - external_file_offset;
const u64 patch_start = file_patch_offset;
const u64 patch_size = file_patch_length == 0 ? external_filesize : file_patch_length;
const u64 patch_end = patch_start + patch_size;
const u64 target_filesize = resize ? patch_end : std::max(file_node->m_size, patch_end);
const u64 target_filesize =
resize || patch_end > file_node->m_size ? patch_end : file_node->m_size;
size_t insert_where = 0;
if (patch_start >= file_node->m_size)
@@ -307,7 +309,8 @@ static void ApplyPatchToFile(const Patch& patch, FSTBuilderNode* file_node,
if (patch_size > 0 && external_filesize > 0)
{
BuilderContentSource source = patch.m_file_data_loader->MakeContentSource(
external_filename, external_file_offset, std::min(patch_size, external_filesize),
external_filename, external_file_offset,
patch_size < external_filesize ? patch_size : external_filesize,
patch_start);
content.emplace(content.begin() + insert_where, std::move(source));
++insert_where;
@@ -342,11 +345,17 @@ static FSTBuilderNode* FindFileNodeInFST(std::string_view path, std::vector<FSTB
const size_t path_separator = path.find('/');
const bool is_file = path_separator == std::string_view::npos;
const std::string_view name = is_file ? path : path.substr(0, path_separator);
const auto it = std::ranges::find_if(*fst, [&](const FSTBuilderNode& node) {
return Common::CaseInsensitiveEquals(node.m_filename, name);
});
FSTBuilderNode* it = nullptr;
for (FSTBuilderNode& node : *fst)
{
if (Common::CaseInsensitiveEquals(node.m_filename, name))
{
it = &node;
break;
}
}
if (it == fst->end())
if (!it)
{
if (!create_if_not_exists)
return nullptr;
@@ -367,7 +376,7 @@ static FSTBuilderNode* FindFileNodeInFST(std::string_view path, std::vector<FSTB
if (is_file != is_existing_node_file)
return nullptr;
if (is_file)
return &*it;
return it;
return FindFileNodeInFST(path.substr(path_separator + 1),
&std::get<std::vector<FSTBuilderNode>>(it->m_content),
@@ -464,11 +473,12 @@ static void ApplyFolderPatchToFST(const Patch& patch, const Folder& folder,
ApplyFolderPatchToFST(patch, folder, fst, dol_node, folder.m_disc, folder.m_external);
}
void ApplyPatchesToFiles(std::span<const Patch> patches, PatchIndex index,
void ApplyPatchesToFiles(const Patch* patches, size_t patch_count, PatchIndex index,
std::vector<FSTBuilderNode>* fst, FSTBuilderNode* dol_node)
{
for (const auto& patch : patches)
for (size_t i = 0; i < patch_count; i++)
{
const Patch& patch = patches[i];
const auto& file_patches =
index == PatchIndex::DolphinSysFiles ? patch.m_sys_file_patches : patch.m_file_patches;
const auto& folder_patches =
@@ -482,10 +492,10 @@ void ApplyPatchesToFiles(std::span<const Patch> patches, PatchIndex index,
}
}
static bool MemoryMatchesAt(const Core::CPUThreadGuard& guard, u32 offset,
std::span<const u8> value)
static bool MemoryMatchesAt(const Core::CPUThreadGuard& guard, u32 offset, const u8* value,
size_t value_size)
{
for (u32 i = 0; i < value.size(); ++i)
for (u32 i = 0; i < value_size; ++i)
{
auto result = PowerPC::MMU::HostTryRead<u8>(guard, offset + i);
if (!result || result->value != value[i])
@@ -494,34 +504,34 @@ static bool MemoryMatchesAt(const Core::CPUThreadGuard& guard, u32 offset,
return true;
}
static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, u32 offset,
std::span<const u8> value, std::span<const u8> original)
static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, u32 offset, const u8* value,
size_t value_size, const u8* original, size_t original_size)
{
if (AchievementManager::GetInstance().IsHardcoreModeActive())
return;
if (value.empty())
if (!value_size)
return;
if (!original.empty() && !MemoryMatchesAt(guard, offset, original))
if (original_size && !MemoryMatchesAt(guard, offset, original, original_size))
return;
auto& system = guard.GetSystem();
const u32 size = static_cast<u32>(value.size());
const u32 size = static_cast<u32>(value_size);
for (u32 i = 0; i < size; ++i)
PowerPC::MMU::HostTryWrite<u8>(guard, value[i], offset + i);
const u32 overlapping_hook_count = HLE::UnpatchRange(system, offset, offset + size);
if (overlapping_hook_count != 0)
{
WARN_LOG_FMT(OSHLE, "Riivolution memory patch overlaps {} HLE hook(s) at {:08x} (size: {})",
overlapping_hook_count, offset, value.size());
overlapping_hook_count, offset, value_size);
}
}
// The patch's value: lent from its value file, or the parsed bytes as they
// are; File::EndLoan(loan) when done either way.
static std::span<const u8> GetMemoryPatchValue(const Patch& patch, const Memory& memory_patch,
::File::FileLoan* loan)
static const u8* GetMemoryPatchValue(const Patch& patch, const Memory& memory_patch,
::File::FileLoan* loan, size_t* size)
{
loan->data = nullptr;
loan->size = 0;
@@ -529,10 +539,15 @@ static std::span<const u8> GetMemoryPatchValue(const Patch& patch, const Memory&
if (!memory_patch.m_valuefile.empty())
{
if (!patch.m_file_data_loader->LoanFileContents(memory_patch.m_valuefile, loan))
return {};
return std::span<const u8>(loan->data, size_t(loan->size));
{
*size = 0;
return nullptr;
}
*size = size_t(loan->size);
return loan->data;
}
return memory_patch.m_value;
*size = memory_patch.m_value.size();
return memory_patch.m_value.data();
}
static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch,
@@ -542,8 +557,10 @@ static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& pat
return;
::File::FileLoan loan;
ApplyMemoryPatch(guard, memory_patch.m_offset | 0x80000000,
GetMemoryPatchValue(patch, memory_patch, &loan), memory_patch.m_original);
size_t value_size;
const u8* const value = GetMemoryPatchValue(patch, memory_patch, &loan, &value_size);
ApplyMemoryPatch(guard, memory_patch.m_offset | 0x80000000, value, value_size,
memory_patch.m_original.data(), memory_patch.m_original.size());
::File::EndLoan(&loan);
}
@@ -557,10 +574,13 @@ static void ApplySearchMemoryPatch(const Core::CPUThreadGuard& guard, const Patc
for (u32 i = 0; i < length - (stride - 1); i += stride)
{
const u32 address = ram_start + i;
if (MemoryMatchesAt(guard, address, memory_patch.m_original))
if (MemoryMatchesAt(guard, address, memory_patch.m_original.data(),
memory_patch.m_original.size()))
{
::File::FileLoan loan;
ApplyMemoryPatch(guard, address, GetMemoryPatchValue(patch, memory_patch, &loan), {});
size_t value_size;
const u8* const value = GetMemoryPatchValue(patch, memory_patch, &loan, &value_size);
ApplyMemoryPatch(guard, address, value, value_size, nullptr, 0);
::File::EndLoan(&loan);
break;
}
@@ -568,14 +588,15 @@ static void ApplySearchMemoryPatch(const Core::CPUThreadGuard& guard, const Patc
}
static void ApplyOcarinaPattern(const Core::CPUThreadGuard& guard, const Memory& memory_patch,
std::span<const u8> value, u32 ram_start, u32 length)
const u8* value, size_t value_size, u32 ram_start,
u32 length)
{
auto& system = guard.GetSystem();
for (u32 i = 0; i < length; i += 4)
{
// first find the pattern
const u32 address = ram_start + i;
if (MemoryMatchesAt(guard, address, value))
if (MemoryMatchesAt(guard, address, value, value_size))
{
for (; i < length; i += 4)
{
@@ -608,19 +629,22 @@ static void ApplyOcarinaMemoryPatch(const Core::CPUThreadGuard& guard, const Pat
if (memory_patch.m_offset == 0)
return;
::File::FileLoan loan;
const std::span<const u8> value = GetMemoryPatchValue(patch, memory_patch, &loan);
if (!value.empty())
ApplyOcarinaPattern(guard, memory_patch, value, ram_start, length);
size_t value_size;
const u8* const value = GetMemoryPatchValue(patch, memory_patch, &loan, &value_size);
if (value_size)
ApplyOcarinaPattern(guard, memory_patch, value, value_size, ram_start, length);
::File::EndLoan(&loan);
}
void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, std::span<const Patch> patches)
void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, const Patch* patches,
size_t patch_count)
{
const auto& system = guard.GetSystem();
const auto& system_memory = system.GetMemory();
for (const auto& patch : patches)
for (size_t i = 0; i < patch_count; i++)
{
const Patch& patch = patches[i];
for (const auto& memory : patch.m_memory_patches)
{
if (memory.m_ocarina)
@@ -634,11 +658,12 @@ void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, std::span<cons
}
}
void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard, std::span<const Patch> patches,
u32 ram_address, u32 ram_length)
void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard, const Patch* patches,
size_t patch_count, u32 ram_address, u32 ram_length)
{
for (const auto& patch : patches)
for (size_t i = 0; i < patch_count; i++)
{
const Patch& patch = patches[i];
for (const auto& memory : patch.m_memory_patches)
{
if (!memory.m_ocarina && !memory.m_search)
@@ -652,10 +677,11 @@ void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard, std::span<co
}
}
std::optional<SavegameRedirect> ExtractSavegameRedirect(std::span<const Patch> riivolution_patches)
std::optional<SavegameRedirect> ExtractSavegameRedirect(const Patch* patches, size_t patch_count)
{
for (const auto& patch : riivolution_patches)
for (size_t i = 0; i < patch_count; i++)
{
const Patch& patch = patches[i];
if (!patch.m_savegame_patches.empty())
{
const auto& save_patch = patch.m_savegame_patches[0];
+6 -6
View File
@@ -4,7 +4,6 @@
#pragma once
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <vector>
@@ -81,10 +80,11 @@ enum class PatchIndex
DolphinSysFiles,
};
void ApplyPatchesToFiles(std::span<const Patch> patches, PatchIndex index,
void ApplyPatchesToFiles(const Patch* patches, size_t patch_count, PatchIndex index,
std::vector<FSTBuilderNode>* fst, FSTBuilderNode* dol_node);
void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, std::span<const Patch> patches);
void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard, std::span<const Patch> patches,
u32 ram_address, u32 ram_length);
std::optional<SavegameRedirect> ExtractSavegameRedirect(std::span<const Patch> riivolution_patches);
void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, const Patch* patches,
size_t patch_count);
void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard, const Patch* patches,
size_t patch_count, u32 ram_address, u32 ram_length);
std::optional<SavegameRedirect> ExtractSavegameRedirect(const Patch* patches, size_t patch_count);
} // namespace DiscIO::Riivolution
+4 -4
View File
@@ -3,7 +3,7 @@
#include "DiscIO/ScrubbedBlob.h"
#include <algorithm>
#include <cstring>
#include <memory>
#include <string>
#include <utility>
@@ -47,12 +47,12 @@ bool ScrubbedBlob::Read(u64 offset, u64 size, u8* out_ptr)
while (size > 0)
{
constexpr size_t CLUSTER_SIZE = DiscScrubber::CLUSTER_SIZE;
const u64 bytes_to_read =
std::min(Common::AlignDown(offset + CLUSTER_SIZE, CLUSTER_SIZE) - offset, size);
const u64 cluster_left = Common::AlignDown(offset + CLUSTER_SIZE, CLUSTER_SIZE) - offset;
const u64 bytes_to_read = cluster_left < size ? cluster_left : size;
if (m_scrubber.CanBlockBeScrubbed(offset))
{
std::fill_n(out_ptr, bytes_to_read, 0);
std::memset(out_ptr, 0, bytes_to_read);
}
else
{
+2 -1
View File
@@ -69,7 +69,8 @@ bool SplitPlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
{
auto& f = file.file;
const u64 offset_in_file = current_offset - file.offset;
const u64 current_read = std::min(file.size - offset_in_file, rest);
const u64 file_left = file.size - offset_in_file;
const u64 current_read = file_left < rest ? file_left : rest;
if (!f.OffsetRead(offset_in_file, out, current_read))
return false;
+10 -6
View File
@@ -3,7 +3,7 @@
#include "DiscIO/TGCBlob.h"
#include <algorithm>
#include <cstring>
#include <memory>
#include <type_traits>
#include <utility>
@@ -22,13 +22,15 @@ u32 SubtractBE32(u32 minuend_be, u32 subtrahend_le)
void Replace(u64 offset, u64 size, u8* out_ptr, u64 replace_offset, u64 replace_size,
const u8* replace_ptr)
{
const u64 replace_start = std::max(offset, replace_offset);
const u64 replace_end = std::min(offset + size, replace_offset + replace_size);
const u64 replace_start = offset > replace_offset ? offset : replace_offset;
const u64 end = offset + size;
const u64 replace_limit = replace_offset + replace_size;
const u64 replace_end = end < replace_limit ? end : replace_limit;
if (replace_end > replace_start)
{
std::copy_n(replace_ptr + (replace_start - replace_offset), replace_end - replace_start,
out_ptr + (replace_start - offset));
std::memcpy(out_ptr + (replace_start - offset),
replace_ptr + (replace_start - replace_offset), replace_end - replace_start);
}
}
@@ -80,7 +82,9 @@ TGCFileReader::TGCFileReader(File::DirectIOFile file) : m_file(std::move(file))
Common::swap32(m_header.tgc_header_size);
const size_t claimed_fst_entries = Common::swap32(m_fst.data() + 8);
const size_t fst_entries = std::min(claimed_fst_entries, m_fst.size() / FST_ENTRY_SIZE);
const size_t stored_fst_entries = m_fst.size() / FST_ENTRY_SIZE;
const size_t fst_entries =
claimed_fst_entries < stored_fst_entries ? claimed_fst_entries : stored_fst_entries;
for (size_t i = 0; i < fst_entries; ++i)
{
// If this is a file (as opposed to a directory)...
+12 -10
View File
@@ -4,11 +4,9 @@
#include "DiscIO/Volume.h"
#include <cstring>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <type_traits>
#include <utility>
@@ -36,34 +34,38 @@ const IOS::ES::TicketReader Volume::INVALID_TICKET{};
const IOS::ES::TMDReader Volume::INVALID_TMD{};
const std::vector<u8> Volume::INVALID_CERT_CHAIN{};
std::string Volume::DecodeString(std::span<const char> data) const
std::string Volume::DecodeString(const char* data, size_t size) const
{
// strnlen to trim null bytes
std::string string(data.data(), strnlen(data.data(), data.size()));
std::string string(data, strnlen(data, size));
return GetRegion() == Region::NTSC_J ? SHIFTJISToUTF8(string) : CP1252ToUTF8(string);
}
std::string Volume::FilterGameID(std::span<const char> data)
std::string Volume::FilterGameID(const char* data, size_t size)
{
std::string string(data.data(), data.size());
std::string string(data, size);
// We don't want game IDs to contain characters that are unprintable or might cause path
// traversal. Game IDs normally only contain ASCII uppercase letters and numbers,
// but GNHE5d contains a lowercase letter, so let's allow all ASCII letters and numbers.
std::ranges::replace_if(string, std::not_fn(Common::IsAlnum), '-');
for (char& c : string)
{
if (!Common::IsAlnum(c))
c = '-';
}
return string;
}
std::map<Language, std::string> Volume::ReadWiiNames(std::span<const char16_t> data)
std::map<Language, std::string> Volume::ReadWiiNames(const char16_t* data, size_t size)
{
std::map<Language, std::string> names;
for (size_t i = 0; i < NUMBER_OF_LANGUAGES; ++i)
{
const size_t name_start = NAME_CHARS_LENGTH * i;
if (name_start + NAME_CHARS_LENGTH <= data.size())
if (name_start + NAME_CHARS_LENGTH <= size)
{
const std::string name = UTF16BEToUTF8(data.data() + name_start, NAME_CHARS_LENGTH);
const std::string name = UTF16BEToUTF8(data + name_start, NAME_CHARS_LENGTH);
if (!name.empty())
names[static_cast<Language>(i)] = name;
}
+5 -6
View File
@@ -7,7 +7,6 @@
#include <map>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <vector>
@@ -89,8 +88,8 @@ public:
}
virtual std::vector<u8> GetContent(u16 index) const { return {}; }
virtual std::vector<u64> GetContentOffsets() const { return {}; }
virtual bool CheckContentIntegrity(const IOS::ES::Content& content,
std::span<const u8> encrypted_data,
virtual bool CheckContentIntegrity(const IOS::ES::Content& content, const u8* encrypted_data,
size_t encrypted_size,
const IOS::ES::TicketReader& ticket) const
{
return false;
@@ -145,11 +144,11 @@ public:
virtual const BlobReader& GetBlobReader() const = 0;
protected:
std::string DecodeString(std::span<const char> data) const;
static std::string FilterGameID(std::span<const char> data);
std::string DecodeString(const char* data, size_t size) const;
static std::string FilterGameID(const char* data, size_t size);
virtual u32 GetOffsetShift() const { return 0; }
static std::map<Language, std::string> ReadWiiNames(std::span<const char16_t> data);
static std::map<Language, std::string> ReadWiiNames(const char16_t* data, size_t size);
static constexpr size_t NUMBER_OF_LANGUAGES = 10;
static constexpr size_t NAME_CHARS_LENGTH = 42;
+7 -7
View File
@@ -48,15 +48,15 @@ std::string VolumeDisc::GetGameID(const Partition& partition) const
}
const std::string maker_id{GetMakerID()};
memcpy(id + 4, maker_id.c_str(), std::min<std::size_t>(maker_id.size(), 2));
memcpy(id + 4, maker_id.c_str(), maker_id.size() < 2 ? maker_id.size() : 2);
return FilterGameID(id);
return FilterGameID(id, sizeof(id));
}
if (!Read(0, sizeof(id), reinterpret_cast<u8*>(id), partition))
return std::string();
return FilterGameID(id);
return FilterGameID(id, sizeof(id));
}
Country VolumeDisc::GetCountry(const Partition& partition) const
@@ -138,7 +138,7 @@ std::string VolumeDisc::GetMakerID(const Partition& partition) const
if (!Read(0x4, sizeof(maker_id), reinterpret_cast<u8*>(&maker_id), partition))
return std::string();
return FilterGameID(maker_id);
return FilterGameID(maker_id, sizeof(maker_id));
}
std::optional<u16> VolumeDisc::GetRevision(const Partition& partition) const
@@ -155,13 +155,13 @@ std::string VolumeDisc::GetInternalName(const Partition& partition) const
if (GetVolumeType() == Platform::Triforce)
{
const BootID* boot_id = static_cast<const VolumeGC*>(this)->GetTriforceBootID();
return DecodeString(boot_id->game_name);
return DecodeString(boot_id->game_name.data(), boot_id->game_name.size());
}
if (!Read(0x20, sizeof(name), reinterpret_cast<u8*>(&name), partition))
return std::string();
return DecodeString(name);
return DecodeString(name, sizeof(name));
}
std::string VolumeDisc::GetApploaderDate(const Partition& partition) const
@@ -171,7 +171,7 @@ std::string VolumeDisc::GetApploaderDate(const Partition& partition) const
if (!Read(0x2440, sizeof(date), reinterpret_cast<u8*>(&date), partition))
return std::string();
return DecodeString(date);
return DecodeString(date, sizeof(date));
}
std::optional<u8> VolumeDisc::GetDiscNumber(const Partition& partition) const
+5 -5
View File
@@ -257,23 +257,23 @@ VolumeGC::ConvertedGCBanner VolumeGC::ExtractBannerInformation(const GCBanner& b
const GCBannerInformation& info = 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, sizeof(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, sizeof(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, sizeof(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, sizeof(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, sizeof(info.long_maker));
if (!long_maker.empty())
banner.long_makers.emplace(language, long_maker);
}
+40 -17
View File
@@ -3,11 +3,9 @@
#include "DiscIO/VolumeWad.h"
#include <algorithm>
#include <map>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <utility>
#include <vector>
@@ -150,23 +148,37 @@ std::vector<u64> VolumeWAD::GetContentOffsets() const
return content_offsets;
}
bool VolumeWAD::CheckContentIntegrity(const IOS::ES::Content& content,
std::span<const u8> encrypted_data,
bool VolumeWAD::CheckContentIntegrity(const IOS::ES::Content& content, const u8* encrypted_data,
size_t encrypted_size,
const IOS::ES::TicketReader& ticket) const
{
if (encrypted_data.size() != Common::AlignUp(content.size, 0x40))
if (encrypted_size != Common::AlignUp(content.size, 0x40))
return false;
auto context = Common::AES::CreateContextDecrypt(ticket.GetTitleKey().data());
std::array<u8, 16> iv{};
u8 iv[16] = {};
iv[0] = static_cast<u8>(content.index >> 8);
iv[1] = static_cast<u8>(content.index & 0xFF);
std::vector<u8> decrypted_data(encrypted_data.size());
context->Crypt(iv.data(), encrypted_data.data(), decrypted_data.data(), decrypted_data.size());
// Decrypt and hash in chunks: in CBC the IV of each chunk is the last
// encrypted block before it, so the borrowed input is never copied whole.
std::unique_ptr<Common::SHA1::Context> sha1 = Common::SHA1::CreateContext();
u8 chunk[2048];
u64 left_to_hash = content.size;
size_t offset = 0;
while (offset < encrypted_size)
{
const size_t left = encrypted_size - offset;
const size_t n = left < sizeof(chunk) ? left : sizeof(chunk);
context->Crypt(offset ? encrypted_data + offset - 16 : iv, encrypted_data + offset, chunk, n);
const size_t hashed = left_to_hash < n ? size_t(left_to_hash) : n;
sha1->Update(chunk, hashed);
left_to_hash -= hashed;
offset += n;
}
return Common::SHA1::CalculateDigest(decrypted_data.data(), content.size) == content.sha1;
return sha1->Finish() == content.sha1;
}
IOS::ES::TicketReader VolumeWAD::GetTicketWithFixedCommonKey() const
@@ -205,14 +217,21 @@ IOS::ES::TicketReader VolumeWAD::GetTicketWithFixedCommonKey() const
offset += Common::AlignUp(content.size, 0x40);
}
std::vector<u8> content_data(Common::AlignUp(smallest_content.size, 0x40));
if (!m_reader->Read(offset_of_smallest_content, content_data.size(), content_data.data()))
const size_t content_size = size_t(Common::AlignUp(smallest_content.size, 0x40));
u8* const content_data = static_cast<u8*>(std::malloc(content_size ? content_size : 1));
if (!content_data)
return m_ticket;
if (!m_reader->Read(offset_of_smallest_content, content_size, content_data))
{
std::free(content_data);
return m_ticket;
}
const u8 specified_index = m_ticket.GetCommonKeyIndex();
if (specified_index < IOS::HLE::IOSC::COMMON_KEY_HANDLES.size() &&
CheckContentIntegrity(smallest_content, content_data, m_ticket))
CheckContentIntegrity(smallest_content, content_data, content_size, m_ticket))
{
std::free(content_data);
return m_ticket; // The common key index is already correct
}
@@ -223,10 +242,14 @@ IOS::ES::TicketReader VolumeWAD::GetTicketWithFixedCommonKey() const
if (i != specified_index)
{
new_ticket.OverwriteCommonKeyIndex(i);
if (CheckContentIntegrity(smallest_content, content_data, new_ticket))
if (CheckContentIntegrity(smallest_content, content_data, content_size, new_ticket))
{
std::free(content_data);
return new_ticket; // We've found the common key index that should be used
}
}
}
std::free(content_data);
ERROR_LOG_FMT(DISCIO, "Couldn't find valid common key for WAD file ({} specified)",
specified_index);
@@ -259,7 +282,7 @@ std::string VolumeWAD::GetMakerID(const Partition& partition) const
if (!Common::IsPrintableCharacter(temp[0]) || !Common::IsPrintableCharacter(temp[1]))
return "00";
return FilterGameID(temp);
return FilterGameID(temp, sizeof(temp));
}
std::optional<u64> VolumeWAD::GetTitleID(const Partition& partition) const
@@ -295,10 +318,10 @@ std::map<Language, std::string> VolumeWAD::GetLongNames() const
if (!m_tmd.IsValid() || !IOS::ES::IsChannel(m_tmd.GetTitleId()))
return {};
std::vector<char16_t> names(NAMES_TOTAL_CHARS);
if (!Read(m_opening_bnr_offset + 0x9C, NAMES_TOTAL_BYTES, reinterpret_cast<u8*>(names.data())))
char16_t names[NAMES_TOTAL_CHARS];
if (!Read(m_opening_bnr_offset + 0x9C, NAMES_TOTAL_BYTES, reinterpret_cast<u8*>(names)))
return std::map<Language, std::string>();
return ReadWiiNames(names);
return ReadWiiNames(names, NAMES_TOTAL_CHARS);
}
std::vector<u32> VolumeWAD::GetBanner(u32* width, u32* height) const
+2 -2
View File
@@ -6,7 +6,6 @@
#include <map>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <vector>
@@ -39,7 +38,8 @@ public:
GetCertificateChain(const Partition& partition = PARTITION_NONE) const override;
std::vector<u8> GetContent(u16 index) const override;
std::vector<u64> GetContentOffsets() const override;
bool CheckContentIntegrity(const IOS::ES::Content& content, std::span<const u8> encrypted_data,
bool CheckContentIntegrity(const IOS::ES::Content& content, const u8* encrypted_data,
size_t encrypted_size,
const IOS::ES::TicketReader& ticket) const override;
IOS::ES::TicketReader GetTicketWithFixedCommonKey() const override;
std::string GetGameID(const Partition& partition = PARTITION_NONE) const override;
+10 -10
View File
@@ -3,14 +3,12 @@
#include "DiscIO/VolumeWii.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstring>
#include <map>
#include <memory>
#include <optional>
#include <ranges>
#include <string>
#include <utility>
#include <vector>
@@ -198,7 +196,8 @@ bool VolumeWii::Read(u64 offset, u64 length, u8* buffer, const Partition& partit
// Calculate offsets
u64 block_offset_on_disc = partition_data_offset + offset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE;
u64 data_offset_in_block = offset % BLOCK_DATA_SIZE;
u64 copy_size = std::min(length, BLOCK_DATA_SIZE - data_offset_in_block);
const u64 block_left = BLOCK_DATA_SIZE - data_offset_in_block;
u64 copy_size = length < block_left ? length : block_left;
if (m_last_decrypted_block != block_offset_on_disc)
{
@@ -258,9 +257,10 @@ bool VolumeWii::HasWiiEncryption() const
std::vector<Partition> VolumeWii::GetPartitions() const
{
std::vector<Partition> partitions(m_partitions.size());
const auto partitions_view = std::views::keys(m_partitions);
std::ranges::copy(partitions_view, partitions.begin());
std::vector<Partition> partitions;
partitions.reserve(m_partitions.size());
for (const auto& partition : m_partitions)
partitions.push_back(partition.first);
return partitions;
}
@@ -342,10 +342,10 @@ Region VolumeWii::GetRegion() const
std::map<Language, std::string> VolumeWii::GetLongNames() const
{
std::vector<char16_t> names(NAMES_TOTAL_CHARS);
names.resize(ReadFile(*this, GetGamePartition(), "opening.bnr",
reinterpret_cast<u8*>(names.data()), NAMES_TOTAL_BYTES, 0x5C));
return ReadWiiNames(names);
char16_t names[NAMES_TOTAL_CHARS];
const u64 read = ReadFile(*this, GetGamePartition(), "opening.bnr",
reinterpret_cast<u8*>(names), NAMES_TOTAL_BYTES, 0x5C);
return ReadWiiNames(names, size_t(read));
}
std::vector<u32> VolumeWii::GetBanner(u32* width, u32* height) const
+24 -12
View File
@@ -3,7 +3,6 @@
#include "DiscIO/WIABlob.h"
#include <algorithm>
#include <array>
#include <cstring>
#include <expected>
@@ -98,7 +97,8 @@ bool WIARVZFileReader<RVZ>::Initialize(const std::string& path)
if (m_header_1.header_2_hash != header_2_actual_hash)
return false;
std::memcpy(&m_header_2, header_2.data(), std::min(header_2.size(), sizeof(WIAHeader2)));
std::memcpy(&m_header_2, header_2.data(),
header_2.size() < sizeof(WIAHeader2) ? header_2.size() : sizeof(WIAHeader2));
if (m_header_2.compressor_data_size > sizeof(WIAHeader2::compressor_data) ||
header_2_size < header_2_min_size + m_header_2.compressor_data_size)
@@ -135,7 +135,9 @@ bool WIARVZFileReader<RVZ>::Initialize(const std::string& path)
if (m_header_2.partition_entries_hash != partition_entries_actual_hash)
return false;
const size_t copy_length = std::min(partition_entry_size, sizeof(PartitionEntry));
const size_t copy_length = partition_entry_size < sizeof(PartitionEntry) ?
partition_entry_size :
sizeof(PartitionEntry);
const size_t memset_length = sizeof(PartitionEntry) - copy_length;
u8* ptr = partition_entries.data();
m_partition_entries.resize(number_of_partition_entries);
@@ -285,7 +287,8 @@ bool WIARVZFileReader<RVZ>::Read(u64 offset, u64 size, u8* out_ptr)
if (offset < sizeof(WIAHeader2::disc_header))
{
const u64 bytes_to_read = std::min(sizeof(WIAHeader2::disc_header) - offset, size);
const u64 header_left = sizeof(WIAHeader2::disc_header) - offset;
const u64 bytes_to_read = header_left < size ? header_left : size;
std::memcpy(out_ptr, m_header_2.disc_header.data() + offset, bytes_to_read);
offset += bytes_to_read;
size -= bytes_to_read;
@@ -334,7 +337,8 @@ bool WIARVZFileReader<RVZ>::Read(u64 offset, u64 size, u8* out_ptr)
if (offset < data_offset)
return false;
const u64 bytes_to_read = std::min(data_size - (offset - data_offset), size);
const u64 data_left = data_size - (offset - data_offset);
const u64 bytes_to_read = data_left < size ? data_left : size;
m_exception_list.clear();
m_write_to_exception_list = true;
@@ -349,7 +353,8 @@ bool WIARVZFileReader<RVZ>::Read(u64 offset, u64 size, u8* out_ptr)
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP], u64 offset_) {
// EncryptGroups calls ReadWiiDecrypted, which calls ReadFromGroups,
// which populates m_exception_list when m_write_to_exception_list == true
if (!ApplyHashExceptions(m_exception_list, hash_blocks))
if (!ApplyHashExceptions(m_exception_list.data(), m_exception_list.size(),
hash_blocks))
hash_exception_error = true;
}))
{
@@ -440,7 +445,9 @@ bool WIARVZFileReader<RVZ>::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr,
if (!ReadFromGroups(
&offset, &size, &out_ptr, chunk_size, VolumeWii::BLOCK_DATA_SIZE, data_offset,
data_size, Common::swap32(data.group_index), Common::swap32(data.number_of_groups),
std::max<u32>(1, static_cast<u32>(chunk_size / VolumeWii::GROUP_DATA_SIZE))))
chunk_size >= VolumeWii::GROUP_DATA_SIZE ?
static_cast<u32>(chunk_size / VolumeWii::GROUP_DATA_SIZE) :
1u))
{
return false;
}
@@ -476,9 +483,11 @@ bool WIARVZFileReader<RVZ>::ReadFromGroups(u64* offset, u64* size, u8** out_ptr,
const u64 group_offset_in_data = i * chunk_size;
const u64 offset_in_group = *offset - group_offset_in_data - data_offset;
chunk_size = std::min(chunk_size, data_size - group_offset_in_data);
if (data_size - group_offset_in_data < chunk_size)
chunk_size = data_size - group_offset_in_data;
const u64 bytes_to_read = std::min(chunk_size - offset_in_group, *size);
const u64 group_left = chunk_size - offset_in_group;
const u64 bytes_to_read = group_left < *size ? group_left : *size;
u32 group_data_size = Common::swap32(group.data_size);
WIARVZCompressionType compression_type = m_compression_type;
@@ -647,7 +656,9 @@ bool WIARVZFileReader<RVZ>::Chunk::Read(u64 offset, u64 size, u8* out_ptr)
m_offset_in_file;
// Ensure we don't read too much.
bytes_to_read = std::min<u64>(m_in.data.size() - m_in.bytes_written, bytes_to_read);
const u64 in_left = m_in.data.size() - m_in.bytes_written;
if (in_left < bytes_to_read)
bytes_to_read = in_left;
}
if (bytes_to_read == 0)
@@ -821,11 +832,12 @@ size_t WIARVZFileReader<RVZ>::Chunk::GetOutBytesWrittenExcludingExceptions() con
template <bool RVZ>
bool WIARVZFileReader<RVZ>::ApplyHashExceptions(
std::span<const HashExceptionEntry> exception_list,
const HashExceptionEntry* exception_list, size_t count,
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP])
{
for (const HashExceptionEntry& exception : exception_list)
for (size_t i = 0; i < count; i++)
{
const HashExceptionEntry& exception = exception_list[i];
const u16 offset = Common::swap16(exception.offset);
const size_t block_index = offset / VolumeWii::BLOCK_HEADER_SIZE;
+1 -1
View File
@@ -233,7 +233,7 @@ private:
WIARVZCompressionType compression_type, u32 exception_lists = 0,
u32 rvz_packed_size = 0, u64 data_offset = 0);
static bool ApplyHashExceptions(std::span<const HashExceptionEntry> exception_list,
static bool ApplyHashExceptions(const HashExceptionEntry* exception_list, size_t count,
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP]);
static std::string VersionToString(u32 version);
+18 -13
View File
@@ -3,7 +3,6 @@
#include "DiscIO/WIACompression.h"
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <memory>
@@ -22,6 +21,11 @@
namespace DiscIO
{
static size_t MinSize(size_t a, size_t b)
{
return a < b ? a : b;
}
static u32 LZMA2DictionarySize(u8 p)
{
return (static_cast<u32>(2) | (p & 1)) << (p / 2 + 11);
@@ -33,7 +37,7 @@ bool NoneDecompressor::Decompress(const DecompressionBuffer& in, DecompressionBu
size_t* in_bytes_read)
{
const size_t length =
std::min(in.bytes_written - *in_bytes_read, out->data.size() - out->bytes_written);
MinSize(in.bytes_written - *in_bytes_read, out->data.size() - out->bytes_written);
std::memcpy(out->data.data() + out->bytes_written, in.data.data() + *in_bytes_read, length);
@@ -66,8 +70,8 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
{
if (m_segment_bytes_written == 0 && *in_bytes_read == in.data.size() - Common::SHA1::DIGEST_LEN)
{
const size_t zeroes_to_write = std::min<size_t>(m_decompressed_size - m_out_bytes_written,
out->data.size() - out->bytes_written);
const size_t zeroes_to_write = MinSize(size_t(m_decompressed_size - m_out_bytes_written),
out->data.size() - out->bytes_written);
std::memset(out->data.data() + out->bytes_written, 0, zeroes_to_write);
@@ -94,7 +98,7 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
if (m_segment_bytes_written < sizeof(m_segment))
{
const size_t bytes_to_copy =
std::min(in.bytes_written - *in_bytes_read, sizeof(m_segment) - m_segment_bytes_written);
MinSize(in.bytes_written - *in_bytes_read, sizeof(m_segment) - m_segment_bytes_written);
std::memcpy(reinterpret_cast<u8*>(&m_segment) + m_segment_bytes_written,
in.data.data() + *in_bytes_read, bytes_to_copy);
@@ -114,7 +118,7 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
if (m_out_bytes_written < offset)
{
const size_t zeroes_to_write =
std::min(offset - m_out_bytes_written, out->data.size() - out->bytes_written);
MinSize(offset - m_out_bytes_written, out->data.size() - out->bytes_written);
std::memset(out->data.data() + out->bytes_written, 0, zeroes_to_write);
@@ -124,8 +128,8 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
if (m_out_bytes_written >= offset && m_out_bytes_written < offset + size)
{
const size_t bytes_to_copy = std::min(
std::min(offset + size - m_out_bytes_written, out->data.size() - out->bytes_written),
const size_t bytes_to_copy = MinSize(
MinSize(offset + size - m_out_bytes_written, out->data.size() - out->bytes_written),
in.bytes_written - *in_bytes_read);
std::memcpy(out->data.data() + out->bytes_written, in.data.data() + *in_bytes_read,
@@ -365,7 +369,7 @@ bool RVZPackDecompressor::Decompress(const DecompressionBuffer& in, Decompressio
m_size = size & 0x7FFFFFFF;
}
size_t bytes_to_write = std::min<size_t>(m_size, out->data.size() - out->bytes_written);
size_t bytes_to_write = MinSize(size_t(m_size), out->data.size() - out->bytes_written);
if (m_junk)
{
m_lfg.GetBytes(bytes_to_write, out->data.data() + out->bytes_written);
@@ -376,7 +380,7 @@ bool RVZPackDecompressor::Decompress(const DecompressionBuffer& in, Decompressio
if (m_decompressed.bytes_written != m_decompressed_bytes_read)
{
bytes_to_write =
std::min(bytes_to_write, m_decompressed.bytes_written - m_decompressed_bytes_read);
MinSize(bytes_to_write, m_decompressed.bytes_written - m_decompressed_bytes_read);
std::memcpy(out->data.data() + out->bytes_written,
m_decompressed.data.data() + m_decompressed_bytes_read, bytes_to_write);
@@ -464,10 +468,11 @@ bool PurgeCompressor::Compress(const u8* data, size_t size)
while (true)
{
const auto first_non_zero =
std::find_if(data + bytes_read, data + size, [](u8 x) { return x != 0; });
size_t first_non_zero = bytes_read;
while (first_non_zero < size && data[first_non_zero] == 0)
first_non_zero++;
const u32 non_zero_data_start = static_cast<u32>(first_non_zero - data);
const u32 non_zero_data_start = static_cast<u32>(first_non_zero);
if (non_zero_data_start == size)
break;
+4 -3
View File
@@ -3,7 +3,6 @@
#include "DiscIO/WbfsBlob.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <memory>
@@ -130,7 +129,8 @@ bool WbfsFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
auto& data_file = SeekToCluster(offset, &read_size);
if (read_size == 0)
return false;
read_size = std::min(read_size, nbytes);
if (nbytes < read_size)
read_size = nbytes;
if (!data_file.Read(out_ptr, read_size))
{
@@ -163,7 +163,8 @@ File::DirectIOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available)
{
u64 till_end_of_file = file_entry.size - (final_address - file_entry.base_address);
u64 till_end_of_sector = m_wbfs_sector_size - cluster_offset;
*available = std::min(till_end_of_file, till_end_of_sector);
*available =
till_end_of_file < till_end_of_sector ? till_end_of_file : till_end_of_sector;
}
return file_entry.file;
+2 -1
View File
@@ -79,7 +79,8 @@ bool WiiEncryptionCache::EncryptGroups(u64 offset, u64 size, u8* out_ptr, u64 pa
return false;
const u64 offset_in_group = offset % VolumeWii::GROUP_TOTAL_SIZE;
const u64 bytes_to_read = std::min(VolumeWii::GROUP_TOTAL_SIZE - offset_in_group, size);
const u64 group_left = VolumeWii::GROUP_TOTAL_SIZE - offset_in_group;
const u64 bytes_to_read = group_left < size ? group_left : size;
std::memcpy(out_ptr, group->data() + offset_in_group, bytes_to_read);
offset += bytes_to_read;