From ba0ee3f54b50cebc60a5303c0c3b591844f03838 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 15:54:26 +0200 Subject: [PATCH] DirectoryBlob: Prepare for supporting multiple partitions --- Source/Core/DiscIO/DirectoryBlob.cpp | 105 +++++++++++++++------------ Source/Core/DiscIO/DirectoryBlob.h | 70 +++++++++++------- 2 files changed, 102 insertions(+), 73 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 3a5abeacd7..dd9cdb83a2 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -156,14 +156,13 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri } DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) - : m_root_directory(root_directory) + : m_root_directory(root_directory), m_game_partition(root_directory) { - SetDiscHeaderAndDiscType(); - SetBI2(); - BuildFST(SetDOL(SetApploader())); + m_is_wii = m_game_partition.IsWii(); if (m_is_wii) { + SetNonpartitionDiscHeader(m_game_partition.GetHeader()); SetPartitionTable(); SetWiiRegionData(); SetTMDAndTicket(); @@ -206,7 +205,8 @@ bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer) { // TODO: We don't handle raw access to the encrypted area of Wii discs correctly. - return ReadInternal(offset, length, buffer, m_is_wii ? m_nonpartition_contents : m_virtual_disc); + return ReadInternal(offset, length, buffer, + m_is_wii ? m_nonpartition_contents : m_game_partition.GetContents()); } bool DirectoryBlobReader::SupportsReadWiiDecrypted() const @@ -219,7 +219,7 @@ bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 if (!m_is_wii || partition_offset != GAME_PARTITION_ADDRESS) return false; - return ReadInternal(offset, size, buffer, m_virtual_disc); + return ReadInternal(offset, size, buffer, m_game_partition.GetContents()); } BlobType DirectoryBlobReader::GetBlobType() const @@ -239,18 +239,25 @@ u64 DirectoryBlobReader::GetDataSize() const return 0; } -void DirectoryBlobReader::SetDiscHeaderAndDiscType() +DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory) + : m_root_directory(root_directory) +{ + SetDiscHeaderAndDiscType(); + SetBI2(); + BuildFST(SetDOL(SetApploader())); +} + +void DirectoryBlobPartition::SetDiscHeaderAndDiscType() { constexpr u64 DISKHEADER_ADDRESS = 0; constexpr u64 DISKHEADER_SIZE = 0x440; - constexpr u64 NONPARTITION_DISKHEADER_SIZE = 0x100; m_disk_header.resize(DISKHEADER_SIZE); const std::string boot_bin_path = m_root_directory + "sys/boot.bin"; if (ReadFileToVector(boot_bin_path, &m_disk_header) < 0x20) ERROR_LOG(DISCIO, "%s doesn't exist or is too small", boot_bin_path.c_str()); - m_virtual_disc.emplace(DISKHEADER_ADDRESS, DISKHEADER_SIZE, m_disk_header.data()); + m_contents.emplace(DISKHEADER_ADDRESS, DISKHEADER_SIZE, m_disk_header.data()); m_is_wii = Common::swap32(&m_disk_header[0x18]) == 0x5d1c9ea3; const bool is_gc = Common::swap32(&m_disk_header[0x1c]) == 0xc2339f3d; @@ -258,34 +265,37 @@ void DirectoryBlobReader::SetDiscHeaderAndDiscType() ERROR_LOG(DISCIO, "Couldn't detect disc type based on %s", boot_bin_path.c_str()); m_address_shift = m_is_wii ? 2 : 0; - - if (m_is_wii) - { - m_disk_header_nonpartition.resize(NONPARTITION_DISKHEADER_SIZE); - const size_t header_bin_bytes_read = - ReadFileToVector(m_root_directory + "disc/header.bin", &m_disk_header_nonpartition); - - // If header.bin is missing or smaller than expected, use the content of sys/boot.bin instead - std::copy(m_disk_header.data() + header_bin_bytes_read, - m_disk_header.data() + m_disk_header_nonpartition.size(), - m_disk_header_nonpartition.data() + header_bin_bytes_read); - - // 0x60 and 0x61 are the only differences between the partition and non-partition headers - if (header_bin_bytes_read < 0x60) - m_disk_header_nonpartition[0x60] = 0; - if (header_bin_bytes_read < 0x61) - m_disk_header_nonpartition[0x61] = 0; - - m_nonpartition_contents.emplace(DISKHEADER_ADDRESS, NONPARTITION_DISKHEADER_SIZE, - m_disk_header_nonpartition.data()); - } } -void DirectoryBlobReader::SetBI2() +void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& partition_header) +{ + constexpr u64 NONPARTITION_DISKHEADER_ADDRESS = 0; + constexpr u64 NONPARTITION_DISKHEADER_SIZE = 0x100; + + m_disk_header_nonpartition.resize(NONPARTITION_DISKHEADER_SIZE); + const size_t header_bin_bytes_read = + ReadFileToVector(m_root_directory + "disc/header.bin", &m_disk_header_nonpartition); + + // If header.bin is missing or smaller than expected, use the content of sys/boot.bin instead + std::copy(partition_header.data() + header_bin_bytes_read, + partition_header.data() + m_disk_header_nonpartition.size(), + m_disk_header_nonpartition.data() + header_bin_bytes_read); + + // 0x60 and 0x61 are the only differences between the partition and non-partition headers + if (header_bin_bytes_read < 0x60) + m_disk_header_nonpartition[0x60] = 0; + if (header_bin_bytes_read < 0x61) + m_disk_header_nonpartition[0x61] = 0; + + m_nonpartition_contents.emplace(NONPARTITION_DISKHEADER_ADDRESS, NONPARTITION_DISKHEADER_SIZE, + m_disk_header_nonpartition.data()); +} + +void DirectoryBlobPartition::SetBI2() { constexpr u64 BI2_ADDRESS = 0x440; constexpr u64 BI2_SIZE = 0x2000; - AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); + AddFileToContents(&m_contents, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); } void DirectoryBlobReader::SetPartitionTable() @@ -331,13 +341,12 @@ void DirectoryBlobReader::SetTMDAndTicket() GAME_PARTITION_ADDRESS + TICKET_OFFSET, TICKET_SIZE); const DiscContent& tmd = AddFileToContents(&m_nonpartition_contents, m_root_directory + "tmd.bin", GAME_PARTITION_ADDRESS + TMD_OFFSET, MAX_TMD_SIZE); - m_tmd_header = {Common::swap32(static_cast(tmd.GetSize())), - Common::swap32(TMD_OFFSET >> m_address_shift)}; + m_tmd_header = {Common::swap32(static_cast(tmd.GetSize())), Common::swap32(TMD_OFFSET >> 2)}; m_nonpartition_contents.emplace(GAME_PARTITION_ADDRESS + TICKET_SIZE, sizeof(m_tmd_header), reinterpret_cast(&m_tmd_header)); } -u64 DirectoryBlobReader::SetApploader() +u64 DirectoryBlobPartition::SetApploader() { bool success = false; @@ -367,16 +376,16 @@ u64 DirectoryBlobReader::SetApploader() constexpr u64 APPLOADER_ADDRESS = 0x2440; - m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); + m_contents.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); // Return DOL address, 32 byte aligned (plus 32 byte padding) return Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); } -u64 DirectoryBlobReader::SetDOL(u64 dol_address) +u64 DirectoryBlobPartition::SetDOL(u64 dol_address) { const DiscContent& dol = - AddFileToContents(&m_virtual_disc, m_root_directory + "sys/main.dol", dol_address); + AddFileToContents(&m_contents, m_root_directory + "sys/main.dol", dol_address); Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disk_header); @@ -384,7 +393,7 @@ u64 DirectoryBlobReader::SetDOL(u64 dol_address) return Common::AlignUp(dol_address + dol.GetSize() + 0x20, 0x20ull); } -void DirectoryBlobReader::BuildFST(u64 fst_address) +void DirectoryBlobPartition::BuildFST(u64 fst_address) { m_fst_data.clear(); @@ -419,11 +428,11 @@ void DirectoryBlobReader::BuildFST(u64 fst_address) Write32((u32)(m_fst_data.size() >> m_address_shift), 0x0428, &m_disk_header); Write32((u32)(m_fst_data.size() >> m_address_shift), 0x042c, &m_disk_header); - m_virtual_disc.emplace(fst_address, m_fst_data.size(), m_fst_data.data()); + m_contents.emplace(fst_address, m_fst_data.size(), m_fst_data.data()); } -void DirectoryBlobReader::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, - u64 data_offset, u64 length, u32 address_shift) +void DirectoryBlobPartition::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, + u64 data_offset, u64 length, u32 address_shift) { m_fst_data[(*entry_offset)++] = type; @@ -438,17 +447,17 @@ void DirectoryBlobReader::WriteEntryData(u32* entry_offset, u8 type, u32 name_of *entry_offset += 4; } -void DirectoryBlobReader::WriteEntryName(u32* name_offset, const std::string& name, - u64 name_table_offset) +void DirectoryBlobPartition::WriteEntryName(u32* name_offset, const std::string& name, + u64 name_table_offset) { strncpy((char*)&m_fst_data[*name_offset + name_table_offset], name.c_str(), name.length() + 1); *name_offset += (u32)(name.length() + 1); } -void DirectoryBlobReader::WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, - u32* name_offset, u64* data_offset, u32 parent_entry_index, - u64 name_table_offset) +void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, + u32* name_offset, u64* data_offset, + u32 parent_entry_index, u64 name_table_offset) { std::vector sorted_entries = parent_entry.children; @@ -479,7 +488,7 @@ void DirectoryBlobReader::WriteDirectory(const File::FSTEntry& parent_entry, u32 WriteEntryName(name_offset, entry.virtualName, name_table_offset); // write entry to virtual disc - auto result = m_virtual_disc.emplace(*data_offset, entry.size, entry.physicalName); + auto result = m_contents.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 diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index fe23bf9e75..3bcde03dd5 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -52,6 +52,49 @@ private: ContentSource m_content_source; }; +class DirectoryBlobPartition +{ +public: + explicit DirectoryBlobPartition(const std::string& root_directory); + + // We do not allow copying, because it might mess up the pointers inside DiscContents + DirectoryBlobPartition(const DirectoryBlobPartition&) = delete; + DirectoryBlobPartition& operator=(const DirectoryBlobPartition&) = delete; + DirectoryBlobPartition(DirectoryBlobPartition&&) = default; + DirectoryBlobPartition& operator=(DirectoryBlobPartition&&) = default; + + bool IsWii() const { return m_is_wii; } + const std::vector& GetHeader() const { return m_disk_header; } + const std::set& GetContents() const { return m_contents; } +private: + void SetDiscHeaderAndDiscType(); + void SetBI2(); + + // Returns DOL address + u64 SetApploader(); + // Returns FST address + u64 SetDOL(u64 dol_address); + + void BuildFST(u64 fst_address); + + // FST creation + void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, + u32 address_shift); + void WriteEntryName(u32* name_offset, const std::string& name, u64 name_table_offset); + 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; + std::vector m_disk_header; + std::vector m_apploader; + std::vector m_fst_data; + + std::string m_root_directory; + bool m_is_wii; + // GameCube has no shift, Wii has 2 bit shift + u32 m_address_shift; +}; + class DirectoryBlobReader : public BlobReader { public: @@ -76,39 +119,18 @@ private: bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); - void SetDiscHeaderAndDiscType(); - void SetBI2(); + void SetNonpartitionDiscHeader(const std::vector& partition_header); void SetPartitionTable(); void SetWiiRegionData(); void SetTMDAndTicket(); - // Returns DOL address - u64 SetApploader(); - // Returns FST address - u64 SetDOL(u64 dol_address); - - void BuildFST(u64 fst_address); - - // FST creation - void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, - u32 address_shift); - void WriteEntryName(u32* name_offset, const std::string& name, u64 name_table_offset); - 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::string m_root_directory; - std::set m_virtual_disc; + DirectoryBlobPartition m_game_partition; std::set m_nonpartition_contents; bool m_is_wii; - // GameCube has no shift, Wii has 2 bit shift - u32 m_address_shift; - - std::vector m_fst_data; - - std::vector m_disk_header; std::vector m_disk_header_nonpartition; std::vector m_wii_region_data; @@ -120,8 +142,6 @@ private: } m_tmd_header; static_assert(sizeof(TMDHeader) == 8, "Wrong size for TMDHeader"); #pragma pack(pop) - - std::vector m_apploader; }; } // namespace