From 49ccc77ebb1862a61293a14ee1d1d8b18b7f1fe1 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 9 Mar 2021 20:06:34 +0100 Subject: DiscIO: Move some code from DiscExtractor to new file DiscUtils --- Source/Core/DiscIO/DiscUtils.cpp | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Source/Core/DiscIO/DiscUtils.cpp (limited to 'Source/Core/DiscIO/DiscUtils.cpp') diff --git a/Source/Core/DiscIO/DiscUtils.cpp b/Source/Core/DiscIO/DiscUtils.cpp new file mode 100644 index 0000000000..1919a1d6e5 --- /dev/null +++ b/Source/Core/DiscIO/DiscUtils.cpp @@ -0,0 +1,123 @@ +// Copyright 2021 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DiscIO/DiscUtils.h" + +#include +#include +#include +#include + +#include + +#include "Common/CommonTypes.h" +#include "DiscIO/Volume.h" + +namespace DiscIO +{ +std::string NameForPartitionType(u32 partition_type, bool include_prefix) +{ + switch (partition_type) + { + case PARTITION_DATA: + return "DATA"; + case PARTITION_UPDATE: + return "UPDATE"; + case PARTITION_CHANNEL: + return "CHANNEL"; + case PARTITION_INSTALL: + // wit doesn't recognize the name "INSTALL", so we can't use it when naming partition folders + if (!include_prefix) + return "INSTALL"; + [[fallthrough]]; + default: + const std::string type_as_game_id{static_cast((partition_type >> 24) & 0xFF), + static_cast((partition_type >> 16) & 0xFF), + static_cast((partition_type >> 8) & 0xFF), + static_cast(partition_type & 0xFF)}; + if (std::all_of(type_as_game_id.cbegin(), type_as_game_id.cend(), + [](char c) { return std::isalnum(c, std::locale::classic()); })) + { + return include_prefix ? "P-" + type_as_game_id : type_as_game_id; + } + + return fmt::format(include_prefix ? "P{}" : "{}", partition_type); + } +} + +std::optional GetApploaderSize(const Volume& volume, const Partition& partition) +{ + constexpr u64 header_size = 0x20; + const std::optional apploader_size = volume.ReadSwapped(0x2440 + 0x14, partition); + const std::optional trailer_size = volume.ReadSwapped(0x2440 + 0x18, partition); + if (!apploader_size || !trailer_size) + return std::nullopt; + + return header_size + *apploader_size + *trailer_size; +} + +std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition) +{ + const Platform volume_type = volume.GetVolumeType(); + if (!IsDisc(volume_type)) + return std::nullopt; + + std::optional dol_offset = volume.ReadSwappedAndShifted(0x420, partition); + + // Datel AR disc has 0x00000000 as the offset (invalid) and doesn't use it in the AppLoader. + if (dol_offset && *dol_offset == 0) + dol_offset.reset(); + + return dol_offset; +} + +std::optional GetBootDOLSize(const Volume& volume, const Partition& partition, u64 dol_offset) +{ + if (!IsDisc(volume.GetVolumeType())) + return std::nullopt; + + u32 dol_size = 0; + + // Iterate through the 7 code segments + for (size_t i = 0; i < 7; i++) + { + const std::optional offset = volume.ReadSwapped(dol_offset + 0x00 + i * 4, partition); + const std::optional size = volume.ReadSwapped(dol_offset + 0x90 + i * 4, partition); + if (!offset || !size) + return {}; + dol_size = std::max(*offset + *size, dol_size); + } + + // Iterate through the 11 data segments + for (size_t i = 0; i < 11; i++) + { + const std::optional offset = volume.ReadSwapped(dol_offset + 0x1c + i * 4, partition); + const std::optional size = volume.ReadSwapped(dol_offset + 0xac + i * 4, partition); + if (!offset || !size) + return {}; + dol_size = std::max(*offset + *size, dol_size); + } + + return dol_size; +} + +std::optional GetFSTOffset(const Volume& volume, const Partition& partition) +{ + const Platform volume_type = volume.GetVolumeType(); + if (!IsDisc(volume_type)) + return std::nullopt; + + return volume.ReadSwappedAndShifted(0x424, partition); +} + +std::optional GetFSTSize(const Volume& volume, const Partition& partition) +{ + const Platform volume_type = volume.GetVolumeType(); + if (!IsDisc(volume_type)) + return std::nullopt; + + return volume.ReadSwappedAndShifted(0x428, partition); +} + +} // namespace DiscIO -- cgit v1.2.3 From b14bf8273245374e14b1b62a1ba5e26e4cccf42d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 9 Mar 2021 20:54:59 +0100 Subject: DiscIO: Move some code from VolumeVerifier to DiscUtils --- Source/Core/DiscIO/DiscUtils.cpp | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'Source/Core/DiscIO/DiscUtils.cpp') 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 -- cgit v1.2.3 From 7d570f1edb063dd2b486eb63cc78f9382b83a354 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 9 Mar 2021 21:06:57 +0100 Subject: DiscIO: Move magic constants for discs to DiscUtils --- Source/Core/DiscIO/DiscUtils.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Source/Core/DiscIO/DiscUtils.cpp') diff --git a/Source/Core/DiscIO/DiscUtils.cpp b/Source/Core/DiscIO/DiscUtils.cpp index f352c5d5c8..d0bcd66857 100644 --- a/Source/Core/DiscIO/DiscUtils.cpp +++ b/Source/Core/DiscIO/DiscUtils.cpp @@ -130,10 +130,9 @@ u64 GetBiggestReferencedOffset(const Volume& volume) // 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; + return volume.ReadSwapped(0x18, partition) != WII_DISC_MAGIC; }); partitions.erase(it, partitions.end()); -- cgit v1.2.3