From d6260e02ce5561a614fc051c7340fe6c803399cd Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 17:45:46 +0200 Subject: [PATCH 1/8] DirectoryBlob: Replace std::set with a new class --- Source/Core/DiscIO/DirectoryBlob.cpp | 144 ++++++++++++++------------- Source/Core/DiscIO/DirectoryBlob.h | 27 ++++- 2 files changed, 95 insertions(+), 76 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 364405aa01..e017bfca78 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -33,10 +32,6 @@ namespace DiscIO { -static const DiscContent& AddFileToContents(std::set* contents, - const std::string& path, u64 offset, - u64 max_size = UINT64_MAX); - // Reads as many bytes as the vector fits (or less, if the file is smaller). // Returns the number of bytes read. static size_t ReadFileToVector(const std::string& path, std::vector* vector); @@ -120,6 +115,58 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const return true; } +const DiscContent& DiscContentContainer::Add(u64 offset, u64 size, const std::string& path) +{ + return *(m_contents.emplace(offset, size, path).first); +} + +const DiscContent& DiscContentContainer::Add(u64 offset, u64 size, const u8* data) +{ + return *(m_contents.emplace(offset, size, data).first); +} + +const DiscContent& DiscContentContainer::CheckSizeAndAdd(u64 offset, const std::string& path) +{ + return Add(offset, File::GetSize(path), path); +} + +const DiscContent& DiscContentContainer::CheckSizeAndAdd(u64 offset, u64 max_size, + const std::string& path) +{ + return Add(offset, std::min(File::GetSize(path), max_size), path); +} + +bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const +{ + if (m_contents.empty()) + return true; + + // Determine which DiscContent the offset refers to + std::set::const_iterator it = m_contents.lower_bound(DiscContent(offset)); + if (it->GetOffset() > offset && it != m_contents.begin()) + --it; + + // zero fill to start of file data + PadToAddress(it->GetOffset(), &offset, &length, &buffer); + + while (it != m_contents.end() && length > 0) + { + _dbg_assert_(DISCIO, it->GetOffset() <= offset); + if (!it->Read(&offset, &length, &buffer)) + return false; + + ++it; + + if (it != m_contents.end()) + { + _dbg_assert_(DISCIO, it->GetOffset() >= offset); + PadToAddress(it->GetOffset(), &offset, &length, &buffer); + } + } + + return true; +} + static std::optional ParsePartitionDirectoryName(const std::string& name) { if (name.size() < 2) @@ -322,45 +369,11 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, } } -bool DirectoryBlobReader::ReadInternal(u64 offset, u64 length, u8* buffer, - const std::set& contents) -{ - if (contents.empty()) - return true; - - // Determine which DiscContent the offset refers to - std::set::const_iterator it = contents.lower_bound(DiscContent(offset)); - if (it->GetOffset() > offset && it != contents.begin()) - --it; - - // zero fill to start of file data - PadToAddress(it->GetOffset(), &offset, &length, &buffer); - - while (it != contents.end() && length > 0) - { - _dbg_assert_(DISCIO, it->GetOffset() <= offset); - if (!it->Read(&offset, &length, &buffer)) - return false; - - ++it; - - if (it != contents.end()) - { - _dbg_assert_(DISCIO, it->GetOffset() >= offset); - PadToAddress(it->GetOffset(), &offset, &length, &buffer); - } - } - - return true; -} - bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer) { // TODO: We don't handle raw access to the encrypted area of Wii discs correctly. - - const std::set& contents = - m_is_wii ? m_nonpartition_contents : m_gamecube_pseudopartition.GetContents(); - return ReadInternal(offset, length, buffer, contents); + return (m_is_wii ? m_nonpartition_contents : m_gamecube_pseudopartition.GetContents()) + .Read(offset, length, buffer); } bool DirectoryBlobReader::SupportsReadWiiDecrypted() const @@ -377,7 +390,7 @@ bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 if (it == m_partitions.end()) return false; - return ReadInternal(offset, size, buffer, it->second.GetContents()); + return it->second.GetContents().Read(offset, size, buffer); } BlobType DirectoryBlobReader::GetBlobType() const @@ -417,8 +430,7 @@ void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& parti if (header_bin_bytes_read < 0x61) m_disc_header_nonpartition[0x61] = 0; - m_nonpartition_contents.emplace(NONPARTITION_DISCHEADER_ADDRESS, NONPARTITION_DISCHEADER_SIZE, - m_disc_header_nonpartition.data()); + m_nonpartition_contents.Add(NONPARTITION_DISCHEADER_ADDRESS, m_disc_header_nonpartition); } void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_root) @@ -436,8 +448,7 @@ void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_roo constexpr u64 WII_REGION_DATA_ADDRESS = 0x4E000; constexpr u64 WII_REGION_DATA_SIZE = 0x20; - m_nonpartition_contents.emplace(WII_REGION_DATA_ADDRESS, WII_REGION_DATA_SIZE, - m_wii_region_data.data()); + m_nonpartition_contents.Add(WII_REGION_DATA_ADDRESS, m_wii_region_data); } void DirectoryBlobReader::SetPartitions(std::vector&& partitions) @@ -501,8 +512,7 @@ void DirectoryBlobReader::SetPartitions(std::vector&& partiti } m_data_size = partition_address; - m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, m_partition_table.size(), - m_partition_table.data()); + m_nonpartition_contents.Add(PARTITION_TABLE_ADDRESS, m_partition_table); } // This function sets the header that's shortly before the start of the encrypted @@ -519,19 +529,19 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti const std::string& partition_root = partition.GetRootDirectory(); - AddFileToContents(&m_nonpartition_contents, partition_root + "ticket.bin", - partition_address + TICKET_OFFSET, TICKET_SIZE); + m_nonpartition_contents.CheckSizeAndAdd(partition_address + TICKET_OFFSET, TICKET_SIZE, + partition_root + "ticket.bin"); - const DiscContent& tmd = AddFileToContents(&m_nonpartition_contents, partition_root + "tmd.bin", - partition_address + TMD_OFFSET, MAX_TMD_SIZE); + const DiscContent& tmd = m_nonpartition_contents.CheckSizeAndAdd( + partition_address + TMD_OFFSET, MAX_TMD_SIZE, partition_root + "tmd.bin"); const u64 cert_offset = Common::AlignUp(TMD_OFFSET + tmd.GetSize(), 0x20ull); const u64 max_cert_size = H3_OFFSET - cert_offset; - const DiscContent& cert = AddFileToContents(&m_nonpartition_contents, partition_root + "cert.bin", - partition_address + cert_offset, max_cert_size); + const DiscContent& cert = m_nonpartition_contents.CheckSizeAndAdd( + partition_address + cert_offset, max_cert_size, partition_root + "cert.bin"); - AddFileToContents(&m_nonpartition_contents, partition_root + "h3.bin", - partition_address + H3_OFFSET, H3_SIZE); + m_nonpartition_contents.CheckSizeAndAdd(partition_address + H3_OFFSET, H3_SIZE, + partition_root + "h3.bin"); constexpr u32 PARTITION_HEADER_SIZE = 0x1c; constexpr u32 DATA_OFFSET = 0x20000; @@ -546,8 +556,7 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti Write32(DATA_OFFSET >> 2, 0x14, &partition_header); Write32(static_cast(data_size >> 2), 0x18, &partition_header); - m_nonpartition_contents.emplace(partition_address + TICKET_SIZE, PARTITION_HEADER_SIZE, - partition_header.data()); + m_nonpartition_contents.Add(partition_address + TICKET_SIZE, partition_header); } DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory, @@ -569,7 +578,7 @@ void DirectoryBlobPartition::SetDiscHeaderAndDiscType(std::optional is_wii if (ReadFileToVector(boot_bin_path, &m_disc_header) < 0x20) ERROR_LOG(DISCIO, "%s doesn't exist or is too small", boot_bin_path.c_str()); - m_contents.emplace(DISCHEADER_ADDRESS, DISCHEADER_SIZE, m_disc_header.data()); + m_contents.Add(DISCHEADER_ADDRESS, m_disc_header); if (is_wii.has_value()) { @@ -600,7 +609,7 @@ void DirectoryBlobPartition::SetBI2() if (!m_is_wii && bytes_read < 0x1C) ERROR_LOG(DISCIO, "Couldn't read region from %s", bi2_path.c_str()); - m_contents.emplace(BI2_ADDRESS, BI2_SIZE, m_bi2.data()); + m_contents.Add(BI2_ADDRESS, m_bi2); } u64 DirectoryBlobPartition::SetApploader() @@ -633,7 +642,7 @@ u64 DirectoryBlobPartition::SetApploader() constexpr u64 APPLOADER_ADDRESS = 0x2440; - m_contents.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); + m_contents.Add(APPLOADER_ADDRESS, m_apploader); // Return DOL address, 32 byte aligned (plus 32 byte padding) return Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); @@ -642,7 +651,7 @@ u64 DirectoryBlobPartition::SetApploader() u64 DirectoryBlobPartition::SetDOL(u64 dol_address) { const DiscContent& dol = - AddFileToContents(&m_contents, m_root_directory + "sys/main.dol", dol_address); + m_contents.CheckSizeAndAdd(dol_address, m_root_directory + "sys/main.dol"); Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disc_header); @@ -685,7 +694,7 @@ void DirectoryBlobPartition::BuildFST(u64 fst_address) Write32((u32)(m_fst_data.size() >> m_address_shift), 0x0428, &m_disc_header); Write32((u32)(m_fst_data.size() >> m_address_shift), 0x042c, &m_disc_header); - m_contents.emplace(fst_address, m_fst_data.size(), m_fst_data.data()); + m_contents.Add(fst_address, m_fst_data); m_data_size = current_data_address; } @@ -747,8 +756,7 @@ void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry, WriteEntryName(name_offset, entry.virtualName, name_table_offset); // write entry to virtual disc - auto result = m_contents.emplace(*data_offset, entry.size, entry.physicalName); - _dbg_assert_(DISCIO, result.second); // Check that this offset wasn't already occupied + auto result = m_contents.Add(*data_offset, entry.size, entry.physicalName); // 32 KiB aligned - many games are fine with less alignment, but not all *data_offset = Common::AlignUp(*data_offset + std::max(entry.size, 1ull), 0x8000ull); @@ -756,12 +764,6 @@ void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry, } } -static const DiscContent& AddFileToContents(std::set* contents, - const std::string& path, u64 offset, u64 max_size) -{ - return *(contents->emplace(offset, std::min(File::GetSize(path), max_size), path).first); -} - static size_t ReadFileToVector(const std::string& path, std::vector* vector) { File::IOFile file(path, "rb"); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 666694e508..86787bbd44 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -58,6 +58,25 @@ private: ContentSource m_content_source; }; +class DiscContentContainer +{ +public: + template + const DiscContent& Add(u64 offset, const std::vector& vector) + { + return Add(offset, vector.size() * sizeof(T), reinterpret_cast(vector.data())); + } + const DiscContent& Add(u64 offset, u64 size, const std::string& path); + const DiscContent& Add(u64 offset, u64 size, const u8* data); + const DiscContent& CheckSizeAndAdd(u64 offset, const std::string& path); + const DiscContent& CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path); + + bool Read(u64 offset, u64 length, u8* buffer) const; + +private: + std::set m_contents; +}; + class DirectoryBlobPartition { public: @@ -74,7 +93,7 @@ public: u64 GetDataSize() const { return m_data_size; } const std::string& GetRootDirectory() const { return m_root_directory; } const std::vector& GetHeader() const { return m_disc_header; } - const std::set& GetContents() const { return m_contents; } + const DiscContentContainer& GetContents() const { return m_contents; } private: void SetDiscHeaderAndDiscType(std::optional is_wii); void SetBI2(); @@ -93,7 +112,7 @@ private: void WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, u32* name_offset, u64* data_offset, u32 parent_entry_index, u64 name_table_offset); - std::set m_contents; + DiscContentContainer m_contents; std::vector m_disc_header; std::vector m_bi2; std::vector m_apploader; @@ -141,8 +160,6 @@ private: explicit DirectoryBlobReader(const std::string& game_partition_root, const std::string& true_root); - bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); - void SetNonpartitionDiscHeader(const std::vector& partition_header, const std::string& game_partition_root); void SetWiiRegionData(const std::string& game_partition_root); @@ -153,7 +170,7 @@ private: DirectoryBlobPartition m_gamecube_pseudopartition; // For Wii: - std::set m_nonpartition_contents; + DiscContentContainer m_nonpartition_contents; std::map m_partitions; bool m_is_wii; From 1b1a75ee3ad52db3fca36158dca318376ebd0bb0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 19:04:33 +0200 Subject: [PATCH 2/8] DirectoryBlob: Lookup DiscContents by offset + size instead of offset This simplifies DiscContentContainer::Read. --- Source/Core/DiscIO/DirectoryBlob.cpp | 12 ++++++------ Source/Core/DiscIO/DirectoryBlob.h | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index e017bfca78..320d3ed054 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -77,6 +77,11 @@ u64 DiscContent::GetOffset() const return m_offset; } +u64 DiscContent::GetEndOffset() const +{ + return m_offset + m_size; +} + u64 DiscContent::GetSize() const { return m_size; @@ -138,13 +143,8 @@ const DiscContent& DiscContentContainer::CheckSizeAndAdd(u64 offset, u64 max_siz bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const { - if (m_contents.empty()) - return true; - // Determine which DiscContent the offset refers to - std::set::const_iterator it = m_contents.lower_bound(DiscContent(offset)); - if (it->GetOffset() > offset && it != m_contents.begin()) - --it; + std::set::const_iterator it = m_contents.upper_bound(DiscContent(offset)); // zero fill to start of file data PadToAddress(it->GetOffset(), &offset, &length, &buffer); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 86787bbd44..4c9646ac8f 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -42,12 +42,13 @@ public: explicit DiscContent(u64 offset); u64 GetOffset() const; + u64 GetEndOffset() const; u64 GetSize() const; bool Read(u64* offset, u64* length, u8** buffer) const; - bool operator==(const DiscContent& other) const { return m_offset == other.m_offset; } + bool operator==(const DiscContent& other) const { return GetEndOffset() == other.GetEndOffset(); } bool operator!=(const DiscContent& other) const { return !(*this == other); } - bool operator<(const DiscContent& other) const { return m_offset < other.m_offset; } + bool operator<(const DiscContent& other) const { return GetEndOffset() < other.GetEndOffset(); } bool operator>(const DiscContent& other) const { return other < *this; } bool operator<=(const DiscContent& other) const { return !(*this < other); } bool operator>=(const DiscContent& other) const { return !(*this > other); } From 78fa98f5593ec61a505a56d89984e41885715313 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 19:13:19 +0200 Subject: [PATCH 3/8] DirectoryBlob: Change the return type of Add/CheckSizeAndAdd Only return the information that isn't already known to the caller. --- Source/Core/DiscIO/DirectoryBlob.cpp | 38 +++++++++++++++------------- Source/Core/DiscIO/DirectoryBlob.h | 10 ++++---- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 320d3ed054..bca7c66a9b 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -120,25 +120,28 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const return true; } -const DiscContent& DiscContentContainer::Add(u64 offset, u64 size, const std::string& path) +void DiscContentContainer::Add(u64 offset, u64 size, const std::string& path) { - return *(m_contents.emplace(offset, size, path).first); + m_contents.emplace(offset, size, path); } -const DiscContent& DiscContentContainer::Add(u64 offset, u64 size, const u8* data) +void DiscContentContainer::Add(u64 offset, u64 size, const u8* data) { - return *(m_contents.emplace(offset, size, data).first); + m_contents.emplace(offset, size, data); } -const DiscContent& DiscContentContainer::CheckSizeAndAdd(u64 offset, const std::string& path) +u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, const std::string& path) { - return Add(offset, File::GetSize(path), path); + const u64 size = File::GetSize(path); + Add(offset, size, path); + return size; } -const DiscContent& DiscContentContainer::CheckSizeAndAdd(u64 offset, u64 max_size, - const std::string& path) +u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path) { - return Add(offset, std::min(File::GetSize(path), max_size), path); + const u64 size = std::min(File::GetSize(path), max_size); + Add(offset, size, path); + return size; } bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const @@ -532,12 +535,12 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti m_nonpartition_contents.CheckSizeAndAdd(partition_address + TICKET_OFFSET, TICKET_SIZE, partition_root + "ticket.bin"); - const DiscContent& tmd = m_nonpartition_contents.CheckSizeAndAdd( + const u64 tmd_size = m_nonpartition_contents.CheckSizeAndAdd( partition_address + TMD_OFFSET, MAX_TMD_SIZE, partition_root + "tmd.bin"); - const u64 cert_offset = Common::AlignUp(TMD_OFFSET + tmd.GetSize(), 0x20ull); + const u64 cert_offset = Common::AlignUp(TMD_OFFSET + tmd_size, 0x20ull); const u64 max_cert_size = H3_OFFSET - cert_offset; - const DiscContent& cert = m_nonpartition_contents.CheckSizeAndAdd( + const u64 cert_size = m_nonpartition_contents.CheckSizeAndAdd( partition_address + cert_offset, max_cert_size, partition_root + "cert.bin"); m_nonpartition_contents.CheckSizeAndAdd(partition_address + H3_OFFSET, H3_SIZE, @@ -548,9 +551,9 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti const u64 data_size = Common::AlignUp(partition.GetDataSize(), 0x7c00) / 0x7c00 * 0x8000; m_partition_headers.emplace_back(PARTITION_HEADER_SIZE); std::vector& partition_header = m_partition_headers.back(); - Write32(static_cast(tmd.GetSize()), 0x0, &partition_header); + Write32(static_cast(tmd_size), 0x0, &partition_header); Write32(TMD_OFFSET >> 2, 0x4, &partition_header); - Write32(static_cast(cert.GetSize()), 0x8, &partition_header); + Write32(static_cast(cert_size), 0x8, &partition_header); Write32(static_cast(cert_offset >> 2), 0x0C, &partition_header); Write32(H3_OFFSET >> 2, 0x10, &partition_header); Write32(DATA_OFFSET >> 2, 0x14, &partition_header); @@ -650,13 +653,12 @@ u64 DirectoryBlobPartition::SetApploader() u64 DirectoryBlobPartition::SetDOL(u64 dol_address) { - const DiscContent& dol = - m_contents.CheckSizeAndAdd(dol_address, m_root_directory + "sys/main.dol"); + const u64 dol_size = m_contents.CheckSizeAndAdd(dol_address, m_root_directory + "sys/main.dol"); Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disc_header); // Return FST address, 32 byte aligned (plus 32 byte padding) - return Common::AlignUp(dol_address + dol.GetSize() + 0x20, 0x20ull); + return Common::AlignUp(dol_address + dol_size + 0x20, 0x20ull); } void DirectoryBlobPartition::BuildFST(u64 fst_address) @@ -756,7 +758,7 @@ void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry, WriteEntryName(name_offset, entry.virtualName, name_table_offset); // write entry to virtual disc - auto result = m_contents.Add(*data_offset, entry.size, entry.physicalName); + m_contents.Add(*data_offset, entry.size, entry.physicalName); // 32 KiB aligned - many games are fine with less alignment, but not all *data_offset = Common::AlignUp(*data_offset + std::max(entry.size, 1ull), 0x8000ull); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 4c9646ac8f..69a3044771 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -63,14 +63,14 @@ class DiscContentContainer { public: template - const DiscContent& Add(u64 offset, const std::vector& vector) + void Add(u64 offset, const std::vector& vector) { return Add(offset, vector.size() * sizeof(T), reinterpret_cast(vector.data())); } - const DiscContent& Add(u64 offset, u64 size, const std::string& path); - const DiscContent& Add(u64 offset, u64 size, const u8* data); - const DiscContent& CheckSizeAndAdd(u64 offset, const std::string& path); - const DiscContent& CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path); + void Add(u64 offset, u64 size, const std::string& path); + void Add(u64 offset, u64 size, const u8* data); + u64 CheckSizeAndAdd(u64 offset, const std::string& path); + u64 CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path); bool Read(u64 offset, u64 length, u8* buffer) const; From 6b0a60d2ee24f3a7dde6eb97f22623696807651e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 19:21:38 +0200 Subject: [PATCH 4/8] DirectoryBlob: Don't add DiscContents with size 0 Having DiscContents with size 0 would mean that some DiscContents might not get added to the std::set because of them comparing identically to another DiscContent. This replaces an older piece of code in WriteDirectory that ensures that no two files have the same starting offset. (We now care about the ending offset, not the starting offset. The new solution both ensures that no two files have the same ending offset and that no two files have the same starting offset.) --- Source/Core/DiscIO/DirectoryBlob.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index bca7c66a9b..dfdc87ffb0 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -122,12 +122,14 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const void DiscContentContainer::Add(u64 offset, u64 size, const std::string& path) { - m_contents.emplace(offset, size, path); + if (size != 0) + m_contents.emplace(offset, size, path); } void DiscContentContainer::Add(u64 offset, u64 size, const u8* data) { - m_contents.emplace(offset, size, data); + if (size != 0) + m_contents.emplace(offset, size, data); } u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, const std::string& path) @@ -761,7 +763,7 @@ void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry, m_contents.Add(*data_offset, entry.size, entry.physicalName); // 32 KiB aligned - many games are fine with less alignment, but not all - *data_offset = Common::AlignUp(*data_offset + std::max(entry.size, 1ull), 0x8000ull); + *data_offset = Common::AlignUp(*data_offset + entry.size, 0x8000ull); } } } From 74ada98e84487a8173a2d9f53f9f66d1111086fc Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 19:35:01 +0200 Subject: [PATCH 5/8] DirectoryBlob: Remove redundant assert DiscContent::Read contains an equivalent assertion. --- Source/Core/DiscIO/DirectoryBlob.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index dfdc87ffb0..d4dc3c872b 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -156,7 +156,6 @@ bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const while (it != m_contents.end() && length > 0) { - _dbg_assert_(DISCIO, it->GetOffset() <= offset); if (!it->Read(&offset, &length, &buffer)) return false; From b155c46aca55b18053bc9a8a83893b87d0dcb1fb Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 19:33:49 +0200 Subject: [PATCH 6/8] DirectoryBlob: Fix reading beyond the end of the disc There were two problems with this: 1. If the starting offset was beyond the end of the disc, we would dereference an invalid iterator. 2. The data beyond the end of the disc was non-deterministic. --- Source/Core/DiscIO/DirectoryBlob.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index d4dc3c872b..696877b528 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -151,23 +151,21 @@ bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const // Determine which DiscContent the offset refers to std::set::const_iterator it = m_contents.upper_bound(DiscContent(offset)); - // zero fill to start of file data - PadToAddress(it->GetOffset(), &offset, &length, &buffer); - while (it != m_contents.end() && length > 0) { + // Zero fill to start of DiscContent data + PadToAddress(it->GetOffset(), &offset, &length, &buffer); + if (!it->Read(&offset, &length, &buffer)) return false; ++it; - - if (it != m_contents.end()) - { - _dbg_assert_(DISCIO, it->GetOffset() >= offset); - PadToAddress(it->GetOffset(), &offset, &length, &buffer); - } + _dbg_assert_(DISCIO, it == m_contents.end() || it->GetOffset() >= offset); } + // Zero fill if we went beyond the last DiscContent + std::fill_n(buffer, static_cast(length), 0); + return true; } From f7032f8debafcb1f7fe4ad87df9b0b89d28c02a3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 19:57:06 +0200 Subject: [PATCH 7/8] FileSystemGCWii: Don't add 0-size files to m_offset_file_info_cache This is done in order to reduce the risk of files not being added due to them having the same end offset as another file. --- Source/Core/DiscIO/FileSystemGCWii.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index 9a7e24c288..4e2132654b 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -308,7 +308,11 @@ std::unique_ptr FileSystemGCWii::FindFileInfo(u64 disc_offset) const { FileInfoGCWii file_info(m_root, i); if (!file_info.IsDirectory()) - m_offset_file_info_cache.emplace(file_info.GetOffset() + file_info.GetSize(), i); + { + const u32 size = file_info.GetSize(); + if (size != 0) + m_offset_file_info_cache.emplace(file_info.GetOffset() + size, i); + } } } From 2bcccd893ab2f24baf0a91b92cb8811d53288be4 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 1 Aug 2017 22:01:34 +0200 Subject: [PATCH 8/8] DirectoryBlob: Remove unused DiscContent member --- Source/Core/DiscIO/DirectoryBlob.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 69a3044771..70ff61c91b 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -55,7 +55,6 @@ public: private: u64 m_offset; u64 m_size = 0; - std::string m_path; ContentSource m_content_source; };