From 047bb803376a294a66bca5c9e91e23918706d151 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 29 Aug 2020 15:12:02 +0200 Subject: [PATCH] DiscIO: Add parameters to BlobReader::SupportsReadWiiDecrypted It's possible (but rare) for a WIA or RVZ file to support this for some partitions but not all, and for the game and the blob code to disagree on how large a partition is. --- Source/Core/DiscIO/Blob.h | 6 ++- Source/Core/DiscIO/DirectoryBlob.cpp | 30 ++++++++----- Source/Core/DiscIO/DirectoryBlob.h | 4 +- Source/Core/DiscIO/VolumeWii.cpp | 8 ++-- Source/Core/DiscIO/WIABlob.cpp | 51 +++++++++++++++++------ Source/Core/DiscIO/WIABlob.h | 4 +- Source/Core/DiscIO/WiiEncryptionCache.cpp | 3 -- 7 files changed, 72 insertions(+), 34 deletions(-) diff --git a/Source/Core/DiscIO/Blob.h b/Source/Core/DiscIO/Blob.h index aa5274618a..473aa9bfce 100644 --- a/Source/Core/DiscIO/Blob.h +++ b/Source/Core/DiscIO/Blob.h @@ -70,7 +70,11 @@ public: return Common::FromBigEndian(temp); } - virtual bool SupportsReadWiiDecrypted() const { return false; } + virtual bool SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const + { + return false; + } + virtual bool ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset) { return false; diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 77ca32d19b..1e06dd74bd 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -406,25 +406,33 @@ bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer) .Read(offset, length, buffer); } -bool DirectoryBlobReader::SupportsReadWiiDecrypted() const +const DirectoryBlobPartition* DirectoryBlobReader::GetPartition(u64 offset, u64 size, + u64 partition_data_offset) const { - return m_is_wii; + const auto it = m_partitions.find(partition_data_offset); + if (it == m_partitions.end()) + return nullptr; + + if (offset + size > it->second.GetDataSize()) + return nullptr; + + return &it->second; +} + +bool DirectoryBlobReader::SupportsReadWiiDecrypted(u64 offset, u64 size, + u64 partition_data_offset) const +{ + return static_cast(GetPartition(offset, size, partition_data_offset)); } bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_data_offset) { - if (!m_is_wii) + const DirectoryBlobPartition* partition = GetPartition(offset, size, partition_data_offset); + if (!partition) return false; - auto it = m_partitions.find(partition_data_offset); - if (it == m_partitions.end()) - return false; - - if (offset + size > it->second.GetDataSize()) - return false; - - return it->second.GetContents().Read(offset, size, buffer); + return partition->GetContents().Read(offset, size, buffer); } bool DirectoryBlobReader::EncryptPartitionData(u64 offset, u64 size, u8* buffer, diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 9e6a834151..ca1f68d6ae 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -157,7 +157,7 @@ public: DirectoryBlobReader& operator=(DirectoryBlobReader&&) = default; bool Read(u64 offset, u64 length, u8* buffer) override; - bool SupportsReadWiiDecrypted() const override; + bool SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const override; bool ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_data_offset) override; BlobType GetBlobType() const override; @@ -185,6 +185,8 @@ private: explicit DirectoryBlobReader(const std::string& game_partition_root, const std::string& true_root); + const DirectoryBlobPartition* GetPartition(u64 offset, u64 size, u64 partition_data_offset) const; + bool EncryptPartitionData(u64 offset, u64 size, u8* buffer, u64 partition_data_offset, u64 partition_data_decrypted_size); diff --git a/Source/Core/DiscIO/VolumeWii.cpp b/Source/Core/DiscIO/VolumeWii.cpp index db31530c8e..2f0c833549 100644 --- a/Source/Core/DiscIO/VolumeWii.cpp +++ b/Source/Core/DiscIO/VolumeWii.cpp @@ -171,11 +171,9 @@ bool VolumeWii::Read(u64 offset, u64 length, u8* buffer, const Partition& partit return false; const PartitionDetails& partition_details = it->second; - if (m_reader->SupportsReadWiiDecrypted()) - { - return m_reader->ReadWiiDecrypted(offset, length, buffer, - partition.offset + *partition_details.data_offset); - } + const u64 partition_data_offset = partition.offset + *partition_details.data_offset; + if (m_reader->SupportsReadWiiDecrypted(offset, length, partition_data_offset)) + return m_reader->ReadWiiDecrypted(offset, length, buffer, partition_data_offset); if (!m_encrypted) { diff --git a/Source/Core/DiscIO/WIABlob.cpp b/Source/Core/DiscIO/WIABlob.cpp index 94c3fc12c3..bdeb3a2951 100644 --- a/Source/Core/DiscIO/WIABlob.cpp +++ b/Source/Core/DiscIO/WIABlob.cpp @@ -413,28 +413,55 @@ bool WIARVZFileReader::Read(u64 offset, u64 size, u8* out_ptr) } template -bool WIARVZFileReader::SupportsReadWiiDecrypted() const +const typename WIARVZFileReader::PartitionEntry* +WIARVZFileReader::GetPartition(u64 partition_data_offset, u32* partition_first_sector) const { - return !m_partition_entries.empty(); + const auto it = m_data_entries.upper_bound(partition_data_offset); + if (it == m_data_entries.end() || !it->second.is_partition) + return nullptr; + + const PartitionEntry* partition = &m_partition_entries[it->second.index]; + *partition_first_sector = Common::swap32(partition->data_entries[0].first_sector); + if (partition_data_offset != *partition_first_sector * VolumeWii::BLOCK_TOTAL_SIZE) + return nullptr; + + return partition; +} + +template +bool WIARVZFileReader::SupportsReadWiiDecrypted(u64 offset, u64 size, + u64 partition_data_offset) const +{ + u32 partition_first_sector; + const PartitionEntry* partition = GetPartition(partition_data_offset, &partition_first_sector); + if (!partition) + return false; + + for (const PartitionDataEntry& data : partition->data_entries) + { + const u32 start_sector = Common::swap32(data.first_sector) - partition_first_sector; + const u32 end_sector = start_sector + Common::swap32(data.number_of_sectors); + + if (offset + size <= end_sector * VolumeWii::BLOCK_DATA_SIZE) + return true; + } + + return false; } template bool WIARVZFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset) { + u32 partition_first_sector; + const PartitionEntry* partition = GetPartition(partition_data_offset, &partition_first_sector); + if (!partition) + return false; + const u64 chunk_size = Common::swap32(m_header_2.chunk_size) * VolumeWii::BLOCK_DATA_SIZE / VolumeWii::BLOCK_TOTAL_SIZE; - const auto it = m_data_entries.upper_bound(partition_data_offset); - if (it == m_data_entries.end() || !it->second.is_partition) - return false; - - const PartitionEntry& partition = m_partition_entries[it->second.index]; - const u32 partition_first_sector = Common::swap32(partition.data_entries[0].first_sector); - if (partition_data_offset != partition_first_sector * VolumeWii::BLOCK_TOTAL_SIZE) - return false; - - for (const PartitionDataEntry& data : partition.data_entries) + for (const PartitionDataEntry& data : partition->data_entries) { if (size == 0) return true; diff --git a/Source/Core/DiscIO/WIABlob.h b/Source/Core/DiscIO/WIABlob.h index 8f941ce98b..c76af169f2 100644 --- a/Source/Core/DiscIO/WIABlob.h +++ b/Source/Core/DiscIO/WIABlob.h @@ -59,7 +59,7 @@ public: std::string GetCompressionMethod() const override; bool Read(u64 offset, u64 size, u8* out_ptr) override; - bool SupportsReadWiiDecrypted() const override; + bool SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const override; bool ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset) override; static ConversionResultCode Convert(BlobReader* infile, const VolumeDisc* infile_volume, @@ -224,6 +224,8 @@ private: bool Initialize(const std::string& path); bool HasDataOverlap() const; + const PartitionEntry* GetPartition(u64 partition_data_offset, u32* partition_first_sector) const; + bool ReadFromGroups(u64* offset, u64* size, u8** out_ptr, u64 chunk_size, u32 sector_size, u64 data_offset, u64 data_size, u32 group_index, u32 number_of_groups, u32 exception_lists); diff --git a/Source/Core/DiscIO/WiiEncryptionCache.cpp b/Source/Core/DiscIO/WiiEncryptionCache.cpp index 0bb892da71..52d978761e 100644 --- a/Source/Core/DiscIO/WiiEncryptionCache.cpp +++ b/Source/Core/DiscIO/WiiEncryptionCache.cpp @@ -29,10 +29,7 @@ WiiEncryptionCache::EncryptGroup(u64 offset, u64 partition_data_offset, { // Only allocate memory if this function actually ends up getting called if (!m_cache) - { m_cache = std::make_unique>(); - ASSERT(m_blob->SupportsReadWiiDecrypted()); - } ASSERT(offset % VolumeWii::GROUP_TOTAL_SIZE == 0); const u64 group_offset_in_partition =