From e1321b131d9e3386a4be17592363d72b13a15f66 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 16:07:01 +0200 Subject: [PATCH] DirectoryBlob: Create a DiscContent class for use in m_virtual_disc --- Source/Core/DiscIO/DirectoryBlob.cpp | 98 +++++++++++++++++----------- Source/Core/DiscIO/DirectoryBlob.h | 29 +++++++- 2 files changed, 88 insertions(+), 39 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index dc262c6509..a974e882d6 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -49,6 +49,50 @@ const std::array PARTITION_TABLE = { {Common::swap32(1), Common::swap32((PARTITION_TABLE_ADDRESS + 0x20) >> 2), 0, 0, 0, 0, 0, 0, Common::swap32(GAME_PARTITION_ADDRESS >> 2), 0}}; +DiscContent::DiscContent(u64 offset, u64 size, const std::string& path) + : m_offset(offset), m_size(size), m_path(path) +{ +} + +DiscContent::DiscContent(u64 offset) : m_offset(offset) +{ +} + +u64 DiscContent::GetOffset() const +{ + return m_offset; +} + +u64 DiscContent::GetSize() const +{ + return m_size; +} + +bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const +{ + if (m_size == 0) + return true; + + _dbg_assert_(DISCIO, *offset >= m_offset); + const u64 offset_in_content = *offset - m_offset; + + if (offset_in_content < m_size) + { + const u64 bytes_to_read = std::min(m_size - offset_in_content, *length); + + File::IOFile file(m_path, "rb"); + file.Seek(offset_in_content, SEEK_SET); + if (!file.ReadBytes(*buffer, bytes_to_read)) + return false; + + *length -= bytes_to_read; + *buffer += bytes_to_read; + *offset += bytes_to_read; + } + + return true; +} + static bool PathCharactersEqual(char a, char b) { return a == b @@ -140,49 +184,29 @@ bool DirectoryBlobReader::ReadPartition(u64 offset, u64 length, u8* buffer) WriteToBuffer(m_fst_address, m_fst_data.size(), m_fst_data.data(), &offset, &length, &buffer); } - if (m_virtual_disk.empty()) + if (m_virtual_disc.empty()) return true; - // Determine which file the offset refers to - std::map::const_iterator fileIter = m_virtual_disk.lower_bound(offset); - if (fileIter->first > offset && fileIter != m_virtual_disk.begin()) - --fileIter; + // Determine which DiscContent the offset refers to + std::set::const_iterator it = m_virtual_disc.lower_bound(DiscContent(offset)); + if (it->GetOffset() > offset && it != m_virtual_disc.begin()) + --it; // zero fill to start of file data - PadToAddress(fileIter->first, &offset, &length, &buffer); + PadToAddress(it->GetOffset(), &offset, &length, &buffer); - while (fileIter != m_virtual_disk.end() && length > 0) + while (it != m_virtual_disc.end() && length > 0) { - _dbg_assert_(DVDINTERFACE, fileIter->first <= offset); - u64 fileOffset = offset - fileIter->first; - const std::string fileName = fileIter->second; - - File::IOFile file(fileName, "rb"); - if (!file) + _dbg_assert_(DVDINTERFACE, it->GetOffset() <= offset); + if (!it->Read(&offset, &length, &buffer)) return false; - u64 fileSize = file.GetSize(); + ++it; - if (fileOffset < fileSize) + if (it != m_virtual_disc.end()) { - u64 fileBytes = std::min(fileSize - fileOffset, length); - - if (!file.Seek(fileOffset, SEEK_SET)) - return false; - if (!file.ReadBytes(buffer, fileBytes)) - return false; - - length -= fileBytes; - buffer += fileBytes; - offset += fileBytes; - } - - ++fileIter; - - if (fileIter != m_virtual_disk.end()) - { - _dbg_assert_(DVDINTERFACE, fileIter->first >= offset); - PadToAddress(fileIter->first, &offset, &length, &buffer); + _dbg_assert_(DVDINTERFACE, it->GetOffset() >= offset); + PadToAddress(it->GetOffset(), &offset, &length, &buffer); } } @@ -468,9 +492,9 @@ void DirectoryBlobReader::WriteDirectory(const File::FSTEntry& parent_entry, u32 m_address_shift); WriteEntryName(name_offset, entry.virtualName); - // write entry to virtual disk - _dbg_assert_(DVDINTERFACE, m_virtual_disk.find(*data_offset) == m_virtual_disk.end()); - m_virtual_disk.emplace(*data_offset, entry.physicalName); + // write entry to virtual disc + auto result = m_virtual_disc.emplace(*data_offset, entry.size, entry.physicalName); + _dbg_assert_(DISCIO, result.second); // Check that this offset wasn't already occupied // 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 ec19229c8a..3e4683b906 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -4,9 +4,10 @@ #pragma once -#include +#include #include #include +#include #include #include @@ -22,6 +23,30 @@ class IOFile; namespace DiscIO { +class DiscContent +{ +public: + DiscContent(u64 offset, u64 size, const std::string& path); + + // Provided because it's convenient when searching for DiscContent in an std::set + explicit DiscContent(u64 offset); + + u64 GetOffset() 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 !(*this == other); } + bool operator<(const DiscContent& other) const { return m_offset < other.m_offset; } + 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); } +private: + u64 m_offset; + u64 m_size = 0; + std::string m_path; +}; + class DirectoryBlobReader : public BlobReader { public: @@ -70,7 +95,7 @@ private: std::string m_root_directory; - std::map m_virtual_disk; + std::set m_virtual_disc; bool m_is_wii = false;