diff --git a/Source/Core/DiscIO/DiscUtils.cpp b/Source/Core/DiscIO/DiscUtils.cpp index 1919a1d6e5..f352c5d5c8 100644 --- a/Source/Core/DiscIO/DiscUtils.cpp +++ b/Source/Core/DiscIO/DiscUtils.cpp @@ -8,10 +8,12 @@ #include #include #include +#include #include #include "Common/CommonTypes.h" +#include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" namespace DiscIO @@ -120,4 +122,82 @@ std::optional GetFSTSize(const Volume& volume, const Partition& partition) return volume.ReadSwappedAndShifted(0x428, partition); } +u64 GetBiggestReferencedOffset(const Volume& volume) +{ + std::vector partitions = volume.GetPartitions(); + + // If a partition doesn't seem to contain any valid data, skip it. + // 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 + constexpr u32 WII_MAGIC = 0x5D1C9EA3; + const auto it = + std::remove_if(partitions.begin(), partitions.end(), [&](const Partition& partition) { + return volume.ReadSwapped(0x18, partition) != WII_MAGIC; + }); + partitions.erase(it, partitions.end()); + + if (partitions.empty()) + partitions.push_back(PARTITION_NONE); + + return GetBiggestReferencedOffset(volume, partitions); +} + +static u64 GetBiggestReferencedOffset(const Volume& volume, const FileInfo& file_info) +{ + if (file_info.IsDirectory()) + { + u64 biggest_offset = 0; + for (const FileInfo& f : file_info) + biggest_offset = std::max(biggest_offset, GetBiggestReferencedOffset(volume, f)); + return biggest_offset; + } + else + { + return file_info.GetOffset() + file_info.GetSize(); + } +} + +u64 GetBiggestReferencedOffset(const Volume& volume, const std::vector& partitions) +{ + const u64 disc_header_size = volume.GetVolumeType() == Platform::GameCubeDisc ? 0x460 : 0x50000; + u64 biggest_offset = disc_header_size; + for (const Partition& partition : partitions) + { + if (partition != PARTITION_NONE) + { + const u64 offset = volume.PartitionOffsetToRawOffset(0x440, partition); + biggest_offset = std::max(biggest_offset, offset); + } + + const std::optional dol_offset = GetBootDOLOffset(volume, partition); + if (dol_offset) + { + const std::optional dol_size = GetBootDOLSize(volume, partition, *dol_offset); + if (dol_size) + { + const u64 offset = volume.PartitionOffsetToRawOffset(*dol_offset + *dol_size, partition); + biggest_offset = std::max(biggest_offset, offset); + } + } + + const std::optional fst_offset = GetFSTOffset(volume, partition); + const std::optional fst_size = GetFSTSize(volume, partition); + if (fst_offset && fst_size) + { + const u64 offset = volume.PartitionOffsetToRawOffset(*fst_offset + *fst_size, partition); + biggest_offset = std::max(biggest_offset, offset); + } + + const FileSystem* fs = volume.GetFileSystem(partition); + if (fs) + { + 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); + } + } + return biggest_offset; +} + } // namespace DiscIO diff --git a/Source/Core/DiscIO/DiscUtils.h b/Source/Core/DiscIO/DiscUtils.h index 3a86ff8b0c..b2844e7759 100644 --- a/Source/Core/DiscIO/DiscUtils.h +++ b/Source/Core/DiscIO/DiscUtils.h @@ -6,14 +6,22 @@ #include #include +#include #include "Common/CommonTypes.h" namespace DiscIO { +class FileInfo; struct Partition; class Volume; +constexpr u64 MINI_DVD_SIZE = 1459978240; // GameCube +constexpr u64 SL_DVD_SIZE = 4699979776; // Wii retail +constexpr u64 SL_DVD_R_SIZE = 4707319808; // Wii RVT-R +constexpr u64 DL_DVD_SIZE = 8511160320; // Wii retail +constexpr u64 DL_DVD_R_SIZE = 8543666176; // Wii RVT-R + constexpr u32 PARTITION_DATA = 0; constexpr u32 PARTITION_UPDATE = 1; constexpr u32 PARTITION_CHANNEL = 2; // Mario Kart Wii, Wii Fit, Wii Fit Plus, Rabbids Go Home @@ -26,4 +34,7 @@ std::optional GetBootDOLOffset(const Volume& volume, const Partition& parti std::optional GetBootDOLSize(const Volume& volume, const Partition& partition, u64 dol_offset); std::optional GetFSTOffset(const Volume& volume, const Partition& partition); std::optional GetFSTSize(const Volume& volume, const Partition& partition); -} + +u64 GetBiggestReferencedOffset(const Volume& volume); +u64 GetBiggestReferencedOffset(const Volume& volume, const std::vector& partitions); +} // namespace DiscIO diff --git a/Source/Core/DiscIO/VolumeVerifier.cpp b/Source/Core/DiscIO/VolumeVerifier.cpp index c5fdb0cf91..d9ef9b991b 100644 --- a/Source/Core/DiscIO/VolumeVerifier.cpp +++ b/Source/Core/DiscIO/VolumeVerifier.cpp @@ -358,12 +358,6 @@ RedumpVerifier::Result RedumpVerifier::Finish(const Hashes>& has return {Status::Unknown, Common::GetStringT("Unknown disc")}; } -constexpr u64 MINI_DVD_SIZE = 1459978240; // GameCube -constexpr u64 SL_DVD_SIZE = 4699979776; // Wii retail -constexpr u64 SL_DVD_R_SIZE = 4707319808; // Wii RVT-R -constexpr u64 DL_DVD_SIZE = 8511160320; // Wii retail -constexpr u64 DL_DVD_R_SIZE = 8543666176; // Wii RVT-R - constexpr u64 BLOCK_SIZE = 0x20000; VolumeVerifier::VolumeVerifier(const Volume& volume, bool redump_verification, @@ -397,7 +391,7 @@ void VolumeVerifier::Start() const std::vector partitions = CheckPartitions(); if (IsDisc(m_volume.GetVolumeType())) - m_biggest_referenced_offset = GetBiggestReferencedOffset(partitions); + m_biggest_referenced_offset = GetBiggestReferencedOffset(m_volume, partitions); CheckMisc(); @@ -822,63 +816,6 @@ void VolumeVerifier::CheckVolumeSize() } } -u64 VolumeVerifier::GetBiggestReferencedOffset(const std::vector& partitions) const -{ - const u64 disc_header_size = m_volume.GetVolumeType() == Platform::GameCubeDisc ? 0x460 : 0x50000; - u64 biggest_offset = disc_header_size; - for (const Partition& partition : partitions) - { - if (partition != PARTITION_NONE) - { - const u64 offset = m_volume.PartitionOffsetToRawOffset(0x440, partition); - biggest_offset = std::max(biggest_offset, offset); - } - - const std::optional dol_offset = GetBootDOLOffset(m_volume, partition); - if (dol_offset) - { - const std::optional dol_size = GetBootDOLSize(m_volume, partition, *dol_offset); - if (dol_size) - { - const u64 offset = m_volume.PartitionOffsetToRawOffset(*dol_offset + *dol_size, partition); - biggest_offset = std::max(biggest_offset, offset); - } - } - - const std::optional fst_offset = GetFSTOffset(m_volume, partition); - const std::optional fst_size = GetFSTSize(m_volume, partition); - if (fst_offset && fst_size) - { - const u64 offset = m_volume.PartitionOffsetToRawOffset(*fst_offset + *fst_size, partition); - biggest_offset = std::max(biggest_offset, offset); - } - - const FileSystem* fs = m_volume.GetFileSystem(partition); - if (fs) - { - const u64 offset = - m_volume.PartitionOffsetToRawOffset(GetBiggestReferencedOffset(fs->GetRoot()), partition); - biggest_offset = std::max(biggest_offset, offset); - } - } - return biggest_offset; -} - -u64 VolumeVerifier::GetBiggestReferencedOffset(const FileInfo& file_info) const -{ - if (file_info.IsDirectory()) - { - u64 biggest_offset = 0; - for (const FileInfo& f : file_info) - biggest_offset = std::max(biggest_offset, GetBiggestReferencedOffset(f)); - return biggest_offset; - } - else - { - return file_info.GetOffset() + file_info.GetSize(); - } -} - void VolumeVerifier::CheckMisc() { const std::string game_id_unencrypted = m_volume.GetGameID(PARTITION_NONE); diff --git a/Source/Core/DiscIO/VolumeVerifier.h b/Source/Core/DiscIO/VolumeVerifier.h index 7992335d7b..78c4305107 100644 --- a/Source/Core/DiscIO/VolumeVerifier.h +++ b/Source/Core/DiscIO/VolumeVerifier.h @@ -34,8 +34,6 @@ namespace DiscIO { -class FileInfo; - template struct Hashes { @@ -154,8 +152,6 @@ private: bool ShouldHaveMasterpiecePartitions() const; bool ShouldBeDualLayer() const; void CheckVolumeSize(); - u64 GetBiggestReferencedOffset(const std::vector& partitions) const; - u64 GetBiggestReferencedOffset(const FileInfo& file_info) const; void CheckMisc(); void CheckSuperPaperMario(); void SetUpHashing();