From 878869488d292e8295daa5a885087f2ec1d875a8 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 7 Jun 2017 14:18:55 +0200 Subject: [PATCH 01/43] Boot: Consider DOL/ELF files as possible volumes The old approach to detecting DOL/ELF files doesn't fit with the new way of implementing extracted discs. The game list is already doing it in a way that's similar to the approach that this commit uses. --- Source/Core/Core/Boot/Boot.cpp | 45 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 7d83cc7660..bf1f87b3ec 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -63,35 +63,34 @@ std::unique_ptr BootParameters::GenerateFromFile(const std::stri std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); static const std::unordered_set disc_image_extensions = { - {".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz"}}; + {".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".dol", ".elf"}}; if (disc_image_extensions.find(extension) != disc_image_extensions.end() || is_drive) { - auto volume = DiscIO::CreateVolumeFromFilename(path); - if (!volume) + std::unique_ptr volume = DiscIO::CreateVolumeFromFilename(path); + if (volume) + return std::make_unique(Disc{path, std::move(volume)}); + + if (extension == ".elf") + return std::make_unique(Executable{path, std::make_unique(path)}); + + if (extension == ".dol") + return std::make_unique(Executable{path, std::make_unique(path)}); + + if (is_drive) { - if (is_drive) - { - PanicAlertT("Could not read \"%s\". " - "There is no disc in the drive or it is not a GameCube/Wii backup. " - "Please note that Dolphin cannot play games directly from the original " - "GameCube and Wii discs.", - path.c_str()); - } - else - { - PanicAlertT("\"%s\" is an invalid GCM/ISO file, or is not a GC/Wii ISO.", path.c_str()); - } - return {}; + PanicAlertT("Could not read \"%s\". " + "There is no disc in the drive or it is not a GameCube/Wii backup. " + "Please note that Dolphin cannot play games directly from the original " + "GameCube and Wii discs.", + path.c_str()); } - return std::make_unique(Disc{path, std::move(volume)}); + else + { + PanicAlertT("\"%s\" is an invalid GCM/ISO file, or is not a GC/Wii ISO.", path.c_str()); + } + return {}; } - if (extension == ".elf") - return std::make_unique(Executable{path, std::make_unique(path)}); - - if (extension == ".dol") - return std::make_unique(Executable{path, std::make_unique(path)}); - if (extension == ".dff") return std::make_unique(DFF{path}); From 5f8935932d38cb17f104e0363a4bb1e988e83548 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 7 Jun 2017 14:30:55 +0200 Subject: [PATCH 02/43] Blob: Add interface for reading decrypted Wii data directly This is useful for blob types that store Wii data unencrypted (such as WIA and discs extracted to directories) so that we don't have to waste CPU time encrypting in the blob code just to decrypt right afterwards in the volume code. --- Source/Core/DiscIO/Blob.h | 6 ++++++ Source/Core/DiscIO/VolumeWii.cpp | 3 +++ 2 files changed, 9 insertions(+) diff --git a/Source/Core/DiscIO/Blob.h b/Source/Core/DiscIO/Blob.h index 686605ed80..20107bef0f 100644 --- a/Source/Core/DiscIO/Blob.h +++ b/Source/Core/DiscIO/Blob.h @@ -56,6 +56,12 @@ public: return Common::FromBigEndian(temp); } + virtual bool SupportsReadWiiDecrypted() const { return false; } + virtual bool ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 partition_offset) + { + return false; + } + protected: BlobReader() {} }; diff --git a/Source/Core/DiscIO/VolumeWii.cpp b/Source/Core/DiscIO/VolumeWii.cpp index 7f7670d6d7..4e8bba6b91 100644 --- a/Source/Core/DiscIO/VolumeWii.cpp +++ b/Source/Core/DiscIO/VolumeWii.cpp @@ -128,6 +128,9 @@ bool VolumeWii::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, const Partition if (partition == PARTITION_NONE) return m_pReader->Read(_ReadOffset, _Length, _pBuffer); + if (m_pReader->SupportsReadWiiDecrypted()) + return m_pReader->ReadWiiDecrypted(_ReadOffset, _Length, _pBuffer, partition.offset); + // Get the decryption key for the partition auto it = m_partitions.find(partition); if (it == m_partitions.end()) From 37c09343d82efec3f758f4ad08ccb59686fd8a10 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 7 Jun 2017 20:32:09 +0200 Subject: [PATCH 03/43] Turn VolumeDirectory into DirectoryBlob This lets VolumeDirectory/DirectoryBlob skip implementing various volume functions like GetGameID, GetBanner, etc. It also lets us view extracted discs in the game list. This ends up breaking the boot process for Wii DirectoryBlobs due to workarounds being removed from the boot process, but that will be fixed later by adding proper DirectoryBlob support for things like TMDs. We now expect the directories to be laid out in a certain format (based on the format that WIT uses) instead of requiring the user to set the DVD root and apploader path settings. --- Source/Core/Core/Boot/Boot.cpp | 82 +---- Source/Core/Core/Boot/Boot.h | 7 +- Source/Core/Core/Boot/DolReader.cpp | 6 + Source/Core/Core/Boot/DolReader.h | 6 + Source/Core/Core/Boot/ElfReader.cpp | 7 + Source/Core/Core/Boot/ElfReader.h | 6 + Source/Core/DiscIO/Blob.cpp | 17 +- Source/Core/DiscIO/CMakeLists.txt | 2 +- ...{VolumeDirectory.cpp => DirectoryBlob.cpp} | 297 ++++++++---------- .../{VolumeDirectory.h => DirectoryBlob.h} | 66 ++-- Source/Core/DiscIO/DiscIO.vcxproj | 4 +- Source/Core/DiscIO/DiscIO.vcxproj.filters | 8 +- Source/Core/DiscIO/Volume.cpp | 11 - Source/Core/DiscIO/Volume.h | 3 - 14 files changed, 215 insertions(+), 307 deletions(-) rename Source/Core/DiscIO/{VolumeDirectory.cpp => DirectoryBlob.cpp} (64%) rename Source/Core/DiscIO/{VolumeDirectory.h => DirectoryBlob.h} (62%) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index bf1f87b3ec..fd442a2a5b 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -132,44 +132,6 @@ bool CBoot::DVDRead(const DiscIO::Volume& volume, u64 dvd_offset, u32 output_add return true; } -void CBoot::Load_FST(bool is_wii, const DiscIO::Volume* volume) -{ - if (!volume) - return; - - const DiscIO::Partition partition = volume->GetGamePartition(); - - // copy first 32 bytes of disc to start of Mem 1 - DVDRead(*volume, /*offset*/ 0, /*address*/ 0, /*length*/ 0x20, DiscIO::PARTITION_NONE); - - // copy of game id - Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180); - - u32 shift = 0; - if (is_wii) - shift = 2; - - const std::optional fst_offset = volume->ReadSwapped(0x0424, partition); - const std::optional fst_size = volume->ReadSwapped(0x0428, partition); - const std::optional max_fst_size = volume->ReadSwapped(0x042c, partition); - if (!fst_offset || !fst_size || !max_fst_size) - return; - - u32 arena_high = Common::AlignDown(0x817FFFFF - (*max_fst_size << shift), 0x20); - Memory::Write_U32(arena_high, 0x00000034); - - // load FST - DVDRead(*volume, *fst_offset << shift, arena_high, *fst_size << shift, partition); - Memory::Write_U32(arena_high, 0x00000038); - Memory::Write_U32(*max_fst_size << shift, 0x0000003c); - - if (is_wii) - { - // the apploader changes IOS MEM1_ARENA_END too - Memory::Write_U32(arena_high, 0x00003110); - } -} - void CBoot::UpdateDebugger_MapLoaded() { Host_NotifyMapLoaded(); @@ -308,15 +270,11 @@ bool CBoot::Load_BS2(const std::string& boot_rom_filename) return true; } -static const DiscIO::Volume* SetDefaultDisc() +static void SetDefaultDisc() { const SConfig& config = SConfig::GetInstance(); - // load default image or create virtual drive from directory - if (!config.m_strDVDRoot.empty()) - return SetDisc(DiscIO::CreateVolumeFromDirectory(config.m_strDVDRoot, config.bWii)); if (!config.m_strDefaultISO.empty()) - return SetDisc(DiscIO::CreateVolumeFromFilename(config.m_strDefaultISO)); - return nullptr; + SetDisc(DiscIO::CreateVolumeFromFilename(config.m_strDefaultISO)); } // Third boot step after BootManager and Core. See Call schedule in BootManager.cpp @@ -358,34 +316,14 @@ bool CBoot::BootUp(std::unique_ptr boot) if (!executable.reader->IsValid()) return false; - const DiscIO::Volume* volume = nullptr; - // VolumeDirectory only works with DOLs. - if (StringEndsWith(executable.path, ".dol")) - { - if (!config.m_strDVDRoot.empty()) - { - NOTICE_LOG(BOOT, "Setting DVDRoot %s", config.m_strDVDRoot.c_str()); - volume = SetDisc(DiscIO::CreateVolumeFromDirectory( - config.m_strDVDRoot, config.bWii, config.m_strApploader, executable.path)); - } - else if (!config.m_strDefaultISO.empty()) - { - NOTICE_LOG(BOOT, "Loading default ISO %s", config.m_strDefaultISO.c_str()); - volume = SetDisc(DiscIO::CreateVolumeFromFilename(config.m_strDefaultISO)); - } - } - else - { - volume = SetDefaultDisc(); - } - if (!executable.reader->LoadIntoMemory()) { PanicAlertT("Failed to load the executable to memory."); return false; } - // Poor man's bootup + SetDefaultDisc(); + if (config.bWii) { HID4.SBE = 1; @@ -393,14 +331,13 @@ bool CBoot::BootUp(std::unique_ptr boot) SetupBAT(config.bWii); // Because there is no TMD to get the requested system (IOS) version from, // we default to IOS58, which is the version used by the Homebrew Channel. - SetupWiiMemory(volume, 0x000000010000003a); + SetupWiiMemory(nullptr, 0x000000010000003a); } else { - EmulatedBS2_GC(volume, true); + EmulatedBS2_GC(nullptr, true); } - Load_FST(config.bWii, volume); PC = executable.reader->GetEntryPoint(); if (executable.reader->LoadSymbols() || LoadMapFromFilename()) @@ -464,8 +401,13 @@ bool CBoot::BootUp(std::unique_ptr boot) } BootExecutableReader::BootExecutableReader(const std::string& file_name) + : BootExecutableReader(File::IOFile{file_name, "rb"}) { - File::IOFile file{file_name, "rb"}; +} + +BootExecutableReader::BootExecutableReader(File::IOFile file) +{ + file.Seek(0, SEEK_SET); m_bytes.resize(file.GetSize()); file.ReadBytes(m_bytes.data(), m_bytes.size()); } diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 1f52daa1c5..69f784c827 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -15,6 +15,11 @@ #include "DiscIO/Enums.h" #include "DiscIO/Volume.h" +namespace File +{ +class IOFile; +} + struct RegionSetting { const std::string area; @@ -101,7 +106,6 @@ private: static bool EmulatedBS2_Wii(const DiscIO::Volume* volume); static bool EmulatedBS2(bool is_wii, const DiscIO::Volume* volume); static bool Load_BS2(const std::string& boot_rom_filename); - static void Load_FST(bool is_wii, const DiscIO::Volume* volume); static bool SetupWiiMemory(const DiscIO::Volume* volume, u64 ios_title_id); }; @@ -110,6 +114,7 @@ class BootExecutableReader { public: explicit BootExecutableReader(const std::string& file_name); + explicit BootExecutableReader(File::IOFile file); explicit BootExecutableReader(const std::vector& buffer); virtual ~BootExecutableReader(); diff --git a/Source/Core/Core/Boot/DolReader.cpp b/Source/Core/Core/Boot/DolReader.cpp index 391aace573..ef1ece315b 100644 --- a/Source/Core/Core/Boot/DolReader.cpp +++ b/Source/Core/Core/Boot/DolReader.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "Common/File.h" @@ -18,6 +19,11 @@ DolReader::DolReader(const std::vector& buffer) : BootExecutableReader(buffe m_is_valid = Initialize(buffer); } +DolReader::DolReader(File::IOFile file) : BootExecutableReader(std::move(file)) +{ + m_is_valid = Initialize(m_bytes); +} + DolReader::DolReader(const std::string& filename) : BootExecutableReader(filename) { m_is_valid = Initialize(m_bytes); diff --git a/Source/Core/Core/Boot/DolReader.h b/Source/Core/Core/Boot/DolReader.h index e2daa04733..38f6616ccb 100644 --- a/Source/Core/Core/Boot/DolReader.h +++ b/Source/Core/Core/Boot/DolReader.h @@ -10,10 +10,16 @@ #include "Common/CommonTypes.h" #include "Core/Boot/Boot.h" +namespace File +{ +class IOFile; +} + class DolReader final : public BootExecutableReader { public: explicit DolReader(const std::string& filename); + explicit DolReader(File::IOFile file); explicit DolReader(const std::vector& buffer); ~DolReader(); diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index 78a77954ed..99faaa6fda 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -5,8 +5,10 @@ #include "Core/Boot/ElfReader.h" #include +#include #include "Common/CommonTypes.h" +#include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/Swap.h" @@ -71,6 +73,11 @@ ElfReader::ElfReader(const std::vector& buffer) : BootExecutableReader(buffe Initialize(m_bytes.data()); } +ElfReader::ElfReader(File::IOFile file) : BootExecutableReader(std::move(file)) +{ + Initialize(m_bytes.data()); +} + ElfReader::ElfReader(const std::string& filename) : BootExecutableReader(filename) { Initialize(m_bytes.data()); diff --git a/Source/Core/Core/Boot/ElfReader.h b/Source/Core/Core/Boot/ElfReader.h index 951f5a7b57..d9ffa78345 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -8,6 +8,11 @@ #include "Core/Boot/Boot.h" #include "Core/Boot/ElfTypes.h" +namespace File +{ +class IOFile; +} + enum KnownElfTypes { KNOWNELF_PSP = 0, @@ -22,6 +27,7 @@ class ElfReader final : public BootExecutableReader { public: explicit ElfReader(const std::string& filename); + explicit ElfReader(File::IOFile file); explicit ElfReader(const std::vector& buffer); ~ElfReader(); u32 Read32(int off) const { return base32[off >> 2]; } diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp index da8640c7bc..a27f6861e1 100644 --- a/Source/Core/DiscIO/Blob.cpp +++ b/Source/Core/DiscIO/Blob.cpp @@ -16,6 +16,7 @@ #include "DiscIO/Blob.h" #include "DiscIO/CISOBlob.h" #include "DiscIO/CompressedBlob.h" +#include "DiscIO/DirectoryBlob.h" #include "DiscIO/DriveBlob.h" #include "DiscIO/FileBlob.h" #include "DiscIO/TGCBlob.h" @@ -183,12 +184,13 @@ std::unique_ptr CreateBlobReader(const std::string& filename) if (!file.ReadArray(&magic, 1)) return nullptr; - // Conveniently, every supported file format (except for plain disc images) starts - // with a 4-byte magic number that identifies the format, so we just need a simple - // switch statement to create the right blob type. If the magic number doesn't - // match any known magic number, we assume it's a plain disc image. If that - // assumption is wrong, the volume code that runs later will notice the error - // because the blob won't provide valid data when reading the GC/Wii disc header. + // Conveniently, every supported file format (except for plain disc images and + // extracted discs) starts with a 4-byte magic number that identifies the format, + // so we just need a simple switch statement to create the right blob type. If the + // magic number doesn't match any known magic number and the directory structure + // doesn't match the directory blob format, we assume it's a plain disc image. If + // that assumption is wrong, the volume code that runs later will notice the error + // because the blob won't provide the right data when reading the GC/Wii disc header. switch (magic) { @@ -201,6 +203,9 @@ std::unique_ptr CreateBlobReader(const std::string& filename) case WBFS_MAGIC: return WbfsFileReader::Create(std::move(file), filename); default: + if (DirectoryBlobReader::IsValidDirectoryBlob(filename)) + return DirectoryBlobReader::Create(std::move(file), filename); + return PlainFileReader::Create(std::move(file)); } } diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index b59435efa0..ef1598ecd7 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -3,6 +3,7 @@ set(SRCS CISOBlob.cpp WbfsBlob.cpp CompressedBlob.cpp + DirectoryBlob.cpp DiscExtractor.cpp DiscScrubber.cpp DriveBlob.cpp @@ -14,7 +15,6 @@ set(SRCS NANDImporter.cpp TGCBlob.cpp Volume.cpp - VolumeDirectory.cpp VolumeGC.cpp VolumeWad.cpp VolumeWii.cpp diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp similarity index 64% rename from Source/Core/DiscIO/VolumeDirectory.cpp rename to Source/Core/DiscIO/DirectoryBlob.cpp index 854aec3da6..9425869f26 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -2,14 +2,18 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "DiscIO/DirectoryBlob.h" + #include +#include +#include #include #include #include #include #include -#include #include +#include #include #include "Common/Align.h" @@ -20,10 +24,9 @@ #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" +#include "Common/Swap.h" +#include "Core/Boot/DolReader.h" #include "DiscIO/Blob.h" -#include "DiscIO/Enums.h" -#include "DiscIO/Volume.h" -#include "DiscIO/VolumeDirectory.h" namespace DiscIO { @@ -31,58 +34,77 @@ static u32 ComputeNameSize(const File::FSTEntry& parent_entry); static std::string ASCIIToUppercase(std::string str); static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); -const size_t VolumeDirectory::MAX_NAME_LENGTH; -const size_t VolumeDirectory::MAX_ID_LENGTH; +constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; +constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; +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}}; -VolumeDirectory::VolumeDirectory(const std::string& directory, bool is_wii, - const std::string& apploader, const std::string& dol) - : m_data_start_address(UINT64_MAX), m_disk_header(DISKHEADERINFO_ADDRESS), +const size_t DirectoryBlobReader::MAX_NAME_LENGTH; +const size_t DirectoryBlobReader::MAX_ID_LENGTH; + +static bool PathCharactersEqual(char a, char b) +{ + return a == b +#ifdef _WIN32 + || (a == '/' && b == '\\') || (a == '\\' && b == '/') +#endif + ; +} + +static bool PathEndsWith(const std::string& path, const std::string& suffix) +{ + if (suffix.size() > path.size()) + return false; + + std::string::const_iterator path_iterator = path.cend() - suffix.size(); + std::string::const_iterator suffix_iterator = suffix.cbegin(); + while (path_iterator != path.cend()) + { + if (!PathCharactersEqual(*path_iterator, *suffix_iterator)) + return false; + path_iterator++; + suffix_iterator++; + } + + return true; +} + +bool DirectoryBlobReader::IsValidDirectoryBlob(const std::string& dol_path) +{ + return PathEndsWith(dol_path, "/sys/main.dol"); +} + +std::unique_ptr DirectoryBlobReader::Create(File::IOFile dol, + const std::string& dol_path) +{ + if (!dol || !IsValidDirectoryBlob(dol_path)) + return nullptr; + + const size_t chars_to_remove = std::string("sys/main.dol").size(); + const std::string root_directory = dol_path.substr(0, dol_path.size() - chars_to_remove); + return std::unique_ptr( + new DirectoryBlobReader(std::move(dol), root_directory)); +} + +DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::string& root_directory) + : m_root_directory(root_directory), m_data_start_address(UINT64_MAX), + m_disk_header(DISKHEADERINFO_ADDRESS), m_disk_header_info(std::make_unique()), m_fst_address(0), m_dol_address(0) { - m_root_directory = ExtractDirectoryName(directory); - // create the default disk header SetGameID("AGBJ01"); SetName("Default name"); - if (is_wii) - SetDiskTypeWii(); - else - SetDiskTypeGC(); - - // Don't load the DOL if we don't have an apploader - if (SetApploader(apploader)) - SetDOL(dol); + // Setting the DOL relies on m_dol_address, which is set by SetApploader + if (SetApploader(m_root_directory + "sys/apploader.img")) + SetDOLAndDiskType(std::move(dol_file)); BuildFST(); } -VolumeDirectory::~VolumeDirectory() +bool DirectoryBlobReader::ReadPartition(u64 offset, u64 length, u8* buffer) { -} - -bool VolumeDirectory::IsValidDirectory(const std::string& directory) -{ - return File::IsDirectory(ExtractDirectoryName(directory)); -} - -bool VolumeDirectory::Read(u64 offset, u64 length, u8* buffer, const Partition& partition) const -{ - bool decrypt = partition != PARTITION_NONE; - - if (!decrypt && (offset + length >= 0x400) && m_is_wii) - { - // Fully supporting this would require re-encrypting every file that's read. - // Only supporting the areas that IOS allows software to read could be more feasible. - // Currently, only the header (up to 0x400) is supported, though we're cheating a bit - // with it by reading the header inside the current partition instead. Supporting the - // header is enough for booting games, but not for running things like the Disc Channel. - return false; - } - - if (decrypt && !m_is_wii) - return false; - // header if (offset < DISKHEADERINFO_ADDRESS) { @@ -161,134 +183,80 @@ bool VolumeDirectory::Read(u64 offset, u64 length, u8* buffer, const Partition& return true; } -std::vector VolumeDirectory::GetPartitions() const +bool DirectoryBlobReader::ReadNonPartition(u64 offset, u64 length, u8* buffer) { - return m_is_wii ? std::vector{GetGamePartition()} : std::vector(); + // header + if (offset < DISKHEADERINFO_ADDRESS) + { + WriteToBuffer(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_disk_header.data(), &offset, + &length, &buffer); + } + if (offset >= 0x40000) + { + WriteToBuffer(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), + reinterpret_cast(PARTITION_TABLE.data()), &offset, &length, &buffer); + } + + // TODO: TMDs, tickets, more headers, the partition contents... + + if (length > 0) + { + ERROR_LOG(DISCIO, "Unsupported raw read in DirectoryBlob at 0x%" PRIx64, offset); + return false; + } + + return true; } -Partition VolumeDirectory::GetGamePartition() const +bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer) { - return m_is_wii ? Partition(0x50000) : PARTITION_NONE; + return m_is_wii ? ReadNonPartition(offset, length, buffer) : + ReadPartition(offset, length, buffer); } -std::string VolumeDirectory::GetGameID(const Partition& partition) const +bool DirectoryBlobReader::SupportsReadWiiDecrypted() const { - return std::string(m_disk_header.begin(), m_disk_header.begin() + MAX_ID_LENGTH); + return m_is_wii; } -void VolumeDirectory::SetGameID(const std::string& id) +bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_offset) +{ + if (!m_is_wii || partition_offset != GAME_PARTITION_ADDRESS) + return false; + + return ReadPartition(offset, size, buffer); +} + +void DirectoryBlobReader::SetGameID(const std::string& id) { memcpy(m_disk_header.data(), id.c_str(), std::min(id.length(), MAX_ID_LENGTH)); } -Region VolumeDirectory::GetRegion() const -{ - if (m_is_wii) - return RegionSwitchWii(m_disk_header[3]); - - return RegionSwitchGC(m_disk_header[3]); -} - -Country VolumeDirectory::GetCountry(const Partition& partition) const -{ - return CountrySwitch(m_disk_header[3]); -} - -std::string VolumeDirectory::GetMakerID(const Partition& partition) const -{ - // Not implemented - return "00"; -} - -std::string VolumeDirectory::GetInternalName(const Partition& partition) const -{ - char name[0x60]; - if (Read(0x20, 0x60, (u8*)name, partition)) - return DecodeString(name); - else - return ""; -} - -std::map VolumeDirectory::GetLongNames() const -{ - std::string name = GetInternalName(); - if (name.empty()) - return {}; - return {{Language::LANGUAGE_UNKNOWN, name}}; -} - -std::vector VolumeDirectory::GetBanner(int* width, int* height) const -{ - // Not implemented - *width = 0; - *height = 0; - return std::vector(); -} - -void VolumeDirectory::SetName(const std::string& name) +void DirectoryBlobReader::SetName(const std::string& name) { size_t length = std::min(name.length(), MAX_NAME_LENGTH); memcpy(&m_disk_header[0x20], name.c_str(), length); m_disk_header[length + 0x20] = 0; } -std::string VolumeDirectory::GetApploaderDate(const Partition& partition) const +BlobType DirectoryBlobReader::GetBlobType() const { - // Not implemented - return "VOID"; -} - -Platform VolumeDirectory::GetVolumeType() const -{ - return m_is_wii ? Platform::WII_DISC : Platform::GAMECUBE_DISC; -} - -BlobType VolumeDirectory::GetBlobType() const -{ - // VolumeDirectory isn't actually a blob, but it sort of acts - // like one, so it makes sense that it has its own blob type. - // It should be made into a proper blob in the future. return BlobType::DIRECTORY; } -u64 VolumeDirectory::GetSize() const +u64 DirectoryBlobReader::GetRawSize() const { // Not implemented return 0; } -u64 VolumeDirectory::GetRawSize() const +u64 DirectoryBlobReader::GetDataSize() const { // Not implemented return 0; } -std::string VolumeDirectory::ExtractDirectoryName(const std::string& directory) -{ - std::string result = directory; - - size_t last_separator = result.find_last_of(DIR_SEP_CHR); - - if (last_separator != result.size() - 1) - { - // TODO: This assumes that file names will always have a dot in them - // and directory names never will; both assumptions are often - // right but in general wrong. - size_t extension_start = result.find_last_of('.'); - if (extension_start != std::string::npos && extension_start > last_separator) - { - result.resize(last_separator); - } - } - else - { - result.resize(last_separator); - } - - return result; -} - -void VolumeDirectory::SetDiskTypeWii() +void DirectoryBlobReader::SetDiskTypeWii() { Write32(0x5d1c9ea3, 0x18, &m_disk_header); memset(&m_disk_header[0x1c], 0, 4); @@ -297,7 +265,7 @@ void VolumeDirectory::SetDiskTypeWii() m_address_shift = 2; } -void VolumeDirectory::SetDiskTypeGC() +void DirectoryBlobReader::SetDiskTypeGC() { memset(&m_disk_header[0x18], 0, 4); Write32(0xc2339f3d, 0x1c, &m_disk_header); @@ -306,7 +274,7 @@ void VolumeDirectory::SetDiskTypeGC() m_address_shift = 0; } -bool VolumeDirectory::SetApploader(const std::string& apploader) +bool DirectoryBlobReader::SetApploader(const std::string& apploader) { if (!apploader.empty()) { @@ -339,27 +307,28 @@ bool VolumeDirectory::SetApploader(const std::string& apploader) } } -void VolumeDirectory::SetDOL(const std::string& dol) +void DirectoryBlobReader::SetDOLAndDiskType(File::IOFile dol_file) { - if (!dol.empty()) - { - std::string data; - File::ReadFileToString(dol, data); - m_dol.resize(data.size()); - std::copy(data.begin(), data.end(), m_dol.begin()); + m_dol.resize(dol_file.GetSize()); + dol_file.Seek(0, SEEK_SET); + dol_file.ReadBytes(m_dol.data(), m_dol.size()); - Write32((u32)(m_dol_address >> m_address_shift), 0x0420, &m_disk_header); + if (DolReader(std::move(dol_file)).IsWii()) + SetDiskTypeWii(); + else + SetDiskTypeGC(); - // 32byte aligned (plus 0x20 padding) - m_fst_address = Common::AlignUp(m_dol_address + m_dol.size() + 0x20, 0x20ull); - } + Write32((u32)(m_dol_address >> m_address_shift), 0x0420, &m_disk_header); + + // 32byte aligned (plus 0x20 padding) + m_fst_address = Common::AlignUp(m_dol_address + m_dol.size() + 0x20, 0x20ull); } -void VolumeDirectory::BuildFST() +void DirectoryBlobReader::BuildFST() { m_fst_data.clear(); - File::FSTEntry rootEntry = File::ScanDirectoryTree(m_root_directory, true); + File::FSTEntry rootEntry = File::ScanDirectoryTree(m_root_directory + "files/", true); ConvertUTF8NamesToSHIFTJIS(rootEntry); @@ -395,8 +364,9 @@ void VolumeDirectory::BuildFST() Write32((u32)(m_fst_data.size() >> m_address_shift), 0x042c, &m_disk_header); } -void VolumeDirectory::WriteToBuffer(u64 source_start_address, u64 source_length, const u8* source, - u64* address, u64* length, u8** buffer) const +void DirectoryBlobReader::WriteToBuffer(u64 source_start_address, u64 source_length, + const u8* source, u64* address, u64* length, + u8** buffer) const { if (*length == 0) return; @@ -417,7 +387,8 @@ void VolumeDirectory::WriteToBuffer(u64 source_start_address, u64 source_length, } } -void VolumeDirectory::PadToAddress(u64 start_address, u64* address, u64* length, u8** buffer) const +void DirectoryBlobReader::PadToAddress(u64 start_address, u64* address, u64* length, + u8** buffer) const { if (start_address > *address && *length > 0) { @@ -429,7 +400,7 @@ void VolumeDirectory::PadToAddress(u64 start_address, u64* address, u64* length, } } -void VolumeDirectory::Write32(u32 data, u32 offset, std::vector* const buffer) +void DirectoryBlobReader::Write32(u32 data, u32 offset, std::vector* const buffer) { (*buffer)[offset++] = (data >> 24); (*buffer)[offset++] = (data >> 16) & 0xff; @@ -437,8 +408,8 @@ void VolumeDirectory::Write32(u32 data, u32 offset, std::vector* const buffe (*buffer)[offset] = (data)&0xff; } -void VolumeDirectory::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, - u64 length, u32 address_shift) +void DirectoryBlobReader::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, + u64 data_offset, u64 length, u32 address_shift) { m_fst_data[(*entry_offset)++] = type; @@ -453,15 +424,15 @@ void VolumeDirectory::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset *entry_offset += 4; } -void VolumeDirectory::WriteEntryName(u32* name_offset, const std::string& name) +void DirectoryBlobReader::WriteEntryName(u32* name_offset, const std::string& name) { strncpy((char*)&m_fst_data[*name_offset + m_fst_name_offset], name.c_str(), name.length() + 1); *name_offset += (u32)(name.length() + 1); } -void VolumeDirectory::WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, - u32* name_offset, u64* data_offset, u32 parent_entry_index) +void DirectoryBlobReader::WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, + u32* name_offset, u64* data_offset, u32 parent_entry_index) { std::vector sorted_entries = parent_entry.children; diff --git a/Source/Core/DiscIO/VolumeDirectory.h b/Source/Core/DiscIO/DirectoryBlob.h similarity index 62% rename from Source/Core/DiscIO/VolumeDirectory.h rename to Source/Core/DiscIO/DirectoryBlob.h index 360570b063..f79929615d 100644 --- a/Source/Core/DiscIO/VolumeDirectory.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -11,74 +11,48 @@ #include #include "Common/CommonTypes.h" -#include "DiscIO/Volume.h" +#include "Common/FileUtil.h" +#include "DiscIO/Blob.h" namespace File { struct FSTEntry; +class IOFile; } -// -// --- this volume type is used for reading files directly from the hard drive --- -// - namespace DiscIO { -enum class BlobType; -enum class Country; -enum class Language; -enum class Region; -enum class Platform; - -class VolumeDirectory : public Volume +class DirectoryBlobReader : public BlobReader { public: - VolumeDirectory(const std::string& directory, bool is_wii, const std::string& apploader = "", - const std::string& dol = ""); + static bool IsValidDirectoryBlob(const std::string& dol_path); + static std::unique_ptr Create(File::IOFile dol, const std::string& dol_path); - ~VolumeDirectory(); - - static bool IsValidDirectory(const std::string& directory); - - bool Read(u64 offset, u64 length, u8* buffer, const Partition& partition) const override; - std::vector GetPartitions() const override; - Partition GetGamePartition() const override; - - std::string GetGameID(const Partition& partition = PARTITION_NONE) const override; - void SetGameID(const std::string& id); - - std::string GetMakerID(const Partition& partition = PARTITION_NONE) const override; - - std::optional GetRevision(const Partition& partition = PARTITION_NONE) const override - { - return {}; - } - std::string GetInternalName(const Partition& partition = PARTITION_NONE) const override; - std::map GetLongNames() const override; - std::vector GetBanner(int* width, int* height) const override; - void SetName(const std::string&); - - std::string GetApploaderDate(const Partition& partition = PARTITION_NONE) const override; - Platform GetVolumeType() const override; - - Region GetRegion() const override; - Country GetCountry(const Partition& partition = PARTITION_NONE) const override; + bool Read(u64 offset, u64 length, u8* buffer) override; + bool SupportsReadWiiDecrypted() const override; + bool ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_offset) override; BlobType GetBlobType() const override; - u64 GetSize() const override; u64 GetRawSize() const override; + u64 GetDataSize() const override; + + void SetGameID(const std::string& id); + void SetName(const std::string&); void BuildFST(); private: - static std::string ExtractDirectoryName(const std::string& directory); + DirectoryBlobReader(File::IOFile dol_file, const std::string& root_directory); + + bool ReadPartition(u64 offset, u64 length, u8* buffer); + bool ReadNonPartition(u64 offset, u64 length, u8* buffer); void SetDiskTypeWii(); void SetDiskTypeGC(); bool SetApploader(const std::string& apploader); - void SetDOL(const std::string& dol); + void SetDOLAndDiskType(File::IOFile dol_file); // writing to read buffer void WriteToBuffer(u64 source_start_address, u64 source_length, const u8* source, u64* address, @@ -99,10 +73,10 @@ private: std::map m_virtual_disk; - bool m_is_wii; + bool m_is_wii = false; // GameCube has no shift, Wii has 2 bit shift - u32 m_address_shift; + u32 m_address_shift = 0; // first address on disk containing file data u64 m_data_start_address; diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj index 3a978ad262..b7ef5b9875 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj +++ b/Source/Core/DiscIO/DiscIO.vcxproj @@ -39,6 +39,7 @@ + @@ -50,7 +51,6 @@ - @@ -61,6 +61,7 @@ + @@ -72,7 +73,6 @@ - diff --git a/Source/Core/DiscIO/DiscIO.vcxproj.filters b/Source/Core/DiscIO/DiscIO.vcxproj.filters index 3c1f85ca10..3cebc18705 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj.filters +++ b/Source/Core/DiscIO/DiscIO.vcxproj.filters @@ -57,8 +57,8 @@ Volume\Blob - - Volume + + Volume\Blob Volume @@ -122,8 +122,8 @@ Volume - - Volume + + Volume\Blob Volume diff --git a/Source/Core/DiscIO/Volume.cpp b/Source/Core/DiscIO/Volume.cpp index 876136e6b9..014eda7d31 100644 --- a/Source/Core/DiscIO/Volume.cpp +++ b/Source/Core/DiscIO/Volume.cpp @@ -22,7 +22,6 @@ #include "DiscIO/Blob.h" #include "DiscIO/Enums.h" -#include "DiscIO/VolumeDirectory.h" #include "DiscIO/VolumeGC.h" #include "DiscIO/VolumeWad.h" #include "DiscIO/VolumeWii.h" @@ -112,14 +111,4 @@ std::unique_ptr CreateVolumeFromFilename(const std::string& filename) return nullptr; } -std::unique_ptr CreateVolumeFromDirectory(const std::string& directory, bool is_wii, - const std::string& apploader, - const std::string& dol) -{ - if (VolumeDirectory::IsValidDirectory(directory)) - return std::make_unique(directory, is_wii, apploader, dol); - - return nullptr; -} - } // namespace diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 209a0d09a9..979a63a23f 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -120,8 +120,5 @@ protected: }; std::unique_ptr CreateVolumeFromFilename(const std::string& filename); -std::unique_ptr CreateVolumeFromDirectory(const std::string& directory, bool is_wii, - const std::string& apploader = "", - const std::string& dol = ""); } // namespace From 12cbeb228895f3a66489fbeb7499551ed5297050 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 14:14:56 +0200 Subject: [PATCH 04/43] Remove DVD root and apploader path settings --- Source/Core/Core/ConfigManager.cpp | 4 -- Source/Core/Core/ConfigManager.h | 2 - Source/Core/DolphinQt2/Settings/PathPane.cpp | 45 ++----------------- Source/Core/DolphinQt2/Settings/PathPane.h | 4 -- .../Core/DolphinWX/Config/PathConfigPane.cpp | 41 +++-------------- Source/Core/DolphinWX/Config/PathConfigPane.h | 4 -- 6 files changed, 9 insertions(+), 91 deletions(-) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 9a605fd563..cda249379c 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -252,8 +252,6 @@ void SConfig::SaveCoreSettings(IniFile& ini) core->Set("FPRF", bFPRF); core->Set("AccurateNaNs", bAccurateNaNs); core->Set("DefaultISO", m_strDefaultISO); - core->Set("DVDRoot", m_strDVDRoot); - core->Set("Apploader", m_strApploader); core->Set("EnableCheats", bEnableCheats); core->Set("SelectedLanguage", SelectedLanguage); core->Set("OverrideGCLang", bOverrideGCLanguage); @@ -568,8 +566,6 @@ void SConfig::LoadCoreSettings(IniFile& ini) core->Get("CPUThread", &bCPUThread, true); core->Get("SyncOnSkipIdle", &bSyncGPUOnSkipIdleHack, true); core->Get("DefaultISO", &m_strDefaultISO); - core->Get("DVDRoot", &m_strDVDRoot); - core->Get("Apploader", &m_strApploader); core->Get("EnableCheats", &bEnableCheats, false); core->Get("SelectedLanguage", &SelectedLanguage, 0); core->Get("OverrideGCLang", &bOverrideGCLanguage, false); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index fa31751331..d7b3d1c77d 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -197,8 +197,6 @@ struct SConfig : NonCopyable std::string m_strBootROM; std::string m_strSRAM; std::string m_strDefaultISO; - std::string m_strDVDRoot; - std::string m_strApploader; std::string m_strWiiSDCardPath; std::string m_perfDir; diff --git a/Source/Core/DolphinQt2/Settings/PathPane.cpp b/Source/Core/DolphinQt2/Settings/PathPane.cpp index 2d21f20112..12faaa8af0 100644 --- a/Source/Core/DolphinQt2/Settings/PathPane.cpp +++ b/Source/Core/DolphinQt2/Settings/PathPane.cpp @@ -48,27 +48,6 @@ void PathPane::BrowseDefaultGame() } } -void PathPane::BrowseDVDRoot() -{ - QString dir = QFileDialog::getExistingDirectory(this, tr("Select DVD Root"), QDir::currentPath()); - if (!dir.isEmpty()) - { - m_dvd_edit->setText(dir); - SConfig::GetInstance().m_strDVDRoot = dir.toStdString(); - } -} - -void PathPane::BrowseApploader() -{ - QString file = QFileDialog::getOpenFileName(this, tr("Select an Apploader"), QDir::currentPath(), - tr("Apploaders (*.img)")); - if (!file.isEmpty()) - { - m_app_edit->setText(file); - SConfig::GetInstance().m_strApploader = file.toStdString(); - } -} - void PathPane::BrowseWiiNAND() { QString dir = @@ -127,32 +106,14 @@ QGridLayout* PathPane::MakePathsLayout() layout->addWidget(m_game_edit, 0, 1); layout->addWidget(game_open, 0, 2); - m_dvd_edit = new QLineEdit(QString::fromStdString(SConfig::GetInstance().m_strDVDRoot)); - connect(m_dvd_edit, &QLineEdit::editingFinished, - [=] { SConfig::GetInstance().m_strDVDRoot = m_dvd_edit->text().toStdString(); }); - QPushButton* dvd_open = new QPushButton; - connect(dvd_open, &QPushButton::clicked, this, &PathPane::BrowseDVDRoot); - layout->addWidget(new QLabel(tr("DVD Root:")), 1, 0); - layout->addWidget(m_dvd_edit, 1, 1); - layout->addWidget(dvd_open, 1, 2); - - m_app_edit = new QLineEdit(QString::fromStdString(SConfig::GetInstance().m_strApploader)); - connect(m_app_edit, &QLineEdit::editingFinished, - [=] { SConfig::GetInstance().m_strApploader = m_app_edit->text().toStdString(); }); - QPushButton* app_open = new QPushButton; - connect(app_open, &QPushButton::clicked, this, &PathPane::BrowseApploader); - layout->addWidget(new QLabel(tr("Apploader:")), 2, 0); - layout->addWidget(m_app_edit, 2, 1); - layout->addWidget(app_open, 2, 2); - m_nand_edit = new QLineEdit(QString::fromStdString(SConfig::GetInstance().m_NANDPath)); connect(m_nand_edit, &QLineEdit::editingFinished, [=] { SConfig::GetInstance().m_NANDPath = m_nand_edit->text().toStdString(); }); QPushButton* nand_open = new QPushButton; connect(nand_open, &QPushButton::clicked, this, &PathPane::BrowseWiiNAND); - layout->addWidget(new QLabel(tr("Wii NAND Root:")), 3, 0); - layout->addWidget(m_nand_edit, 3, 1); - layout->addWidget(nand_open, 3, 2); + layout->addWidget(new QLabel(tr("Wii NAND Root:")), 1, 0); + layout->addWidget(m_nand_edit, 1, 1); + layout->addWidget(nand_open, 1, 2); return layout; } diff --git a/Source/Core/DolphinQt2/Settings/PathPane.h b/Source/Core/DolphinQt2/Settings/PathPane.h index 753c5001c4..2d0f0b190c 100644 --- a/Source/Core/DolphinQt2/Settings/PathPane.h +++ b/Source/Core/DolphinQt2/Settings/PathPane.h @@ -19,8 +19,6 @@ public: private: void Browse(); void BrowseDefaultGame(); - void BrowseDVDRoot(); - void BrowseApploader(); void BrowseWiiNAND(); QGroupBox* MakeGameFolderBox(); QGridLayout* MakePathsLayout(); @@ -28,7 +26,5 @@ private: QListWidget* m_path_list; QLineEdit* m_game_edit; - QLineEdit* m_dvd_edit; - QLineEdit* m_app_edit; QLineEdit* m_nand_edit; }; diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.cpp b/Source/Core/DolphinWX/Config/PathConfigPane.cpp index ec3376acc2..0d54738192 100644 --- a/Source/Core/DolphinWX/Config/PathConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/PathConfigPane.cpp @@ -45,14 +45,6 @@ void PathConfigPane::InitializeGUI() wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.tgc;*.wbfs;*.ciso;*.gcz;*.wad|%s", wxGetTranslation(wxALL_FILES)), wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL); - m_dvd_root_dirpicker = - new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a DVD root directory:"), - wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL); - m_apploader_path_filepicker = new wxFilePickerCtrl( - this, wxID_ANY, wxEmptyString, - _("Choose file to use as apploader: (applies to discs constructed from directories only)"), - _("apploader (.img)") + wxString::Format("|*.img|%s", wxGetTranslation(wxALL_FILES)), - wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL); m_nand_root_dirpicker = new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a NAND root directory:"), wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL); @@ -82,21 +74,15 @@ void PathConfigPane::InitializeGUI() picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Default ISO:")), wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("DVD Root:")), wxGBPosition(1, 0), + picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - picker_sizer->Add(m_dvd_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Apploader:")), wxGBPosition(2, 0), + picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND); + picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Dump Path:")), wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - picker_sizer->Add(m_apploader_path_filepicker, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), wxGBPosition(3, 0), + picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND); + picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("SD Card Path:")), wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Dump Path:")), wxGBPosition(4, 0), - wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(4, 1), wxDefaultSpan, wxEXPAND); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("SD Card Path:")), wxGBPosition(5, 0), - wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(5, 1), wxDefaultSpan, wxEXPAND); + picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND); picker_sizer->AddGrowableCol(1); // Populate the Paths page @@ -116,8 +102,6 @@ void PathConfigPane::LoadGUIValues() m_recursive_iso_paths_checkbox->SetValue(SConfig::GetInstance().m_RecursiveISOFolder); m_default_iso_filepicker->SetPath(StrToWxStr(startup_params.m_strDefaultISO)); - m_dvd_root_dirpicker->SetPath(StrToWxStr(startup_params.m_strDVDRoot)); - m_apploader_path_filepicker->SetPath(StrToWxStr(startup_params.m_strApploader)); m_nand_root_dirpicker->SetPath(StrToWxStr(SConfig::GetInstance().m_NANDPath)); m_dump_path_dirpicker->SetPath(StrToWxStr(SConfig::GetInstance().m_DumpPath)); m_wii_sdcard_filepicker->SetPath(StrToWxStr(SConfig::GetInstance().m_strWiiSDCardPath)); @@ -136,9 +120,6 @@ void PathConfigPane::BindEvents() m_remove_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnRemoveISOPath, this); m_default_iso_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnDefaultISOChanged, this); - m_dvd_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnDVDRootChanged, this); - m_apploader_path_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, - &PathConfigPane::OnApploaderPathChanged, this); m_nand_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnNANDRootChanged, this); m_dump_path_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnDumpPathChanged, this); m_wii_sdcard_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnSdCardPathChanged, @@ -206,16 +187,6 @@ void PathConfigPane::OnDefaultISOChanged(wxCommandEvent& event) SConfig::GetInstance().m_strDefaultISO = WxStrToStr(m_default_iso_filepicker->GetPath()); } -void PathConfigPane::OnDVDRootChanged(wxCommandEvent& event) -{ - SConfig::GetInstance().m_strDVDRoot = WxStrToStr(m_dvd_root_dirpicker->GetPath()); -} - -void PathConfigPane::OnApploaderPathChanged(wxCommandEvent& event) -{ - SConfig::GetInstance().m_strApploader = WxStrToStr(m_apploader_path_filepicker->GetPath()); -} - void PathConfigPane::OnSdCardPathChanged(wxCommandEvent& event) { std::string sd_card_path = WxStrToStr(m_wii_sdcard_filepicker->GetPath()); diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.h b/Source/Core/DolphinWX/Config/PathConfigPane.h index 484c6d937c..ae708c116c 100644 --- a/Source/Core/DolphinWX/Config/PathConfigPane.h +++ b/Source/Core/DolphinWX/Config/PathConfigPane.h @@ -29,8 +29,6 @@ private: void OnAddISOPath(wxCommandEvent&); void OnRemoveISOPath(wxCommandEvent&); void OnDefaultISOChanged(wxCommandEvent&); - void OnDVDRootChanged(wxCommandEvent&); - void OnApploaderPathChanged(wxCommandEvent&); void OnNANDRootChanged(wxCommandEvent&); void OnDumpPathChanged(wxCommandEvent&); void OnSdCardPathChanged(wxCommandEvent&); @@ -42,10 +40,8 @@ private: wxButton* m_add_iso_path_button; wxButton* m_remove_iso_path_button; - wxDirPickerCtrl* m_dvd_root_dirpicker; wxDirPickerCtrl* m_nand_root_dirpicker; wxFilePickerCtrl* m_default_iso_filepicker; - wxFilePickerCtrl* m_apploader_path_filepicker; wxDirPickerCtrl* m_dump_path_dirpicker; wxFilePickerCtrl* m_wii_sdcard_filepicker; }; From b8d8c7370f9f9dabdf3964b403e4ae7666740136 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 7 Jun 2017 21:13:24 +0200 Subject: [PATCH 05/43] DirectoryBlob: Move constants to .cpp file --- Source/Core/DiscIO/DirectoryBlob.cpp | 12 +++++++++--- Source/Core/DiscIO/DirectoryBlob.h | 9 --------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 9425869f26..dc262c6509 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -34,15 +34,21 @@ static u32 ComputeNameSize(const File::FSTEntry& parent_entry); static std::string ASCIIToUppercase(std::string str); static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); +constexpr u8 ENTRY_SIZE = 0x0c; +constexpr u8 FILE_ENTRY = 0; +constexpr u8 DIRECTORY_ENTRY = 1; +constexpr u64 DISKHEADER_ADDRESS = 0; +constexpr u64 DISKHEADERINFO_ADDRESS = 0x440; +constexpr u64 APPLOADER_ADDRESS = 0x2440; +constexpr size_t MAX_NAME_LENGTH = 0x3df; +constexpr size_t MAX_ID_LENGTH = 6; + constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; 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}}; -const size_t DirectoryBlobReader::MAX_NAME_LENGTH; -const size_t DirectoryBlobReader::MAX_ID_LENGTH; - static bool PathCharactersEqual(char a, char b) { return a == b diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index f79929615d..fef7d83c46 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -121,15 +121,6 @@ private: u64 m_fst_address; u64 m_dol_address; - - static constexpr u8 ENTRY_SIZE = 0x0c; - static constexpr u8 FILE_ENTRY = 0; - static constexpr u8 DIRECTORY_ENTRY = 1; - static constexpr u64 DISKHEADER_ADDRESS = 0; - static constexpr u64 DISKHEADERINFO_ADDRESS = 0x440; - static constexpr u64 APPLOADER_ADDRESS = 0x2440; - static const size_t MAX_NAME_LENGTH = 0x3df; - static const size_t MAX_ID_LENGTH = 6; }; } // namespace From b56214789eaceb0a0b5c80fe33a1a381e350dcc2 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 14:24:43 +0200 Subject: [PATCH 06/43] DirectoryBlob: Make some functions private --- Source/Core/DiscIO/DirectoryBlob.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index fef7d83c46..ec19229c8a 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -36,11 +36,6 @@ public: u64 GetRawSize() const override; u64 GetDataSize() const override; - void SetGameID(const std::string& id); - void SetName(const std::string&); - - void BuildFST(); - private: DirectoryBlobReader(File::IOFile dol_file, const std::string& root_directory); @@ -50,10 +45,14 @@ private: void SetDiskTypeWii(); void SetDiskTypeGC(); - bool SetApploader(const std::string& apploader); + void SetGameID(const std::string& id); + void SetName(const std::string&); + bool SetApploader(const std::string& apploader); void SetDOLAndDiskType(File::IOFile dol_file); + void BuildFST(); + // writing to read buffer void WriteToBuffer(u64 source_start_address, u64 source_length, const u8* source, u64* address, u64* length, u8** buffer) const; From e1321b131d9e3386a4be17592363d72b13a15f66 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 16:07:01 +0200 Subject: [PATCH 07/43] 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; From 936ef5b9dde767698fc2a61b1d2b2c2f867f60f0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 16:37:51 +0200 Subject: [PATCH 08/43] DirectoryBlob: Let DiscContent be backed by memory instead of file --- Source/Core/DiscIO/DirectoryBlob.cpp | 24 +++++++++++++++++++----- Source/Core/DiscIO/DirectoryBlob.h | 11 +++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index a974e882d6..8f000454e8 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "Common/Align.h" @@ -50,7 +51,12 @@ const std::array PARTITION_TABLE = { 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) + : m_offset(offset), m_size(size), m_content_source(path) +{ +} + +DiscContent::DiscContent(u64 offset, u64 size, const u8* data) + : m_offset(offset), m_size(size), m_content_source(data) { } @@ -80,10 +86,18 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const { 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; + if (std::holds_alternative(m_content_source)) + { + File::IOFile file(std::get(m_content_source), "rb"); + file.Seek(offset_in_content, SEEK_SET); + if (!file.ReadBytes(*buffer, bytes_to_read)) + return false; + } + else + { + const u8* const content_pointer = std::get(m_content_source) + offset_in_content; + std::copy(content_pointer, content_pointer + bytes_to_read, *buffer); + } *length -= bytes_to_read; *buffer += bytes_to_read; diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 3e4683b906..f3879c97f6 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "Common/CommonTypes.h" @@ -26,7 +27,10 @@ namespace DiscIO class DiscContent { public: + using ContentSource = std::variant; + DiscContent(u64 offset, u64 size, const std::string& path); + DiscContent(u64 offset, u64 size, const u8* data); // Provided because it's convenient when searching for DiscContent in an std::set explicit DiscContent(u64 offset); @@ -45,6 +49,7 @@ private: u64 m_offset; u64 m_size = 0; std::string m_path; + ContentSource m_content_source; }; class DirectoryBlobReader : public BlobReader @@ -53,6 +58,12 @@ public: static bool IsValidDirectoryBlob(const std::string& dol_path); static std::unique_ptr Create(File::IOFile dol, const std::string& dol_path); + // We do not allow copying, because it might mess up the pointers inside DiscContents + DirectoryBlobReader(const DirectoryBlobReader&) = delete; + DirectoryBlobReader& operator=(const DirectoryBlobReader&) = delete; + DirectoryBlobReader(DirectoryBlobReader&&) = default; + DirectoryBlobReader& operator=(DirectoryBlobReader&&) = default; + bool Read(u64 offset, u64 length, u8* buffer) override; bool SupportsReadWiiDecrypted() const override; bool ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_offset) override; From a0fa350ca651f3ecbeb2b06e107c49c506bf995e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 18:30:05 +0200 Subject: [PATCH 09/43] DirectoryBlob: Use DiscContent for everything in ReadPartition --- Source/Core/DiscIO/DirectoryBlob.cpp | 36 ++++++---------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 8f000454e8..39b0595987 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -165,39 +165,17 @@ DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::strin SetDOLAndDiskType(std::move(dol_file)); BuildFST(); + + m_virtual_disc.emplace(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_disk_header.data()); + m_virtual_disc.emplace(DISKHEADERINFO_ADDRESS, sizeof(m_disk_header_info), + reinterpret_cast(m_disk_header_info.get())); + m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); + m_virtual_disc.emplace(m_dol_address, m_dol.size(), m_dol.data()); + m_virtual_disc.emplace(m_fst_address, m_fst_data.size(), m_fst_data.data()); } bool DirectoryBlobReader::ReadPartition(u64 offset, u64 length, u8* buffer) { - // header - if (offset < DISKHEADERINFO_ADDRESS) - { - WriteToBuffer(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_disk_header.data(), &offset, - &length, &buffer); - } - // header info - if (offset >= DISKHEADERINFO_ADDRESS && offset < APPLOADER_ADDRESS) - { - WriteToBuffer(DISKHEADERINFO_ADDRESS, sizeof(m_disk_header_info), (u8*)m_disk_header_info.get(), - &offset, &length, &buffer); - } - // apploader - if (offset >= APPLOADER_ADDRESS && offset < APPLOADER_ADDRESS + m_apploader.size()) - { - WriteToBuffer(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data(), &offset, &length, - &buffer); - } - // dol - if (offset >= m_dol_address && offset < m_dol_address + m_dol.size()) - { - WriteToBuffer(m_dol_address, m_dol.size(), m_dol.data(), &offset, &length, &buffer); - } - // fst - if (offset >= m_fst_address && offset < m_data_start_address) - { - WriteToBuffer(m_fst_address, m_fst_data.size(), m_fst_data.data(), &offset, &length, &buffer); - } - if (m_virtual_disc.empty()) return true; From 3f9eec9ae4d7d4285811ec5cea016f3edb418143 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 18:43:52 +0200 Subject: [PATCH 10/43] DirectoryBlob: Use DiscContent for ReadNonPartition too ReadPartition and ReadNonPartition are now unified into ReadInternal, with a parameter controlling whether the read is in a partition or not. --- Source/Core/DiscIO/DirectoryBlob.cpp | 75 +++++++--------------------- Source/Core/DiscIO/DirectoryBlob.h | 8 +-- 2 files changed, 20 insertions(+), 63 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 39b0595987..fa573d8d34 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -172,22 +172,32 @@ DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::strin m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); m_virtual_disc.emplace(m_dol_address, m_dol.size(), m_dol.data()); m_virtual_disc.emplace(m_fst_address, m_fst_data.size(), m_fst_data.data()); + + if (m_is_wii) + { + m_nonpartition_contents.emplace(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, + m_disk_header.data()); + m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), + reinterpret_cast(PARTITION_TABLE.data())); + // TODO: TMDs, tickets, more headers, the raw partition contents... + } } -bool DirectoryBlobReader::ReadPartition(u64 offset, u64 length, u8* buffer) +bool DirectoryBlobReader::ReadInternal(u64 offset, u64 length, u8* buffer, + const std::set& contents) { - if (m_virtual_disc.empty()) + if (contents.empty()) return true; // 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()) + std::set::const_iterator it = contents.lower_bound(DiscContent(offset)); + if (it->GetOffset() > offset && it != contents.begin()) --it; // zero fill to start of file data PadToAddress(it->GetOffset(), &offset, &length, &buffer); - while (it != m_virtual_disc.end() && length > 0) + while (it != contents.end() && length > 0) { _dbg_assert_(DVDINTERFACE, it->GetOffset() <= offset); if (!it->Read(&offset, &length, &buffer)) @@ -195,7 +205,7 @@ bool DirectoryBlobReader::ReadPartition(u64 offset, u64 length, u8* buffer) ++it; - if (it != m_virtual_disc.end()) + if (it != contents.end()) { _dbg_assert_(DVDINTERFACE, it->GetOffset() >= offset); PadToAddress(it->GetOffset(), &offset, &length, &buffer); @@ -205,35 +215,9 @@ bool DirectoryBlobReader::ReadPartition(u64 offset, u64 length, u8* buffer) return true; } -bool DirectoryBlobReader::ReadNonPartition(u64 offset, u64 length, u8* buffer) -{ - // header - if (offset < DISKHEADERINFO_ADDRESS) - { - WriteToBuffer(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_disk_header.data(), &offset, - &length, &buffer); - } - if (offset >= 0x40000) - { - WriteToBuffer(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), - reinterpret_cast(PARTITION_TABLE.data()), &offset, &length, &buffer); - } - - // TODO: TMDs, tickets, more headers, the partition contents... - - if (length > 0) - { - ERROR_LOG(DISCIO, "Unsupported raw read in DirectoryBlob at 0x%" PRIx64, offset); - return false; - } - - return true; -} - bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer) { - return m_is_wii ? ReadNonPartition(offset, length, buffer) : - ReadPartition(offset, length, buffer); + return ReadInternal(offset, length, buffer, m_is_wii ? m_nonpartition_contents : m_virtual_disc); } bool DirectoryBlobReader::SupportsReadWiiDecrypted() const @@ -246,7 +230,7 @@ bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 if (!m_is_wii || partition_offset != GAME_PARTITION_ADDRESS) return false; - return ReadPartition(offset, size, buffer); + return ReadInternal(offset, size, buffer, m_virtual_disc); } void DirectoryBlobReader::SetGameID(const std::string& id) @@ -386,29 +370,6 @@ void DirectoryBlobReader::BuildFST() Write32((u32)(m_fst_data.size() >> m_address_shift), 0x042c, &m_disk_header); } -void DirectoryBlobReader::WriteToBuffer(u64 source_start_address, u64 source_length, - const u8* source, u64* address, u64* length, - u8** buffer) const -{ - if (*length == 0) - return; - - _dbg_assert_(DVDINTERFACE, *address >= source_start_address); - - u64 source_offset = *address - source_start_address; - - if (source_offset < source_length) - { - size_t bytes_to_read = std::min(source_length - source_offset, *length); - - memcpy(*buffer, source + source_offset, bytes_to_read); - - *length -= bytes_to_read; - *buffer += bytes_to_read; - *address += bytes_to_read; - } -} - void DirectoryBlobReader::PadToAddress(u64 start_address, u64* address, u64* length, u8** buffer) const { diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index f3879c97f6..0d0a196be9 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -75,8 +75,7 @@ public: private: DirectoryBlobReader(File::IOFile dol_file, const std::string& root_directory); - bool ReadPartition(u64 offset, u64 length, u8* buffer); - bool ReadNonPartition(u64 offset, u64 length, u8* buffer); + bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); void SetDiskTypeWii(); void SetDiskTypeGC(); @@ -89,10 +88,6 @@ private: void BuildFST(); - // writing to read buffer - void WriteToBuffer(u64 source_start_address, u64 source_length, const u8* source, u64* address, - u64* length, u8** buffer) const; - void PadToAddress(u64 start_address, u64* address, u64* length, u8** buffer) const; void Write32(u32 data, u32 offset, std::vector* const buffer); @@ -107,6 +102,7 @@ private: std::string m_root_directory; std::set m_virtual_disc; + std::set m_nonpartition_contents; bool m_is_wii = false; From 02610d4b28f631880f0ed34c344095caaf3b48a4 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 18:56:09 +0200 Subject: [PATCH 11/43] DirectoryBlob: Use DISCIO instead of DVDINTERFACE for logging --- Source/Core/DiscIO/DirectoryBlob.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index fa573d8d34..849ceef2a4 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -199,7 +199,7 @@ bool DirectoryBlobReader::ReadInternal(u64 offset, u64 length, u8* buffer, while (it != contents.end() && length > 0) { - _dbg_assert_(DVDINTERFACE, it->GetOffset() <= offset); + _dbg_assert_(DISCIO, it->GetOffset() <= offset); if (!it->Read(&offset, &length, &buffer)) return false; @@ -207,7 +207,7 @@ bool DirectoryBlobReader::ReadInternal(u64 offset, u64 length, u8* buffer, if (it != contents.end()) { - _dbg_assert_(DVDINTERFACE, it->GetOffset() >= offset); + _dbg_assert_(DISCIO, it->GetOffset() >= offset); PadToAddress(it->GetOffset(), &offset, &length, &buffer); } } From 71578b468dda2e3d2425a909d873e1a3eb8dbef0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 22:11:31 +0200 Subject: [PATCH 12/43] DirectoryBlob: Support tickets and TMDs --- Source/Core/DiscIO/DirectoryBlob.cpp | 27 ++++++++++++++++++++++++++- Source/Core/DiscIO/DirectoryBlob.h | 8 ++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 849ceef2a4..ab33013b4c 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -31,6 +31,10 @@ namespace DiscIO { +static const DiscContent& AddFileToContents(std::set* contents, + const std::string& path, u64 offset, + u64 max_size = UINT64_MAX); + static u32 ComputeNameSize(const File::FSTEntry& parent_entry); static std::string ASCIIToUppercase(std::string str); static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); @@ -179,7 +183,20 @@ DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::strin m_disk_header.data()); m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), reinterpret_cast(PARTITION_TABLE.data())); - // TODO: TMDs, tickets, more headers, the raw partition contents... + + constexpr u32 TICKET_OFFSET = 0x0; + constexpr u32 TICKET_SIZE = 0x2a4; + constexpr u32 TMD_OFFSET = 0x2c0; + constexpr u32 MAX_TMD_SIZE = 0x49e4; + AddFileToContents(&m_nonpartition_contents, m_root_directory + "ticket.bin", + 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_nonpartition_contents.emplace(GAME_PARTITION_ADDRESS + TICKET_SIZE, sizeof(m_tmd_header), + reinterpret_cast(&m_tmd_header)); } } @@ -217,6 +234,8 @@ bool DirectoryBlobReader::ReadInternal(u64 offset, u64 length, u8* buffer, 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); } @@ -455,6 +474,12 @@ void DirectoryBlobReader::WriteDirectory(const File::FSTEntry& parent_entry, u32 } } +static const DiscContent& AddFileToContents(std::set* contents, + const std::string& path, u64 offset, u64 max_size) +{ + return *(contents->emplace(offset, std::min(File::GetSize(path), max_size), path).first); +} + static u32 ComputeNameSize(const File::FSTEntry& parent_entry) { u32 name_size = 0; diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 0d0a196be9..5e5eb0a50d 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -118,6 +118,13 @@ private: std::vector m_disk_header; #pragma pack(push, 1) + struct TMDHeader + { + u32 tmd_size; + u32 tmd_offset; + } m_tmd_header; + static_assert(sizeof(TMDHeader) == 8, "Wrong size for TMDHeader"); + struct SDiskHeaderInfo { u32 debug_monitor_size; @@ -144,6 +151,7 @@ private: unknown2 = 0; } }; + static_assert(sizeof(SDiskHeaderInfo) == 36, "Wrong size for SDiskHeaderInfo"); #pragma pack(pop) std::unique_ptr m_disk_header_info; From 4cc8d3091cab23c8d76646099266209f45c872bb Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 12:08:17 +0200 Subject: [PATCH 13/43] DirectoryBlob: Require header file (boot.bin) --- Source/Core/DiscIO/DirectoryBlob.cpp | 101 ++++++++++++++++----------- Source/Core/DiscIO/DirectoryBlob.h | 15 ++-- 2 files changed, 65 insertions(+), 51 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index ab33013b4c..49c0210be9 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -43,10 +43,9 @@ constexpr u8 ENTRY_SIZE = 0x0c; constexpr u8 FILE_ENTRY = 0; constexpr u8 DIRECTORY_ENTRY = 1; constexpr u64 DISKHEADER_ADDRESS = 0; +constexpr u64 NONPARTITION_DISKHEADER_SIZE = 0x100; constexpr u64 DISKHEADERINFO_ADDRESS = 0x440; constexpr u64 APPLOADER_ADDRESS = 0x2440; -constexpr size_t MAX_NAME_LENGTH = 0x3df; -constexpr size_t MAX_ID_LENGTH = 6; constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; @@ -138,19 +137,31 @@ static bool PathEndsWith(const std::string& path, const std::string& suffix) return true; } +bool DirectoryBlobReader::IsValidDirectoryBlob(const std::string& dol_path, + std::string* root_directory) +{ + if (!PathEndsWith(dol_path, "/sys/main.dol")) + return false; + + const size_t chars_to_remove = std::string("sys/main.dol").size(); + *root_directory = dol_path.substr(0, dol_path.size() - chars_to_remove); + + return File::GetSize(*root_directory + "sys/boot.bin") >= 0x20; +} + bool DirectoryBlobReader::IsValidDirectoryBlob(const std::string& dol_path) { - return PathEndsWith(dol_path, "/sys/main.dol"); + std::string root_directory; + return IsValidDirectoryBlob(dol_path, &root_directory); } std::unique_ptr DirectoryBlobReader::Create(File::IOFile dol, const std::string& dol_path) { - if (!dol || !IsValidDirectoryBlob(dol_path)) + std::string root_directory; + if (!dol || !IsValidDirectoryBlob(dol_path, &root_directory)) return nullptr; - const size_t chars_to_remove = std::string("sys/main.dol").size(); - const std::string root_directory = dol_path.substr(0, dol_path.size() - chars_to_remove); return std::unique_ptr( new DirectoryBlobReader(std::move(dol), root_directory)); } @@ -160,13 +171,11 @@ DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::strin m_disk_header(DISKHEADERINFO_ADDRESS), m_disk_header_info(std::make_unique()), m_fst_address(0), m_dol_address(0) { - // create the default disk header - SetGameID("AGBJ01"); - SetName("Default name"); + SetDiscHeaderAndDiscType(); // Setting the DOL relies on m_dol_address, which is set by SetApploader if (SetApploader(m_root_directory + "sys/apploader.img")) - SetDOLAndDiskType(std::move(dol_file)); + SetDOL(std::move(dol_file)); BuildFST(); @@ -179,8 +188,8 @@ DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::strin if (m_is_wii) { - m_nonpartition_contents.emplace(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, - m_disk_header.data()); + m_nonpartition_contents.emplace(DISKHEADER_ADDRESS, NONPARTITION_DISKHEADER_SIZE, + m_disk_header_nonpartition.data()); m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), reinterpret_cast(PARTITION_TABLE.data())); @@ -252,18 +261,6 @@ bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 return ReadInternal(offset, size, buffer, m_virtual_disc); } -void DirectoryBlobReader::SetGameID(const std::string& id) -{ - memcpy(m_disk_header.data(), id.c_str(), std::min(id.length(), MAX_ID_LENGTH)); -} - -void DirectoryBlobReader::SetName(const std::string& name) -{ - size_t length = std::min(name.length(), MAX_NAME_LENGTH); - memcpy(&m_disk_header[0x20], name.c_str(), length); - m_disk_header[length + 0x20] = 0; -} - BlobType DirectoryBlobReader::GetBlobType() const { return BlobType::DIRECTORY; @@ -281,22 +278,47 @@ u64 DirectoryBlobReader::GetDataSize() const return 0; } -void DirectoryBlobReader::SetDiskTypeWii() +void DirectoryBlobReader::SetDiscHeaderAndDiscType() { - Write32(0x5d1c9ea3, 0x18, &m_disk_header); - memset(&m_disk_header[0x1c], 0, 4); + const std::string boot_bin_path = m_root_directory + "sys/boot.bin"; + { + File::IOFile boot_bin(boot_bin_path, "rb"); + const u64 bytes_to_read = std::min(boot_bin.GetSize(), m_disk_header.size()); + if (!boot_bin.ReadBytes(m_disk_header.data(), bytes_to_read)) + ERROR_LOG(DISCIO, "Failed to read %s", boot_bin_path.c_str()); + } - m_is_wii = true; - m_address_shift = 2; -} + m_is_wii = Common::swap32(&m_disk_header[0x18]) == 0x5d1c9ea3; + const bool is_gc = Common::swap32(&m_disk_header[0x1c]) == 0xc2339f3d; + if (m_is_wii == is_gc) + ERROR_LOG(DISCIO, "Couldn't detect disc type based on %s", boot_bin_path.c_str()); -void DirectoryBlobReader::SetDiskTypeGC() -{ - memset(&m_disk_header[0x18], 0, 4); - Write32(0xc2339f3d, 0x1c, &m_disk_header); + m_address_shift = m_is_wii ? 2 : 0; - m_is_wii = false; - m_address_shift = 0; + if (m_is_wii) + { + m_disk_header_nonpartition.resize(NONPARTITION_DISKHEADER_SIZE); + + size_t header_bin_bytes_read; + const std::string header_bin_path = m_root_directory + "disc/header.bin"; + { + File::IOFile header_bin(header_bin_path, "rb"); + const u64 bytes_to_read = std::min(header_bin.GetSize(), NONPARTITION_DISKHEADER_SIZE); + header_bin.ReadArray(m_disk_header_nonpartition.data(), bytes_to_read, + &header_bin_bytes_read); + } + + // 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; + } } bool DirectoryBlobReader::SetApploader(const std::string& apploader) @@ -332,17 +354,12 @@ bool DirectoryBlobReader::SetApploader(const std::string& apploader) } } -void DirectoryBlobReader::SetDOLAndDiskType(File::IOFile dol_file) +void DirectoryBlobReader::SetDOL(File::IOFile dol_file) { m_dol.resize(dol_file.GetSize()); dol_file.Seek(0, SEEK_SET); dol_file.ReadBytes(m_dol.data(), m_dol.size()); - if (DolReader(std::move(dol_file)).IsWii()) - SetDiskTypeWii(); - else - SetDiskTypeGC(); - Write32((u32)(m_dol_address >> m_address_shift), 0x0420, &m_disk_header); // 32byte aligned (plus 0x20 padding) diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 5e5eb0a50d..8f9e17a225 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -55,6 +55,7 @@ private: class DirectoryBlobReader : public BlobReader { public: + static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* root_directory); static bool IsValidDirectoryBlob(const std::string& dol_path); static std::unique_ptr Create(File::IOFile dol, const std::string& dol_path); @@ -77,14 +78,9 @@ private: bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); - void SetDiskTypeWii(); - void SetDiskTypeGC(); - - void SetGameID(const std::string& id); - void SetName(const std::string&); - + void SetDiscHeaderAndDiscType(); bool SetApploader(const std::string& apploader); - void SetDOLAndDiskType(File::IOFile dol_file); + void SetDOL(File::IOFile dol_file); void BuildFST(); @@ -104,10 +100,10 @@ private: std::set m_virtual_disc; std::set m_nonpartition_contents; - bool m_is_wii = false; + bool m_is_wii; // GameCube has no shift, Wii has 2 bit shift - u32 m_address_shift = 0; + u32 m_address_shift; // first address on disk containing file data u64 m_data_start_address; @@ -116,6 +112,7 @@ private: std::vector m_fst_data; std::vector m_disk_header; + std::vector m_disk_header_nonpartition; #pragma pack(push, 1) struct TMDHeader From a6bbf7e21b7ae1c0d11feb3acb88875b7b6e30ca Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 12:45:34 +0200 Subject: [PATCH 14/43] DirectoryBlob: Don't keep DOL in memory --- Source/Core/DiscIO/Blob.cpp | 2 +- Source/Core/DiscIO/DirectoryBlob.cpp | 22 +++++++++------------- Source/Core/DiscIO/DirectoryBlob.h | 7 +++---- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp index a27f6861e1..7f4eeccb1c 100644 --- a/Source/Core/DiscIO/Blob.cpp +++ b/Source/Core/DiscIO/Blob.cpp @@ -204,7 +204,7 @@ std::unique_ptr CreateBlobReader(const std::string& filename) return WbfsFileReader::Create(std::move(file), filename); default: if (DirectoryBlobReader::IsValidDirectoryBlob(filename)) - return DirectoryBlobReader::Create(std::move(file), filename); + return DirectoryBlobReader::Create(filename); return PlainFileReader::Create(std::move(file)); } diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 49c0210be9..04c6d352b0 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -155,18 +155,16 @@ bool DirectoryBlobReader::IsValidDirectoryBlob(const std::string& dol_path) return IsValidDirectoryBlob(dol_path, &root_directory); } -std::unique_ptr DirectoryBlobReader::Create(File::IOFile dol, - const std::string& dol_path) +std::unique_ptr DirectoryBlobReader::Create(const std::string& dol_path) { std::string root_directory; - if (!dol || !IsValidDirectoryBlob(dol_path, &root_directory)) + if (!IsValidDirectoryBlob(dol_path, &root_directory)) return nullptr; - return std::unique_ptr( - new DirectoryBlobReader(std::move(dol), root_directory)); + return std::unique_ptr(new DirectoryBlobReader(root_directory)); } -DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::string& root_directory) +DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) : m_root_directory(root_directory), m_data_start_address(UINT64_MAX), m_disk_header(DISKHEADERINFO_ADDRESS), m_disk_header_info(std::make_unique()), m_fst_address(0), m_dol_address(0) @@ -175,7 +173,7 @@ DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::strin // Setting the DOL relies on m_dol_address, which is set by SetApploader if (SetApploader(m_root_directory + "sys/apploader.img")) - SetDOL(std::move(dol_file)); + SetDOL(); BuildFST(); @@ -183,7 +181,6 @@ DirectoryBlobReader::DirectoryBlobReader(File::IOFile dol_file, const std::strin m_virtual_disc.emplace(DISKHEADERINFO_ADDRESS, sizeof(m_disk_header_info), reinterpret_cast(m_disk_header_info.get())); m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); - m_virtual_disc.emplace(m_dol_address, m_dol.size(), m_dol.data()); m_virtual_disc.emplace(m_fst_address, m_fst_data.size(), m_fst_data.data()); if (m_is_wii) @@ -354,16 +351,15 @@ bool DirectoryBlobReader::SetApploader(const std::string& apploader) } } -void DirectoryBlobReader::SetDOL(File::IOFile dol_file) +void DirectoryBlobReader::SetDOL() { - m_dol.resize(dol_file.GetSize()); - dol_file.Seek(0, SEEK_SET); - dol_file.ReadBytes(m_dol.data(), m_dol.size()); + const DiscContent& dol = + AddFileToContents(&m_virtual_disc, m_root_directory + "sys/main.dol", m_dol_address); Write32((u32)(m_dol_address >> m_address_shift), 0x0420, &m_disk_header); // 32byte aligned (plus 0x20 padding) - m_fst_address = Common::AlignUp(m_dol_address + m_dol.size() + 0x20, 0x20ull); + m_fst_address = Common::AlignUp(m_dol_address + dol.GetSize() + 0x20, 0x20ull); } void DirectoryBlobReader::BuildFST() diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 8f9e17a225..ab42bd159b 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -57,7 +57,7 @@ class DirectoryBlobReader : public BlobReader public: static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* root_directory); static bool IsValidDirectoryBlob(const std::string& dol_path); - static std::unique_ptr Create(File::IOFile dol, const std::string& dol_path); + static std::unique_ptr Create(const std::string& dol_path); // We do not allow copying, because it might mess up the pointers inside DiscContents DirectoryBlobReader(const DirectoryBlobReader&) = delete; @@ -74,13 +74,13 @@ public: u64 GetDataSize() const override; private: - DirectoryBlobReader(File::IOFile dol_file, const std::string& root_directory); + explicit DirectoryBlobReader(const std::string& root_directory); bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); void SetDiscHeaderAndDiscType(); bool SetApploader(const std::string& apploader); - void SetDOL(File::IOFile dol_file); + void SetDOL(); void BuildFST(); @@ -153,7 +153,6 @@ private: std::unique_ptr m_disk_header_info; std::vector m_apploader; - std::vector m_dol; u64 m_fst_address; u64 m_dol_address; From 251828ccc0d449ff9da1c823c7fb5aee6c4ace73 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 12:56:36 +0200 Subject: [PATCH 15/43] Don't check validity twice when creating DirectoryBlob --- Source/Core/DiscIO/Blob.cpp | 4 ++-- Source/Core/DiscIO/DirectoryBlob.cpp | 9 +-------- Source/Core/DiscIO/DirectoryBlob.h | 2 -- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp index 7f4eeccb1c..5e603610b2 100644 --- a/Source/Core/DiscIO/Blob.cpp +++ b/Source/Core/DiscIO/Blob.cpp @@ -203,8 +203,8 @@ std::unique_ptr CreateBlobReader(const std::string& filename) case WBFS_MAGIC: return WbfsFileReader::Create(std::move(file), filename); default: - if (DirectoryBlobReader::IsValidDirectoryBlob(filename)) - return DirectoryBlobReader::Create(filename); + if (auto directory_blob = DirectoryBlobReader::Create(filename)) + return std::move(directory_blob); return PlainFileReader::Create(std::move(file)); } diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 04c6d352b0..df8dfe59bb 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -137,8 +137,7 @@ static bool PathEndsWith(const std::string& path, const std::string& suffix) return true; } -bool DirectoryBlobReader::IsValidDirectoryBlob(const std::string& dol_path, - std::string* root_directory) +static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* root_directory) { if (!PathEndsWith(dol_path, "/sys/main.dol")) return false; @@ -149,12 +148,6 @@ bool DirectoryBlobReader::IsValidDirectoryBlob(const std::string& dol_path, return File::GetSize(*root_directory + "sys/boot.bin") >= 0x20; } -bool DirectoryBlobReader::IsValidDirectoryBlob(const std::string& dol_path) -{ - std::string root_directory; - return IsValidDirectoryBlob(dol_path, &root_directory); -} - std::unique_ptr DirectoryBlobReader::Create(const std::string& dol_path) { std::string root_directory; diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index ab42bd159b..1e0056f03c 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -55,8 +55,6 @@ private: class DirectoryBlobReader : public BlobReader { public: - static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* root_directory); - static bool IsValidDirectoryBlob(const std::string& dol_path); static std::unique_ptr Create(const std::string& dol_path); // We do not allow copying, because it might mess up the pointers inside DiscContents From 975b2b40fab867f95acb7e5266996e8f17e3e3fd Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 21:39:26 +0200 Subject: [PATCH 16/43] DirectoryBlob: Support bi2.bin --- Source/Core/DiscIO/DirectoryBlob.cpp | 7 +++---- Source/Core/DiscIO/DirectoryBlob.h | 29 ---------------------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index df8dfe59bb..d2675a0f65 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -159,8 +159,7 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) : m_root_directory(root_directory), m_data_start_address(UINT64_MAX), - m_disk_header(DISKHEADERINFO_ADDRESS), - m_disk_header_info(std::make_unique()), m_fst_address(0), m_dol_address(0) + m_disk_header(DISKHEADERINFO_ADDRESS), m_fst_address(0), m_dol_address(0) { SetDiscHeaderAndDiscType(); @@ -171,8 +170,8 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) BuildFST(); m_virtual_disc.emplace(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_disk_header.data()); - m_virtual_disc.emplace(DISKHEADERINFO_ADDRESS, sizeof(m_disk_header_info), - reinterpret_cast(m_disk_header_info.get())); + AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", DISKHEADERINFO_ADDRESS, + APPLOADER_ADDRESS - DISKHEADERINFO_ADDRESS); m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); m_virtual_disc.emplace(m_fst_address, m_fst_data.size(), m_fst_data.data()); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 1e0056f03c..c7057ecdb2 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -119,36 +119,7 @@ private: u32 tmd_offset; } m_tmd_header; static_assert(sizeof(TMDHeader) == 8, "Wrong size for TMDHeader"); - - struct SDiskHeaderInfo - { - u32 debug_monitor_size; - u32 simulated_mem_size; - u32 arg_offset; - u32 debug_flag; - u32 track_location; - u32 track_size; - u32 country_code; - u32 unknown; - u32 unknown2; - - // All the data is byteswapped - SDiskHeaderInfo() - { - debug_monitor_size = 0; - simulated_mem_size = 0; - arg_offset = 0; - debug_flag = 0; - track_location = 0; - track_size = 0; - country_code = 0; - unknown = 0; - unknown2 = 0; - } - }; - static_assert(sizeof(SDiskHeaderInfo) == 36, "Wrong size for SDiskHeaderInfo"); #pragma pack(pop) - std::unique_ptr m_disk_header_info; std::vector m_apploader; From 8afa230787b7ea945841cb28c149d4c7db31f593 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 21:42:26 +0200 Subject: [PATCH 17/43] DirectoryBlob: Rename DISKHEADERINFO_ADDRESS to BI2_ADDRESS Because DISKHEADERINFO is too easy confuse with DISKHEADER. Also adding BI2_SIZE and DISKHEADER_SIZE contants. --- Source/Core/DiscIO/DirectoryBlob.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index d2675a0f65..5d5bafb01a 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -43,8 +43,10 @@ constexpr u8 ENTRY_SIZE = 0x0c; constexpr u8 FILE_ENTRY = 0; constexpr u8 DIRECTORY_ENTRY = 1; constexpr u64 DISKHEADER_ADDRESS = 0; +constexpr u64 DISKHEADER_SIZE = 0x440; constexpr u64 NONPARTITION_DISKHEADER_SIZE = 0x100; -constexpr u64 DISKHEADERINFO_ADDRESS = 0x440; +constexpr u64 BI2_ADDRESS = 0x440; +constexpr u64 BI2_SIZE = 0x2000; constexpr u64 APPLOADER_ADDRESS = 0x2440; constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; @@ -159,7 +161,7 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) : m_root_directory(root_directory), m_data_start_address(UINT64_MAX), - m_disk_header(DISKHEADERINFO_ADDRESS), m_fst_address(0), m_dol_address(0) + m_disk_header(DISKHEADER_SIZE), m_fst_address(0), m_dol_address(0) { SetDiscHeaderAndDiscType(); @@ -169,9 +171,8 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) BuildFST(); - m_virtual_disc.emplace(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_disk_header.data()); - AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", DISKHEADERINFO_ADDRESS, - APPLOADER_ADDRESS - DISKHEADERINFO_ADDRESS); + m_virtual_disc.emplace(DISKHEADER_ADDRESS, DISKHEADER_SIZE, m_disk_header.data()); + AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); m_virtual_disc.emplace(m_fst_address, m_fst_data.size(), m_fst_data.data()); From c73f6b6c260d4db8c84b3eb8eac17ccc491028eb Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 08:46:21 +0200 Subject: [PATCH 18/43] DirectoryBlob: Add ReadFileToVector function --- Source/Core/DiscIO/DirectoryBlob.cpp | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 5d5bafb01a..616540d9a3 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -35,6 +35,10 @@ static const DiscContent& AddFileToContents(std::set* contents, const std::string& path, u64 offset, u64 max_size = UINT64_MAX); +// Reads as many bytes as the vector fits (or less, if the file is smaller). +// Returns the number of bytes read. +static size_t ReadFileToVector(const std::string& path, std::vector* vector); + static u32 ComputeNameSize(const File::FSTEntry& parent_entry); static std::string ASCIIToUppercase(std::string str); static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); @@ -271,12 +275,8 @@ u64 DirectoryBlobReader::GetDataSize() const void DirectoryBlobReader::SetDiscHeaderAndDiscType() { const std::string boot_bin_path = m_root_directory + "sys/boot.bin"; - { - File::IOFile boot_bin(boot_bin_path, "rb"); - const u64 bytes_to_read = std::min(boot_bin.GetSize(), m_disk_header.size()); - if (!boot_bin.ReadBytes(m_disk_header.data(), bytes_to_read)) - ERROR_LOG(DISCIO, "Failed to read %s", boot_bin_path.c_str()); - } + 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_is_wii = Common::swap32(&m_disk_header[0x18]) == 0x5d1c9ea3; const bool is_gc = Common::swap32(&m_disk_header[0x1c]) == 0xc2339f3d; @@ -288,15 +288,8 @@ void DirectoryBlobReader::SetDiscHeaderAndDiscType() if (m_is_wii) { m_disk_header_nonpartition.resize(NONPARTITION_DISKHEADER_SIZE); - - size_t header_bin_bytes_read; - const std::string header_bin_path = m_root_directory + "disc/header.bin"; - { - File::IOFile header_bin(header_bin_path, "rb"); - const u64 bytes_to_read = std::min(header_bin.GetSize(), NONPARTITION_DISKHEADER_SIZE); - header_bin.ReadArray(m_disk_header_nonpartition.data(), bytes_to_read, - &header_bin_bytes_read); - } + 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, @@ -486,6 +479,14 @@ static const DiscContent& AddFileToContents(std::set* contents, return *(contents->emplace(offset, std::min(File::GetSize(path), max_size), path).first); } +static size_t ReadFileToVector(const std::string& path, std::vector* vector) +{ + File::IOFile file(path, "rb"); + size_t bytes_read; + file.ReadArray(vector->data(), std::min(file.GetSize(), vector->size()), &bytes_read); + return bytes_read; +} + static u32 ComputeNameSize(const File::FSTEntry& parent_entry) { u32 name_size = 0; From 8747b1b6ab2e579ccc78745c1b7252014f92252e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 09:53:36 +0200 Subject: [PATCH 19/43] DirectoryBlob: Support region.bin --- Source/Core/DiscIO/DirectoryBlob.cpp | 23 +++++++++++++++++++++++ Source/Core/DiscIO/DirectoryBlob.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 616540d9a3..3cfbd0fc38 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -52,6 +52,8 @@ constexpr u64 NONPARTITION_DISKHEADER_SIZE = 0x100; constexpr u64 BI2_ADDRESS = 0x440; constexpr u64 BI2_SIZE = 0x2000; constexpr u64 APPLOADER_ADDRESS = 0x2440; +constexpr u64 WII_REGION_DATA_ADDRESS = 0x4E000; +constexpr u64 WII_REGION_DATA_SIZE = 0x20; constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; @@ -187,6 +189,10 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), reinterpret_cast(PARTITION_TABLE.data())); + SetWiiRegionData(); + m_nonpartition_contents.emplace(WII_REGION_DATA_ADDRESS, WII_REGION_DATA_SIZE, + m_wii_region_data.data()); + constexpr u32 TICKET_OFFSET = 0x0; constexpr u32 TICKET_SIZE = 0x2a4; constexpr u32 TMD_OFFSET = 0x2c0; @@ -304,6 +310,23 @@ void DirectoryBlobReader::SetDiscHeaderAndDiscType() } } +void DirectoryBlobReader::SetWiiRegionData() +{ + m_wii_region_data.resize(0x10, 0x00); + m_wii_region_data.resize(0x20, 0x80); + + // 0xFF is an arbitrarily picked value. Note that we can't use 0x00, because that means NTSC-J + constexpr u32 INVALID_REGION = 0xFF; + Write32(INVALID_REGION, 0, &m_wii_region_data); + + const std::string region_bin_path = m_root_directory + "disc/region.bin"; + const size_t bytes_read = ReadFileToVector(region_bin_path, &m_wii_region_data); + if (bytes_read < 0x4) + ERROR_LOG(DISCIO, "Couldn't read region from %s", region_bin_path.c_str()); + else if (bytes_read < 0x20) + ERROR_LOG(DISCIO, "Couldn't read age ratings from %s", region_bin_path.c_str()); +} + bool DirectoryBlobReader::SetApploader(const std::string& apploader) { if (!apploader.empty()) diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index c7057ecdb2..37e34f0061 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -77,6 +77,7 @@ private: bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); void SetDiscHeaderAndDiscType(); + void SetWiiRegionData(); bool SetApploader(const std::string& apploader); void SetDOL(); @@ -111,6 +112,7 @@ private: std::vector m_disk_header; std::vector m_disk_header_nonpartition; + std::vector m_wii_region_data; #pragma pack(push, 1) struct TMDHeader From 1258d18f214d036d03d3507b86933f1d4638f6cf Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:27:46 +0200 Subject: [PATCH 20/43] DirectoryBlob: Restructure SetApploader --- Source/Core/DiscIO/DirectoryBlob.cpp | 47 ++++++++++++++++------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 3cfbd0fc38..f7fc9785bc 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -329,35 +329,42 @@ void DirectoryBlobReader::SetWiiRegionData() bool DirectoryBlobReader::SetApploader(const std::string& apploader) { - if (!apploader.empty()) + bool success = false; + + if (apploader.empty()) + { + m_apploader.resize(0x20); + // Make sure BS2 HLE doesn't try to run the apploader + Write32(static_cast(-1), 0x10, &m_apploader); + } + else { std::string data; if (!File::ReadFileToString(apploader, data)) { PanicAlertT("Apploader unable to load from file"); - return false; } - size_t apploader_size = 0x20 + Common::swap32(*(u32*)&data.data()[0x14]) + - Common::swap32(*(u32*)&data.data()[0x18]); - if (apploader_size != data.size()) + else { - PanicAlertT("Apploader is the wrong size...is it really an apploader?"); - return false; - } - m_apploader.resize(apploader_size); - std::copy(data.begin(), data.end(), m_apploader.begin()); + const size_t apploader_size = 0x20 + Common::swap32(*(u32*)&data.data()[0x14]) + + Common::swap32(*(u32*)&data.data()[0x18]); + if (apploader_size != data.size()) + { + PanicAlertT("Apploader is the wrong size...is it really an apploader?"); + } + else + { + m_apploader.resize(apploader_size); + std::copy(data.begin(), data.end(), m_apploader.begin()); - // 32byte aligned (plus 0x20 padding) - m_dol_address = Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); - return true; - } - else - { - m_apploader.resize(0x20); - // Make sure BS2 HLE doesn't try to run the apploader - Write32(static_cast(-1), 0x10, &m_apploader); - return false; + // 32byte aligned (plus 0x20 padding) + m_dol_address = Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); + success = true; + } + } } + + return success; } void DirectoryBlobReader::SetDOL() From 5a00bda490aa49a5baaeba652087f7e7794f9c42 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:37:06 +0200 Subject: [PATCH 21/43] DirectoryBlob: Move content emplacement out of the constructor --- Source/Core/DiscIO/DirectoryBlob.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index f7fc9785bc..7b6fc1ff64 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -171,27 +171,20 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) { SetDiscHeaderAndDiscType(); + AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); + // Setting the DOL relies on m_dol_address, which is set by SetApploader if (SetApploader(m_root_directory + "sys/apploader.img")) SetDOL(); BuildFST(); - m_virtual_disc.emplace(DISKHEADER_ADDRESS, DISKHEADER_SIZE, m_disk_header.data()); - AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); - m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); - m_virtual_disc.emplace(m_fst_address, m_fst_data.size(), m_fst_data.data()); - if (m_is_wii) { - m_nonpartition_contents.emplace(DISKHEADER_ADDRESS, NONPARTITION_DISKHEADER_SIZE, - m_disk_header_nonpartition.data()); m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), reinterpret_cast(PARTITION_TABLE.data())); SetWiiRegionData(); - m_nonpartition_contents.emplace(WII_REGION_DATA_ADDRESS, WII_REGION_DATA_SIZE, - m_wii_region_data.data()); constexpr u32 TICKET_OFFSET = 0x0; constexpr u32 TICKET_SIZE = 0x2a4; @@ -284,6 +277,8 @@ void DirectoryBlobReader::SetDiscHeaderAndDiscType() 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_is_wii = Common::swap32(&m_disk_header[0x18]) == 0x5d1c9ea3; const bool is_gc = Common::swap32(&m_disk_header[0x1c]) == 0xc2339f3d; if (m_is_wii == is_gc) @@ -307,6 +302,9 @@ void DirectoryBlobReader::SetDiscHeaderAndDiscType() 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()); } } @@ -325,6 +323,9 @@ void DirectoryBlobReader::SetWiiRegionData() ERROR_LOG(DISCIO, "Couldn't read region from %s", region_bin_path.c_str()); else if (bytes_read < 0x20) ERROR_LOG(DISCIO, "Couldn't read age ratings from %s", region_bin_path.c_str()); + + m_nonpartition_contents.emplace(WII_REGION_DATA_ADDRESS, WII_REGION_DATA_SIZE, + m_wii_region_data.data()); } bool DirectoryBlobReader::SetApploader(const std::string& apploader) @@ -364,6 +365,7 @@ bool DirectoryBlobReader::SetApploader(const std::string& apploader) } } + m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); return success; } @@ -416,6 +418,8 @@ void DirectoryBlobReader::BuildFST() Write32((u32)(m_fst_address >> m_address_shift), 0x0424, &m_disk_header); 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(m_fst_address, m_fst_data.size(), m_fst_data.data()); } void DirectoryBlobReader::PadToAddress(u64 start_address, u64* address, u64* length, From c4879aa48dd29928e64516d4367be9328700989d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:38:59 +0200 Subject: [PATCH 22/43] DirectoryBlob: Split out setting TMD and ticket to new function --- Source/Core/DiscIO/DirectoryBlob.cpp | 31 +++++++++++++++------------- Source/Core/DiscIO/DirectoryBlob.h | 1 + 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 7b6fc1ff64..6392651edd 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -185,20 +185,7 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) reinterpret_cast(PARTITION_TABLE.data())); SetWiiRegionData(); - - constexpr u32 TICKET_OFFSET = 0x0; - constexpr u32 TICKET_SIZE = 0x2a4; - constexpr u32 TMD_OFFSET = 0x2c0; - constexpr u32 MAX_TMD_SIZE = 0x49e4; - AddFileToContents(&m_nonpartition_contents, m_root_directory + "ticket.bin", - 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_nonpartition_contents.emplace(GAME_PARTITION_ADDRESS + TICKET_SIZE, sizeof(m_tmd_header), - reinterpret_cast(&m_tmd_header)); + SetTMDAndTicket(); } } @@ -328,6 +315,22 @@ void DirectoryBlobReader::SetWiiRegionData() m_wii_region_data.data()); } +void DirectoryBlobReader::SetTMDAndTicket() +{ + constexpr u32 TICKET_OFFSET = 0x0; + constexpr u32 TICKET_SIZE = 0x2a4; + constexpr u32 TMD_OFFSET = 0x2c0; + constexpr u32 MAX_TMD_SIZE = 0x49e4; + AddFileToContents(&m_nonpartition_contents, m_root_directory + "ticket.bin", + 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_nonpartition_contents.emplace(GAME_PARTITION_ADDRESS + TICKET_SIZE, sizeof(m_tmd_header), + reinterpret_cast(&m_tmd_header)); +} + bool DirectoryBlobReader::SetApploader(const std::string& apploader) { bool success = false; diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 37e34f0061..efb865c124 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -78,6 +78,7 @@ private: void SetDiscHeaderAndDiscType(); void SetWiiRegionData(); + void SetTMDAndTicket(); bool SetApploader(const std::string& apploader); void SetDOL(); From b28ec0b7eed764c4d642f9e9a1013bc05a401e65 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:41:49 +0200 Subject: [PATCH 23/43] DirectoryBlob: Split out setting partition table to new function --- Source/Core/DiscIO/DirectoryBlob.cpp | 20 ++++++++++++-------- Source/Core/DiscIO/DirectoryBlob.h | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 6392651edd..16b5ac0de9 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -54,12 +54,7 @@ constexpr u64 BI2_SIZE = 0x2000; constexpr u64 APPLOADER_ADDRESS = 0x2440; constexpr u64 WII_REGION_DATA_ADDRESS = 0x4E000; constexpr u64 WII_REGION_DATA_SIZE = 0x20; - constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; -constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; -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_content_source(path) @@ -181,9 +176,7 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) if (m_is_wii) { - m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), - reinterpret_cast(PARTITION_TABLE.data())); - + SetPartitionTable(); SetWiiRegionData(); SetTMDAndTicket(); } @@ -295,6 +288,17 @@ void DirectoryBlobReader::SetDiscHeaderAndDiscType() } } +void DirectoryBlobReader::SetPartitionTable() +{ + constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; + static 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}}; + + m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), + reinterpret_cast(PARTITION_TABLE.data())); +} + void DirectoryBlobReader::SetWiiRegionData() { m_wii_region_data.resize(0x10, 0x00); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index efb865c124..da7cddbf5c 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -77,6 +77,7 @@ private: bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); void SetDiscHeaderAndDiscType(); + void SetPartitionTable(); void SetWiiRegionData(); void SetTMDAndTicket(); bool SetApploader(const std::string& apploader); From 31d8322c5a0732ae631ee6f8226c6b7c5527cff5 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 11:24:11 +0200 Subject: [PATCH 24/43] DirectoryBlob: Don't use member variables for addresses Now it's clearer that SetDOL depends on SetApploader and BuildFST depends on SetDOL. As a side note, we now load the DOL even if there's no apploader. (I don't think it matters whether we do it, but it was easier to implement this way.) --- Source/Core/DiscIO/DirectoryBlob.cpp | 44 ++++++++++------------------ Source/Core/DiscIO/DirectoryBlob.h | 15 ++++------ 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 16b5ac0de9..7243d23b97 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -161,18 +161,13 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri } DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) - : m_root_directory(root_directory), m_data_start_address(UINT64_MAX), - m_disk_header(DISKHEADER_SIZE), m_fst_address(0), m_dol_address(0) + : m_root_directory(root_directory), m_disk_header(DISKHEADER_SIZE) { SetDiscHeaderAndDiscType(); AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); - // Setting the DOL relies on m_dol_address, which is set by SetApploader - if (SetApploader(m_root_directory + "sys/apploader.img")) - SetDOL(); - - BuildFST(); + BuildFST(SetDOL(SetApploader(m_root_directory + "sys/apploader.img"))); if (m_is_wii) { @@ -335,10 +330,8 @@ void DirectoryBlobReader::SetTMDAndTicket() reinterpret_cast(&m_tmd_header)); } -bool DirectoryBlobReader::SetApploader(const std::string& apploader) +u64 DirectoryBlobReader::SetApploader(const std::string& apploader) { - bool success = false; - if (apploader.empty()) { m_apploader.resize(0x20); @@ -364,30 +357,28 @@ bool DirectoryBlobReader::SetApploader(const std::string& apploader) { m_apploader.resize(apploader_size); std::copy(data.begin(), data.end(), m_apploader.begin()); - - // 32byte aligned (plus 0x20 padding) - m_dol_address = Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); - success = true; } } } m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); - return success; + + // Return DOL address, 32 byte aligned (plus 32 byte padding) + return Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); } -void DirectoryBlobReader::SetDOL() +u64 DirectoryBlobReader::SetDOL(u64 dol_address) { const DiscContent& dol = - AddFileToContents(&m_virtual_disc, m_root_directory + "sys/main.dol", m_dol_address); + AddFileToContents(&m_virtual_disc, m_root_directory + "sys/main.dol", dol_address); - Write32((u32)(m_dol_address >> m_address_shift), 0x0420, &m_disk_header); + Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disk_header); - // 32byte aligned (plus 0x20 padding) - m_fst_address = Common::AlignUp(m_dol_address + dol.GetSize() + 0x20, 0x20ull); + // Return FST address, 32 byte aligned (plus 32 byte padding) + return Common::AlignUp(dol_address + dol.GetSize() + 0x20, 0x20ull); } -void DirectoryBlobReader::BuildFST() +void DirectoryBlobReader::BuildFST(u64 fst_address) { m_fst_data.clear(); @@ -401,13 +392,8 @@ void DirectoryBlobReader::BuildFST() m_fst_name_offset = total_entries * ENTRY_SIZE; // offset of name table in FST m_fst_data.resize(m_fst_name_offset + name_table_size); - // if FST hasn't been assigned (ie no apploader/dol setup), set to default - if (m_fst_address == 0) - m_fst_address = APPLOADER_ADDRESS + 0x2000; - // 32 KiB aligned start of data on disk - m_data_start_address = Common::AlignUp(m_fst_address + m_fst_data.size(), 0x8000ull); - u64 current_data_address = m_data_start_address; + u64 current_data_address = Common::AlignUp(fst_address + m_fst_data.size(), 0x8000ull); u32 fst_offset = 0; // Offset within FST data u32 name_offset = 0; // Offset within name table @@ -422,11 +408,11 @@ void DirectoryBlobReader::BuildFST() _assert_(Common::AlignUp(name_offset, 1ull << m_address_shift) == name_table_size); // write FST size and location - Write32((u32)(m_fst_address >> m_address_shift), 0x0424, &m_disk_header); + Write32((u32)(fst_address >> m_address_shift), 0x0424, &m_disk_header); 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(m_fst_address, m_fst_data.size(), m_fst_data.data()); + m_virtual_disc.emplace(fst_address, m_fst_data.size(), m_fst_data.data()); } void DirectoryBlobReader::PadToAddress(u64 start_address, u64* address, u64* length, diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index da7cddbf5c..b1c560a83d 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -80,10 +80,13 @@ private: void SetPartitionTable(); void SetWiiRegionData(); void SetTMDAndTicket(); - bool SetApploader(const std::string& apploader); - void SetDOL(); - void BuildFST(); + // Returns DOL address + u64 SetApploader(const std::string& apploader); + // Returns FST address + u64 SetDOL(u64 dol_address); + + void BuildFST(u64 fst_address); void PadToAddress(u64 start_address, u64* address, u64* length, u8** buffer) const; @@ -106,9 +109,6 @@ private: // GameCube has no shift, Wii has 2 bit shift u32 m_address_shift; - // first address on disk containing file data - u64 m_data_start_address; - u64 m_fst_name_offset; std::vector m_fst_data; @@ -126,9 +126,6 @@ private: #pragma pack(pop) std::vector m_apploader; - - u64 m_fst_address; - u64 m_dol_address; }; } // namespace From ef39b4da4611169bab695d3943df794430cd7c45 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 11:54:41 +0200 Subject: [PATCH 25/43] DirectoryBlob: Improve SetApploader The code gets simpler by using IOFile instead of ReadFileToString. Also, we now write -1 in all cases where loading fails. --- Source/Core/DiscIO/DirectoryBlob.cpp | 47 +++++++++++++--------------- Source/Core/DiscIO/DirectoryBlob.h | 2 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 7243d23b97..004cc46a82 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -167,7 +167,7 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); - BuildFST(SetDOL(SetApploader(m_root_directory + "sys/apploader.img"))); + BuildFST(SetDOL(SetApploader())); if (m_is_wii) { @@ -330,36 +330,33 @@ void DirectoryBlobReader::SetTMDAndTicket() reinterpret_cast(&m_tmd_header)); } -u64 DirectoryBlobReader::SetApploader(const std::string& apploader) +u64 DirectoryBlobReader::SetApploader() { - if (apploader.empty()) + bool success = false; + + const std::string path = m_root_directory + "sys/apploader.img"; + File::IOFile file(path, "rb"); + m_apploader.resize(file.GetSize()); + if (m_apploader.size() < 0x20 || !file.ReadBytes(m_apploader.data(), m_apploader.size())) + { + ERROR_LOG(DISCIO, "%s couldn't be accessed or is too small", path.c_str()); + } + else + { + const size_t apploader_size = 0x20 + Common::swap32(*(u32*)&m_apploader[0x14]) + + Common::swap32(*(u32*)&m_apploader[0x18]); + if (apploader_size != m_apploader.size()) + ERROR_LOG(DISCIO, "%s is the wrong size... Is it really an apploader?", path.c_str()); + else + success = true; + } + + if (!success) { m_apploader.resize(0x20); // Make sure BS2 HLE doesn't try to run the apploader Write32(static_cast(-1), 0x10, &m_apploader); } - else - { - std::string data; - if (!File::ReadFileToString(apploader, data)) - { - PanicAlertT("Apploader unable to load from file"); - } - else - { - const size_t apploader_size = 0x20 + Common::swap32(*(u32*)&data.data()[0x14]) + - Common::swap32(*(u32*)&data.data()[0x18]); - if (apploader_size != data.size()) - { - PanicAlertT("Apploader is the wrong size...is it really an apploader?"); - } - else - { - m_apploader.resize(apploader_size); - std::copy(data.begin(), data.end(), m_apploader.begin()); - } - } - } m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index b1c560a83d..3e7048b3fa 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -82,7 +82,7 @@ private: void SetTMDAndTicket(); // Returns DOL address - u64 SetApploader(const std::string& apploader); + u64 SetApploader(); // Returns FST address u64 SetDOL(u64 dol_address); From 0d4ad0e39e633d911cced0ecb13b90d873c78271 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 13:02:16 +0200 Subject: [PATCH 26/43] DirectoryBlob: Remove m_fst_name_offset --- Source/Core/DiscIO/DirectoryBlob.cpp | 21 ++++++++++++--------- Source/Core/DiscIO/DirectoryBlob.h | 5 ++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 004cc46a82..be540b30ef 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -386,8 +386,8 @@ void DirectoryBlobReader::BuildFST(u64 fst_address) u32 name_table_size = Common::AlignUp(ComputeNameSize(rootEntry), 1ull << m_address_shift); u64 total_entries = rootEntry.size + 1; // The root entry itself isn't counted in rootEntry.size - m_fst_name_offset = total_entries * ENTRY_SIZE; // offset of name table in FST - m_fst_data.resize(m_fst_name_offset + name_table_size); + const u64 name_table_offset = total_entries * ENTRY_SIZE; + m_fst_data.resize(name_table_offset + name_table_size); // 32 KiB aligned start of data on disk u64 current_data_address = Common::AlignUp(fst_address + m_fst_data.size(), 0x8000ull); @@ -399,7 +399,8 @@ void DirectoryBlobReader::BuildFST(u64 fst_address) // write root entry WriteEntryData(&fst_offset, DIRECTORY_ENTRY, 0, 0, total_entries, m_address_shift); - WriteDirectory(rootEntry, &fst_offset, &name_offset, ¤t_data_address, root_offset); + WriteDirectory(rootEntry, &fst_offset, &name_offset, ¤t_data_address, root_offset, + name_table_offset); // overflow check, compare the aligned name offset with the aligned name table size _assert_(Common::AlignUp(name_offset, 1ull << m_address_shift) == name_table_size); @@ -449,15 +450,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) +void DirectoryBlobReader::WriteEntryName(u32* name_offset, const std::string& name, + u64 name_table_offset) { - strncpy((char*)&m_fst_data[*name_offset + m_fst_name_offset], name.c_str(), name.length() + 1); + 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) + u32* name_offset, u64* data_offset, u32 parent_entry_index, + u64 name_table_offset) { std::vector sorted_entries = parent_entry.children; @@ -476,16 +479,16 @@ void DirectoryBlobReader::WriteDirectory(const File::FSTEntry& parent_entry, u32 u32 entry_index = *fst_offset / ENTRY_SIZE; WriteEntryData(fst_offset, DIRECTORY_ENTRY, *name_offset, parent_entry_index, entry_index + entry.size + 1, 0); - WriteEntryName(name_offset, entry.virtualName); + WriteEntryName(name_offset, entry.virtualName, name_table_offset); - WriteDirectory(entry, fst_offset, name_offset, data_offset, entry_index); + WriteDirectory(entry, fst_offset, name_offset, data_offset, entry_index, name_table_offset); } else { // put entry in FST WriteEntryData(fst_offset, FILE_ENTRY, *name_offset, *data_offset, entry.size, m_address_shift); - WriteEntryName(name_offset, entry.virtualName); + 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); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 3e7048b3fa..c156e877ac 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -95,9 +95,9 @@ private: // 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); + 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* data_offset, u32 parent_entry_index, u64 name_table_offset); std::string m_root_directory; @@ -109,7 +109,6 @@ private: // GameCube has no shift, Wii has 2 bit shift u32 m_address_shift; - u64 m_fst_name_offset; std::vector m_fst_data; std::vector m_disk_header; From 2ea0a1a08657835657dda07c7bd1ee37d7a408c3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 13:06:39 +0200 Subject: [PATCH 27/43] DirectoryBlob: Make some constants local --- Source/Core/DiscIO/DirectoryBlob.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index be540b30ef..6433c87822 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -46,14 +46,6 @@ static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); constexpr u8 ENTRY_SIZE = 0x0c; constexpr u8 FILE_ENTRY = 0; constexpr u8 DIRECTORY_ENTRY = 1; -constexpr u64 DISKHEADER_ADDRESS = 0; -constexpr u64 DISKHEADER_SIZE = 0x440; -constexpr u64 NONPARTITION_DISKHEADER_SIZE = 0x100; -constexpr u64 BI2_ADDRESS = 0x440; -constexpr u64 BI2_SIZE = 0x2000; -constexpr u64 APPLOADER_ADDRESS = 0x2440; -constexpr u64 WII_REGION_DATA_ADDRESS = 0x4E000; -constexpr u64 WII_REGION_DATA_SIZE = 0x20; constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; DiscContent::DiscContent(u64 offset, u64 size, const std::string& path) @@ -161,10 +153,12 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri } DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) - : m_root_directory(root_directory), m_disk_header(DISKHEADER_SIZE) + : m_root_directory(root_directory) { SetDiscHeaderAndDiscType(); + constexpr u64 BI2_ADDRESS = 0x440; + constexpr u64 BI2_SIZE = 0x2000; AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); BuildFST(SetDOL(SetApploader())); @@ -248,6 +242,11 @@ u64 DirectoryBlobReader::GetDataSize() const void DirectoryBlobReader::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()); @@ -310,6 +309,8 @@ void DirectoryBlobReader::SetWiiRegionData() else if (bytes_read < 0x20) ERROR_LOG(DISCIO, "Couldn't read age ratings from %s", region_bin_path.c_str()); + constexpr u64 WII_REGION_DATA_ADDRESS = 0x4E000; + constexpr u64 WII_REGION_DATA_SIZE = 0x20; m_nonpartition_contents.emplace(WII_REGION_DATA_ADDRESS, WII_REGION_DATA_SIZE, m_wii_region_data.data()); } @@ -358,6 +359,8 @@ u64 DirectoryBlobReader::SetApploader() Write32(static_cast(-1), 0x10, &m_apploader); } + constexpr u64 APPLOADER_ADDRESS = 0x2440; + m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); // Return DOL address, 32 byte aligned (plus 32 byte padding) From ab4762c4c24626c06941ed8f5de6bec616e53095 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 13:20:23 +0200 Subject: [PATCH 28/43] DirectoryBlob: Split out setting BI2 to new function --- Source/Core/DiscIO/DirectoryBlob.cpp | 13 ++++++++----- Source/Core/DiscIO/DirectoryBlob.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 6433c87822..cf63309d45 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -156,11 +156,7 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) : m_root_directory(root_directory) { SetDiscHeaderAndDiscType(); - - constexpr u64 BI2_ADDRESS = 0x440; - constexpr u64 BI2_SIZE = 0x2000; - AddFileToContents(&m_virtual_disc, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); - + SetBI2(); BuildFST(SetDOL(SetApploader())); if (m_is_wii) @@ -282,6 +278,13 @@ void DirectoryBlobReader::SetDiscHeaderAndDiscType() } } +void DirectoryBlobReader::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); +} + void DirectoryBlobReader::SetPartitionTable() { constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index c156e877ac..abe1f4b164 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -77,6 +77,7 @@ private: bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); void SetDiscHeaderAndDiscType(); + void SetBI2(); void SetPartitionTable(); void SetWiiRegionData(); void SetTMDAndTicket(); From 953ca9cee193a6459ae78e28b387d9f49f6be755 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 14:42:41 +0200 Subject: [PATCH 29/43] DirectoryBlob: Make PadToAddress and Write32 static --- Source/Core/DiscIO/DirectoryBlob.cpp | 44 +++++++++++++++------------- Source/Core/DiscIO/DirectoryBlob.h | 4 --- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index cf63309d45..3a5abeacd7 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -39,6 +39,9 @@ static const DiscContent& AddFileToContents(std::set* contents, // Returns the number of bytes read. static size_t ReadFileToVector(const std::string& path, std::vector* vector); +static void PadToAddress(u64 start_address, u64* address, u64* length, u8** buffer); +static void Write32(u32 data, u32 offset, std::vector* buffer); + static u32 ComputeNameSize(const File::FSTEntry& parent_entry); static std::string ASCIIToUppercase(std::string str); static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); @@ -419,27 +422,6 @@ void DirectoryBlobReader::BuildFST(u64 fst_address) m_virtual_disc.emplace(fst_address, m_fst_data.size(), m_fst_data.data()); } -void DirectoryBlobReader::PadToAddress(u64 start_address, u64* address, u64* length, - u8** buffer) const -{ - if (start_address > *address && *length > 0) - { - u64 padBytes = std::min(start_address - *address, *length); - memset(*buffer, 0, (size_t)padBytes); - *length -= padBytes; - *buffer += padBytes; - *address += padBytes; - } -} - -void DirectoryBlobReader::Write32(u32 data, u32 offset, std::vector* const buffer) -{ - (*buffer)[offset++] = (data >> 24); - (*buffer)[offset++] = (data >> 16) & 0xff; - (*buffer)[offset++] = (data >> 8) & 0xff; - (*buffer)[offset] = (data)&0xff; -} - void DirectoryBlobReader::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, u32 address_shift) { @@ -520,6 +502,26 @@ static size_t ReadFileToVector(const std::string& path, std::vector* vector) return bytes_read; } +static void PadToAddress(u64 start_address, u64* address, u64* length, u8** buffer) +{ + if (start_address > *address && *length > 0) + { + u64 padBytes = std::min(start_address - *address, *length); + memset(*buffer, 0, (size_t)padBytes); + *length -= padBytes; + *buffer += padBytes; + *address += padBytes; + } +} + +static void Write32(u32 data, u32 offset, std::vector* buffer) +{ + (*buffer)[offset++] = (data >> 24); + (*buffer)[offset++] = (data >> 16) & 0xff; + (*buffer)[offset++] = (data >> 8) & 0xff; + (*buffer)[offset] = data & 0xff; +} + static u32 ComputeNameSize(const File::FSTEntry& parent_entry) { u32 name_size = 0; diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index abe1f4b164..fe23bf9e75 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -89,10 +89,6 @@ private: void BuildFST(u64 fst_address); - void PadToAddress(u64 start_address, u64* address, u64* length, u8** buffer) const; - - void Write32(u32 data, u32 offset, std::vector* const buffer); - // FST creation void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, u32 address_shift); From ba0ee3f54b50cebc60a5303c0c3b591844f03838 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 15:54:26 +0200 Subject: [PATCH 30/43] 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 From fb09874f79eedf4b2cd0c5d49d2a42ecc5b21f18 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 16:14:32 +0200 Subject: [PATCH 31/43] DirectoryBlob: Reorder functions in .cpp file They're now grouped by which class they belong to. --- Source/Core/DiscIO/DirectoryBlob.cpp | 70 ++++++++++++++-------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index dd9cdb83a2..74e9682860 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -239,34 +239,6 @@ u64 DirectoryBlobReader::GetDataSize() const return 0; } -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; - - 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_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; - if (m_is_wii == is_gc) - ERROR_LOG(DISCIO, "Couldn't detect disc type based on %s", boot_bin_path.c_str()); - - m_address_shift = m_is_wii ? 2 : 0; -} - void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& partition_header) { constexpr u64 NONPARTITION_DISKHEADER_ADDRESS = 0; @@ -291,13 +263,6 @@ void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& parti m_disk_header_nonpartition.data()); } -void DirectoryBlobPartition::SetBI2() -{ - constexpr u64 BI2_ADDRESS = 0x440; - constexpr u64 BI2_SIZE = 0x2000; - AddFileToContents(&m_contents, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); -} - void DirectoryBlobReader::SetPartitionTable() { constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; @@ -346,6 +311,41 @@ void DirectoryBlobReader::SetTMDAndTicket() reinterpret_cast(&m_tmd_header)); } +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; + + 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_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; + if (m_is_wii == is_gc) + ERROR_LOG(DISCIO, "Couldn't detect disc type based on %s", boot_bin_path.c_str()); + + m_address_shift = m_is_wii ? 2 : 0; +} + +void DirectoryBlobPartition::SetBI2() +{ + constexpr u64 BI2_ADDRESS = 0x440; + constexpr u64 BI2_SIZE = 0x2000; + AddFileToContents(&m_contents, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); +} + u64 DirectoryBlobPartition::SetApploader() { bool success = false; From a3ee61e1a97899a0d29f15cdebf6a6589aa444dd Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 17:31:03 +0200 Subject: [PATCH 32/43] DirectoryBlob: Let DirectoryBlob force GC/Wii for partition --- Source/Core/DiscIO/DirectoryBlob.cpp | 24 ++++++++++++++++-------- Source/Core/DiscIO/DirectoryBlob.h | 4 ++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 74e9682860..e8db47d29a 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -156,7 +156,7 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri } DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) - : m_root_directory(root_directory), m_game_partition(root_directory) + : m_root_directory(root_directory), m_game_partition(root_directory, {}) { m_is_wii = m_game_partition.IsWii(); @@ -311,15 +311,16 @@ void DirectoryBlobReader::SetTMDAndTicket() reinterpret_cast(&m_tmd_header)); } -DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory) +DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory, + std::optional is_wii) : m_root_directory(root_directory) { - SetDiscHeaderAndDiscType(); + SetDiscHeaderAndDiscType(is_wii); SetBI2(); BuildFST(SetDOL(SetApploader())); } -void DirectoryBlobPartition::SetDiscHeaderAndDiscType() +void DirectoryBlobPartition::SetDiscHeaderAndDiscType(std::optional is_wii) { constexpr u64 DISKHEADER_ADDRESS = 0; constexpr u64 DISKHEADER_SIZE = 0x440; @@ -331,10 +332,17 @@ void DirectoryBlobPartition::SetDiscHeaderAndDiscType() 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; - if (m_is_wii == is_gc) - ERROR_LOG(DISCIO, "Couldn't detect disc type based on %s", boot_bin_path.c_str()); + if (is_wii.has_value()) + { + m_is_wii = *is_wii; + } + else + { + m_is_wii = Common::swap32(&m_disk_header[0x18]) == 0x5d1c9ea3; + const bool is_gc = Common::swap32(&m_disk_header[0x1c]) == 0xc2339f3d; + if (m_is_wii == is_gc) + ERROR_LOG(DISCIO, "Couldn't detect disc type based on %s", boot_bin_path.c_str()); + } m_address_shift = m_is_wii ? 2 : 0; } diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 3bcde03dd5..647ac11380 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -55,7 +55,7 @@ private: class DirectoryBlobPartition { public: - explicit DirectoryBlobPartition(const std::string& root_directory); + DirectoryBlobPartition(const std::string& root_directory, std::optional is_wii); // We do not allow copying, because it might mess up the pointers inside DiscContents DirectoryBlobPartition(const DirectoryBlobPartition&) = delete; @@ -67,7 +67,7 @@ public: const std::vector& GetHeader() const { return m_disk_header; } const std::set& GetContents() const { return m_contents; } private: - void SetDiscHeaderAndDiscType(); + void SetDiscHeaderAndDiscType(std::optional is_wii); void SetBI2(); // Returns DOL address From d84bee3ff4bf084ccb10fd176244a436b50e40d4 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 17:51:22 +0200 Subject: [PATCH 33/43] DirectoryBlob: Prepare more for supporting multiple partitions --- Source/Core/DiscIO/DirectoryBlob.cpp | 30 ++++++++++++++++++++-------- Source/Core/DiscIO/DirectoryBlob.h | 12 ++++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index e8db47d29a..0b16c4da7b 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -156,13 +157,21 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri } DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) - : m_root_directory(root_directory), m_game_partition(root_directory, {}) + : m_root_directory(root_directory) { - m_is_wii = m_game_partition.IsWii(); + DirectoryBlobPartition game_partition(root_directory, {}); + m_is_wii = game_partition.IsWii(); - if (m_is_wii) + if (!m_is_wii) { - SetNonpartitionDiscHeader(m_game_partition.GetHeader()); + m_gamecube_pseudopartition = std::move(game_partition); + } + else + { + SetNonpartitionDiscHeader(game_partition.GetHeader()); + + m_partitions.emplace(GAME_PARTITION_ADDRESS, std::move(game_partition)); + SetPartitionTable(); SetWiiRegionData(); SetTMDAndTicket(); @@ -205,8 +214,9 @@ 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_game_partition.GetContents()); + const std::set& contents = + m_is_wii ? m_nonpartition_contents : m_gamecube_pseudopartition.GetContents(); + return ReadInternal(offset, length, buffer, contents); } bool DirectoryBlobReader::SupportsReadWiiDecrypted() const @@ -216,10 +226,14 @@ bool DirectoryBlobReader::SupportsReadWiiDecrypted() const bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_offset) { - if (!m_is_wii || partition_offset != GAME_PARTITION_ADDRESS) + if (!m_is_wii) return false; - return ReadInternal(offset, size, buffer, m_game_partition.GetContents()); + auto it = m_partitions.find(partition_offset); + if (it == m_partitions.end()) + return false; + + return ReadInternal(offset, size, buffer, it->second.GetContents()); } BlobType DirectoryBlobReader::GetBlobType() const diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 647ac11380..23048b64b0 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include @@ -55,6 +56,7 @@ private: class DirectoryBlobPartition { public: + DirectoryBlobPartition() = default; DirectoryBlobPartition(const std::string& root_directory, std::optional is_wii); // We do not allow copying, because it might mess up the pointers inside DiscContents @@ -90,9 +92,9 @@ private: std::vector m_fst_data; std::string m_root_directory; - bool m_is_wii; + bool m_is_wii = false; // GameCube has no shift, Wii has 2 bit shift - u32 m_address_shift; + u32 m_address_shift = 0; }; class DirectoryBlobReader : public BlobReader @@ -126,8 +128,12 @@ private: std::string m_root_directory; - DirectoryBlobPartition m_game_partition; + // For GameCube: + DirectoryBlobPartition m_gamecube_pseudopartition; + + // For Wii: std::set m_nonpartition_contents; + std::map m_partitions; bool m_is_wii; From e15b957d531870bd67c2c0257b38004426f8d34b Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 19:07:12 +0200 Subject: [PATCH 34/43] DirectoryBlob: Implement GetDataSize() --- Source/Core/DiscIO/DirectoryBlob.cpp | 11 +++++++++-- Source/Core/DiscIO/DirectoryBlob.h | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 0b16c4da7b..4256d6cc9a 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -29,6 +29,7 @@ #include "Common/Swap.h" #include "Core/Boot/DolReader.h" #include "DiscIO/Blob.h" +#include "DiscIO/VolumeWii.h" namespace DiscIO { @@ -165,11 +166,16 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) if (!m_is_wii) { m_gamecube_pseudopartition = std::move(game_partition); + m_data_size = m_gamecube_pseudopartition.GetDataSize(); } else { SetNonpartitionDiscHeader(game_partition.GetHeader()); + const u64 unaligned_data_size = VolumeWii::PartitionOffsetToRawOffset( + game_partition.GetDataSize(), Partition(GAME_PARTITION_ADDRESS)); + m_data_size = Common::AlignUp(unaligned_data_size, 0x8000ull); + m_partitions.emplace(GAME_PARTITION_ADDRESS, std::move(game_partition)); SetPartitionTable(); @@ -249,8 +255,7 @@ u64 DirectoryBlobReader::GetRawSize() const u64 DirectoryBlobReader::GetDataSize() const { - // Not implemented - return 0; + return m_data_size; } void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& partition_header) @@ -451,6 +456,8 @@ void DirectoryBlobPartition::BuildFST(u64 fst_address) Write32((u32)(m_fst_data.size() >> m_address_shift), 0x042c, &m_disk_header); m_contents.emplace(fst_address, m_fst_data.size(), m_fst_data.data()); + + m_data_size = current_data_address; } void DirectoryBlobPartition::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 23048b64b0..c644db4692 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -66,6 +66,7 @@ public: DirectoryBlobPartition& operator=(DirectoryBlobPartition&&) = default; bool IsWii() const { return m_is_wii; } + u64 GetDataSize() const { return m_data_size; } const std::vector& GetHeader() const { return m_disk_header; } const std::set& GetContents() const { return m_contents; } private: @@ -95,6 +96,8 @@ private: bool m_is_wii = false; // GameCube has no shift, Wii has 2 bit shift u32 m_address_shift = 0; + + u64 m_data_size; }; class DirectoryBlobReader : public BlobReader @@ -148,6 +151,8 @@ private: } m_tmd_header; static_assert(sizeof(TMDHeader) == 8, "Wrong size for TMDHeader"); #pragma pack(pop) + + u64 m_data_size; }; } // namespace From 955ab72b1d0661b1917373d185ed0c9252ea67c5 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 20:11:58 +0200 Subject: [PATCH 35/43] DirectoryBlob: Remove m_root_directory from DirectoryBlob --- Source/Core/DiscIO/DirectoryBlob.cpp | 26 +++++++++++++------------- Source/Core/DiscIO/DirectoryBlob.h | 11 +++++------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 4256d6cc9a..a2e2d2f505 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -157,10 +157,9 @@ std::unique_ptr DirectoryBlobReader::Create(const std::stri return std::unique_ptr(new DirectoryBlobReader(root_directory)); } -DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) - : m_root_directory(root_directory) +DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root) { - DirectoryBlobPartition game_partition(root_directory, {}); + DirectoryBlobPartition game_partition(game_partition_root, {}); m_is_wii = game_partition.IsWii(); if (!m_is_wii) @@ -170,7 +169,7 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) } else { - SetNonpartitionDiscHeader(game_partition.GetHeader()); + SetNonpartitionDiscHeader(game_partition.GetHeader(), game_partition_root); const u64 unaligned_data_size = VolumeWii::PartitionOffsetToRawOffset( game_partition.GetDataSize(), Partition(GAME_PARTITION_ADDRESS)); @@ -179,8 +178,8 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& root_directory) m_partitions.emplace(GAME_PARTITION_ADDRESS, std::move(game_partition)); SetPartitionTable(); - SetWiiRegionData(); - SetTMDAndTicket(); + SetWiiRegionData(game_partition_root); + SetTMDAndTicket(game_partition_root); } } @@ -258,14 +257,15 @@ u64 DirectoryBlobReader::GetDataSize() const return m_data_size; } -void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& partition_header) +void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& partition_header, + const std::string& game_partition_root) { 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); + ReadFileToVector(game_partition_root + "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, @@ -293,7 +293,7 @@ void DirectoryBlobReader::SetPartitionTable() reinterpret_cast(PARTITION_TABLE.data())); } -void DirectoryBlobReader::SetWiiRegionData() +void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_root) { m_wii_region_data.resize(0x10, 0x00); m_wii_region_data.resize(0x20, 0x80); @@ -302,7 +302,7 @@ void DirectoryBlobReader::SetWiiRegionData() constexpr u32 INVALID_REGION = 0xFF; Write32(INVALID_REGION, 0, &m_wii_region_data); - const std::string region_bin_path = m_root_directory + "disc/region.bin"; + const std::string region_bin_path = game_partition_root + "disc/region.bin"; const size_t bytes_read = ReadFileToVector(region_bin_path, &m_wii_region_data); if (bytes_read < 0x4) ERROR_LOG(DISCIO, "Couldn't read region from %s", region_bin_path.c_str()); @@ -315,15 +315,15 @@ void DirectoryBlobReader::SetWiiRegionData() m_wii_region_data.data()); } -void DirectoryBlobReader::SetTMDAndTicket() +void DirectoryBlobReader::SetTMDAndTicket(const std::string& partition_root) { constexpr u32 TICKET_OFFSET = 0x0; constexpr u32 TICKET_SIZE = 0x2a4; constexpr u32 TMD_OFFSET = 0x2c0; constexpr u32 MAX_TMD_SIZE = 0x49e4; - AddFileToContents(&m_nonpartition_contents, m_root_directory + "ticket.bin", + AddFileToContents(&m_nonpartition_contents, partition_root + "ticket.bin", GAME_PARTITION_ADDRESS + TICKET_OFFSET, TICKET_SIZE); - const DiscContent& tmd = AddFileToContents(&m_nonpartition_contents, m_root_directory + "tmd.bin", + const DiscContent& tmd = AddFileToContents(&m_nonpartition_contents, partition_root + "tmd.bin", GAME_PARTITION_ADDRESS + TMD_OFFSET, MAX_TMD_SIZE); 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), diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index c644db4692..ef7509ede0 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -120,16 +120,15 @@ public: u64 GetDataSize() const override; private: - explicit DirectoryBlobReader(const std::string& root_directory); + explicit DirectoryBlobReader(const std::string& game_partition_root); bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); - void SetNonpartitionDiscHeader(const std::vector& partition_header); + void SetNonpartitionDiscHeader(const std::vector& partition_header, + const std::string& game_partition_root); void SetPartitionTable(); - void SetWiiRegionData(); - void SetTMDAndTicket(); - - std::string m_root_directory; + void SetWiiRegionData(const std::string& game_partition_root); + void SetTMDAndTicket(const std::string& partition_root); // For GameCube: DirectoryBlobPartition m_gamecube_pseudopartition; From 34fd08e7eb0a3cc3bff814a3a6e30403cab12896 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 11 Jun 2017 13:22:13 +0200 Subject: [PATCH 36/43] DirectoryBlob: Support multiple partitions --- Source/Core/DiscIO/DirectoryBlob.cpp | 195 ++++++++++++++++++++++----- Source/Core/DiscIO/DirectoryBlob.h | 32 +++-- 2 files changed, 181 insertions(+), 46 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index a2e2d2f505..78f4302bc9 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -48,10 +48,17 @@ static u32 ComputeNameSize(const File::FSTEntry& parent_entry); static std::string ASCIIToUppercase(std::string str); static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); +enum class PartitionType : u32 +{ + Game = 0, + Update = 1, + Channel = 2, + // There are more types used by Super Smash Bros. Brawl, but they don't have special names +}; + constexpr u8 ENTRY_SIZE = 0x0c; constexpr u8 FILE_ENTRY = 0; constexpr u8 DIRECTORY_ENTRY = 1; -constexpr u64 GAME_PARTITION_ADDRESS = 0x50000; DiscContent::DiscContent(u64 offset, u64 size, const std::string& path) : m_offset(offset), m_size(size), m_content_source(path) @@ -110,6 +117,39 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const return true; } +static std::optional ParsePartitionDirectoryName(const std::string& name) +{ + if (name.size() < 2) + return {}; + + if (!strcasecmp(name.c_str(), "DATA")) + return PartitionType::Game; + if (!strcasecmp(name.c_str(), "UPDATE")) + return PartitionType::Update; + if (!strcasecmp(name.c_str(), "CHANNEL")) + return PartitionType::Channel; + + if (name[0] == 'P' || name[0] == 'p') + { + // e.g. "P-HA8E" (normally only used for Super Smash Bros. Brawl's VC partitions) + if (name[1] == '-' && name.size() == 6) + { + const u32 result = Common::swap32(reinterpret_cast(name.data() + 2)); + return static_cast(result); + } + + // e.g. "P0" + if (std::all_of(name.cbegin() + 1, name.cend(), [](char c) { return c >= '0' && c <= '9'; })) + { + u32 result; + if (TryParse(name.substr(1), &result)) + return static_cast(result); + } + } + + return {}; +} + static bool PathCharactersEqual(char a, char b) { return a == b @@ -137,27 +177,40 @@ static bool PathEndsWith(const std::string& path, const std::string& suffix) return true; } -static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* root_directory) +static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* partition_root, + std::string* true_root) { if (!PathEndsWith(dol_path, "/sys/main.dol")) return false; const size_t chars_to_remove = std::string("sys/main.dol").size(); - *root_directory = dol_path.substr(0, dol_path.size() - chars_to_remove); + *partition_root = dol_path.substr(0, dol_path.size() - chars_to_remove); - return File::GetSize(*root_directory + "sys/boot.bin") >= 0x20; + if (File::GetSize(*partition_root + "sys/boot.bin") < 0x20) + return false; + +#ifdef _WIN32 + constexpr const char* dir_separator = "/\\"; +#else + constexpr char dir_separator = '/'; +#endif + const size_t true_root_end = dol_path.find_last_of(dir_separator, partition_root->size() - 2) + 1; + *true_root = dol_path.substr(0, true_root_end); + + return true; } std::unique_ptr DirectoryBlobReader::Create(const std::string& dol_path) { - std::string root_directory; - if (!IsValidDirectoryBlob(dol_path, &root_directory)) + std::string partition_root, true_root; + if (!IsValidDirectoryBlob(dol_path, &partition_root, &true_root)) return nullptr; - return std::unique_ptr(new DirectoryBlobReader(root_directory)); + return std::unique_ptr(new DirectoryBlobReader(partition_root, true_root)); } -DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root) +DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, + const std::string& true_root) { DirectoryBlobPartition game_partition(game_partition_root, {}); m_is_wii = game_partition.IsWii(); @@ -170,16 +223,31 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root) else { SetNonpartitionDiscHeader(game_partition.GetHeader(), game_partition_root); - - const u64 unaligned_data_size = VolumeWii::PartitionOffsetToRawOffset( - game_partition.GetDataSize(), Partition(GAME_PARTITION_ADDRESS)); - m_data_size = Common::AlignUp(unaligned_data_size, 0x8000ull); - - m_partitions.emplace(GAME_PARTITION_ADDRESS, std::move(game_partition)); - - SetPartitionTable(); SetWiiRegionData(game_partition_root); - SetTMDAndTicket(game_partition_root); + + std::vector partitions; + partitions.emplace_back(std::move(game_partition), PartitionType::Game); + + std::string game_partition_directory_name = game_partition_root.substr(true_root.size()); + game_partition_directory_name.pop_back(); // Remove trailing slash + if (ParsePartitionDirectoryName(game_partition_directory_name) == PartitionType::Game) + { + const File::FSTEntry true_root_entry = File::ScanDirectoryTree(true_root, false); + for (const File::FSTEntry& entry : true_root_entry.children) + { + if (entry.isDirectory) + { + const std::optional type = ParsePartitionDirectoryName(entry.virtualName); + if (type && *type != PartitionType::Game) + { + partitions.emplace_back(DirectoryBlobPartition(entry.physicalName + "/", m_is_wii), + *type); + } + } + } + } + + SetPartitions(std::move(partitions)); } } @@ -282,17 +350,6 @@ void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& parti m_disk_header_nonpartition.data()); } -void DirectoryBlobReader::SetPartitionTable() -{ - constexpr u64 PARTITION_TABLE_ADDRESS = 0x40000; - static 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}}; - - m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, PARTITION_TABLE.size() * sizeof(u32), - reinterpret_cast(PARTITION_TABLE.data())); -} - void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_root) { m_wii_region_data.resize(0x10, 0x00); @@ -315,19 +372,89 @@ void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_roo m_wii_region_data.data()); } -void DirectoryBlobReader::SetTMDAndTicket(const std::string& partition_root) +void DirectoryBlobReader::SetPartitions(std::vector&& partitions) +{ + std::sort(partitions.begin(), partitions.end(), + [](const PartitionWithType& lhs, const PartitionWithType& rhs) { + if (lhs.type == rhs.type) + return lhs.partition.GetRootDirectory() < rhs.partition.GetRootDirectory(); + + // Ascending sort by partition type, except Update (1) comes before before Game (0) + return (lhs.type > PartitionType::Update || rhs.type > PartitionType::Update) ? + lhs.type < rhs.type : + lhs.type > rhs.type; + }); + + u32 subtable_1_size = 0; + while (subtable_1_size < partitions.size() && subtable_1_size < 3 && + partitions[subtable_1_size].type <= PartitionType::Channel) + { + ++subtable_1_size; + } + const u32 subtable_2_size = static_cast(partitions.size() - subtable_1_size); + + constexpr u32 PARTITION_TABLE_ADDRESS = 0x40000; + constexpr u32 PARTITION_SUBTABLE1_OFFSET = 0x20; + constexpr u32 PARTITION_SUBTABLE2_OFFSET = 0x40; + m_partition_table.resize(PARTITION_SUBTABLE2_OFFSET + subtable_2_size * 8); + + Write32(subtable_1_size, 0x0, &m_partition_table); + Write32((PARTITION_TABLE_ADDRESS + PARTITION_SUBTABLE1_OFFSET) >> 2, 0x4, &m_partition_table); + if (subtable_2_size != 0) + { + Write32(subtable_2_size, 0x8, &m_partition_table); + Write32((PARTITION_TABLE_ADDRESS + PARTITION_SUBTABLE2_OFFSET) >> 2, 0xC, &m_partition_table); + } + + constexpr u64 STANDARD_UPDATE_PARTITION_ADDRESS = 0x50000; + constexpr u64 STANDARD_GAME_PARTITION_ADDRESS = 0xF800000; + u64 partition_address = STANDARD_UPDATE_PARTITION_ADDRESS; + u64 offset_in_table = PARTITION_SUBTABLE1_OFFSET; + for (size_t i = 0; i < partitions.size(); ++i) + { + if (i == subtable_1_size) + offset_in_table = PARTITION_SUBTABLE2_OFFSET; + + if (partitions[i].type == PartitionType::Game) + partition_address = std::max(partition_address, STANDARD_GAME_PARTITION_ADDRESS); + + Write32(static_cast(partition_address >> 2), offset_in_table, &m_partition_table); + offset_in_table += 4; + Write32(static_cast(partitions[i].type), offset_in_table, &m_partition_table); + offset_in_table += 4; + + SetTMDAndTicket(partitions[i].partition.GetRootDirectory(), partition_address); + + const u64 partition_data_size = partitions[i].partition.GetDataSize(); + m_partitions.emplace(partition_address, std::move(partitions[i].partition)); + const u64 unaligned_next_partition_address = + VolumeWii::PartitionOffsetToRawOffset(partition_data_size, Partition(partition_address)); + partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull); + } + m_data_size = partition_address; + + m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, m_partition_table.size(), + m_partition_table.data()); +} + +void DirectoryBlobReader::SetTMDAndTicket(const std::string& partition_root, u64 partition_address) { constexpr u32 TICKET_OFFSET = 0x0; constexpr u32 TICKET_SIZE = 0x2a4; constexpr u32 TMD_OFFSET = 0x2c0; constexpr u32 MAX_TMD_SIZE = 0x49e4; AddFileToContents(&m_nonpartition_contents, partition_root + "ticket.bin", - GAME_PARTITION_ADDRESS + TICKET_OFFSET, TICKET_SIZE); + partition_address + TICKET_OFFSET, TICKET_SIZE); const DiscContent& tmd = AddFileToContents(&m_nonpartition_contents, partition_root + "tmd.bin", - GAME_PARTITION_ADDRESS + TMD_OFFSET, MAX_TMD_SIZE); - 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)); + partition_address + TMD_OFFSET, MAX_TMD_SIZE); + + constexpr u32 TMD_HEADER_SIZE = 8; + m_tmd_headers.emplace_back(TMD_HEADER_SIZE); + std::vector& tmd_header = m_tmd_headers.back(); + Write32(static_cast(tmd.GetSize()), 0x0, &tmd_header); + Write32(TMD_OFFSET >> 2, 0x4, &tmd_header); + m_nonpartition_contents.emplace(partition_address + TICKET_SIZE, TMD_HEADER_SIZE, + tmd_header.data()); } DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory, diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index ef7509ede0..dc7ffd8138 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -25,6 +25,8 @@ class IOFile; namespace DiscIO { +enum class PartitionType : u32; + class DiscContent { public: @@ -67,6 +69,7 @@ public: bool IsWii() const { return m_is_wii; } u64 GetDataSize() const { return m_data_size; } + const std::string& GetRootDirectory() const { return m_root_directory; } const std::vector& GetHeader() const { return m_disk_header; } const std::set& GetContents() const { return m_contents; } private: @@ -120,15 +123,27 @@ public: u64 GetDataSize() const override; private: - explicit DirectoryBlobReader(const std::string& game_partition_root); + struct PartitionWithType + { + PartitionWithType(DirectoryBlobPartition&& partition_, PartitionType type_) + : partition(std::move(partition_)), type(type_) + { + } + + DirectoryBlobPartition partition; + PartitionType type; + }; + + explicit DirectoryBlobReader(const std::string& game_partition_root, + const std::string& true_root); bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set& contents); void SetNonpartitionDiscHeader(const std::vector& partition_header, const std::string& game_partition_root); - void SetPartitionTable(); void SetWiiRegionData(const std::string& game_partition_root); - void SetTMDAndTicket(const std::string& partition_root); + void SetPartitions(std::vector&& partitions); + void SetTMDAndTicket(const std::string& partition_root, u64 partition_address); // For GameCube: DirectoryBlobPartition m_gamecube_pseudopartition; @@ -140,16 +155,9 @@ private: bool m_is_wii; std::vector m_disk_header_nonpartition; + std::vector m_partition_table; std::vector m_wii_region_data; - -#pragma pack(push, 1) - struct TMDHeader - { - u32 tmd_size; - u32 tmd_offset; - } m_tmd_header; - static_assert(sizeof(TMDHeader) == 8, "Wrong size for TMDHeader"); -#pragma pack(pop) + std::vector> m_tmd_headers; u64 m_data_size; }; From 1ea44f425d071ae8ad2543dea7bdd4eed7945298 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 11 Jun 2017 13:47:03 +0200 Subject: [PATCH 37/43] DirectoryBlob: Change ConvertUTF8NamesToSHIFTJIS's parameter to pointer --- Source/Core/DiscIO/DirectoryBlob.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 78f4302bc9..b9cf27123b 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -46,7 +46,7 @@ static void Write32(u32 data, u32 offset, std::vector* buffer); static u32 ComputeNameSize(const File::FSTEntry& parent_entry); static std::string ASCIIToUppercase(std::string str); -static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); +static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry* parent_entry); enum class PartitionType : u32 { @@ -553,7 +553,7 @@ void DirectoryBlobPartition::BuildFST(u64 fst_address) File::FSTEntry rootEntry = File::ScanDirectoryTree(m_root_directory + "files/", true); - ConvertUTF8NamesToSHIFTJIS(rootEntry); + ConvertUTF8NamesToSHIFTJIS(&rootEntry); u32 name_table_size = Common::AlignUp(ComputeNameSize(rootEntry), 1ull << m_address_shift); u64 total_entries = rootEntry.size + 1; // The root entry itself isn't counted in rootEntry.size @@ -700,12 +700,12 @@ static u32 ComputeNameSize(const File::FSTEntry& parent_entry) return name_size; } -static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry) +static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry* parent_entry) { - for (File::FSTEntry& entry : parent_entry.children) + for (File::FSTEntry& entry : parent_entry->children) { if (entry.isDirectory) - ConvertUTF8NamesToSHIFTJIS(entry); + ConvertUTF8NamesToSHIFTJIS(&entry); entry.virtualName = UTF8ToSHIFTJIS(entry.virtualName); } From 5fe3745750af23e1999caac9326ab77738231642 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 11 Jun 2017 14:45:42 +0200 Subject: [PATCH 38/43] Don't show "extra" files from DirectoryBlobs in game list For instance, we don't want to show TGC files that might be inside the /files/ directory of a GameCube DirectoryBlob, and we don't want to show the /sys/main.dol files for extra partitions of Wii DirectoryBlobs. --- Source/Core/DiscIO/DirectoryBlob.cpp | 80 +++++++++++++++++-- Source/Core/DiscIO/DirectoryBlob.h | 3 + .../Core/DolphinQt2/GameList/GameTracker.cpp | 11 +++ Source/Core/DolphinQt2/GameList/GameTracker.h | 7 +- Source/Core/DolphinWX/GameListCtrl.cpp | 7 ++ 5 files changed, 96 insertions(+), 12 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index b9cf27123b..5a92d6c88c 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -150,15 +150,20 @@ static std::optional ParsePartitionDirectoryName(const std::strin return {}; } -static bool PathCharactersEqual(char a, char b) +static bool IsDirectorySeparator(char c) { - return a == b + return c == '/' #ifdef _WIN32 - || (a == '/' && b == '\\') || (a == '\\' && b == '/') + || c == '\\' #endif ; } +static bool PathCharactersEqual(char a, char b) +{ + return a == b || (IsDirectorySeparator(a) && IsDirectorySeparator(b)); +} + static bool PathEndsWith(const std::string& path, const std::string& suffix) { if (suffix.size() > path.size()) @@ -178,7 +183,7 @@ static bool PathEndsWith(const std::string& path, const std::string& suffix) } static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* partition_root, - std::string* true_root) + std::string* true_root = nullptr) { if (!PathEndsWith(dol_path, "/sys/main.dol")) return false; @@ -194,12 +199,75 @@ static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* parti #else constexpr char dir_separator = '/'; #endif - const size_t true_root_end = dol_path.find_last_of(dir_separator, partition_root->size() - 2) + 1; - *true_root = dol_path.substr(0, true_root_end); + if (true_root) + { + *true_root = + dol_path.substr(0, dol_path.find_last_of(dir_separator, partition_root->size() - 2) + 1); + } return true; } +static bool ExistsAndIsValidDirectoryBlob(const std::string& dol_path) +{ + std::string partition_root; + return File::Exists(dol_path) && IsValidDirectoryBlob(dol_path, &partition_root); +} + +static bool IsInFilesDirectory(const std::string& path) +{ + size_t files_pos = std::string::npos; + while (true) + { + files_pos = path.rfind("files", files_pos); + if (files_pos == std::string::npos) + return false; + + const size_t slash_before_pos = files_pos - 1; + const size_t slash_after_pos = files_pos + 5; + if ((files_pos == 0 || IsDirectorySeparator(path[slash_before_pos])) && + (slash_after_pos == path.size() || (IsDirectorySeparator(path[slash_after_pos]))) && + ExistsAndIsValidDirectoryBlob(path.substr(0, files_pos) + "sys/main.dol")) + { + return true; + } + + --files_pos; + } +} + +static bool IsMainDolForNonGamePartition(const std::string& path) +{ + std::string partition_root, true_root; + if (!IsValidDirectoryBlob(path, &partition_root, &true_root)) + return false; // This is not a /sys/main.dol + + std::string partition_directory_name = partition_root.substr(true_root.size()); + partition_directory_name.pop_back(); // Remove trailing slash + const std::optional partition_type = + ParsePartitionDirectoryName(partition_directory_name); + if (!partition_type || *partition_type == PartitionType::Game) + return false; // volume_path is the game partition's /sys/main.dol + + const File::FSTEntry true_root_entry = File::ScanDirectoryTree(true_root, false); + for (const File::FSTEntry& entry : true_root_entry.children) + { + if (entry.isDirectory && + ParsePartitionDirectoryName(entry.virtualName) == PartitionType::Game && + ExistsAndIsValidDirectoryBlob(entry.physicalName + "/sys/main.dol")) + { + return true; // volume_path is the /sys/main.dol for a non-game partition + } + } + + return false; // volume_path is the game partition's /sys/main.dol +} + +bool ShouldHideFromGameList(const std::string& volume_path) +{ + return IsInFilesDirectory(volume_path) || IsMainDolForNonGamePartition(volume_path); +} + std::unique_ptr DirectoryBlobReader::Create(const std::string& dol_path) { std::string partition_root, true_root; diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index dc7ffd8138..18fca46726 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -27,6 +27,9 @@ namespace DiscIO { enum class PartitionType : u32; +// Returns true if the path is inside a DirectoryBlob and doesn't represent the DirectoryBlob itself +bool ShouldHideFromGameList(const std::string& volume_path); + class DiscContent { public: diff --git a/Source/Core/DolphinQt2/GameList/GameTracker.cpp b/Source/Core/DolphinQt2/GameList/GameTracker.cpp index be66ab406e..3d541e6559 100644 --- a/Source/Core/DolphinQt2/GameList/GameTracker.cpp +++ b/Source/Core/DolphinQt2/GameList/GameTracker.cpp @@ -6,6 +6,7 @@ #include #include +#include "DiscIO/DirectoryBlob.h" #include "DolphinQt2/GameList/GameTracker.h" #include "DolphinQt2/Settings.h" @@ -137,3 +138,13 @@ void GameTracker::UpdateFile(const QString& file) emit GameRemoved(file); } } + +void GameLoader::LoadGame(const QString& path) +{ + if (!DiscIO::ShouldHideFromGameList(path.toStdString())) + { + GameFile* game = new GameFile(path); + if (game->IsValid()) + emit GameLoaded(QSharedPointer(game)); + } +} diff --git a/Source/Core/DolphinQt2/GameList/GameTracker.h b/Source/Core/DolphinQt2/GameList/GameTracker.h index 5867278b19..926e2a9ae2 100644 --- a/Source/Core/DolphinQt2/GameList/GameTracker.h +++ b/Source/Core/DolphinQt2/GameList/GameTracker.h @@ -54,12 +54,7 @@ class GameLoader final : public QObject Q_OBJECT public: - void LoadGame(const QString& path) - { - GameFile* game = new GameFile(path); - if (game->IsValid()) - emit GameLoaded(QSharedPointer(game)); - } + void LoadGame(const QString& path); signals: void GameLoaded(QSharedPointer game); diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index 2395028790..b0e23a9469 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -53,6 +53,7 @@ #include "Core/Movie.h" #include "Core/TitleDatabase.h" #include "DiscIO/Blob.h" +#include "DiscIO/DirectoryBlob.h" #include "DiscIO/Enums.h" #include "DiscIO/Volume.h" #include "DolphinWX/Frame.h" @@ -761,6 +762,12 @@ void GameListCtrl::RescanList() auto search_results = Common::DoFileSearch(SConfig::GetInstance().m_ISOFolder, search_extensions, SConfig::GetInstance().m_RecursiveISOFolder); + // TODO Prevent DoFileSearch from looking inside /files/ directories of DirectoryBlobs at all? + // TODO Make DoFileSearch support filter predicates so we don't have remove things afterwards? + search_results.erase( + std::remove_if(search_results.begin(), search_results.end(), DiscIO::ShouldHideFromGameList), + search_results.end()); + std::vector cached_paths; for (const auto& file : m_cached_files) cached_paths.emplace_back(file->GetFileName()); From a6be1513bff9af9f47e7f28c467ea75011c1b36a Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 11 Jun 2017 14:53:53 +0200 Subject: [PATCH 39/43] DolphinWX: Increment game list cache version This is so that DirectoryBlobs won't look like valid discs in old versions that don't support the DirectoryBlob format. --- Source/Core/DolphinWX/GameListCtrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index b0e23a9469..58005099be 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -81,7 +81,7 @@ public: wxProgressDialog* dialog; }; -static constexpr u32 CACHE_REVISION = 2; // Last changed in PR 5687 +static constexpr u32 CACHE_REVISION = 3; // Last changed in PR 5573 static bool sorted = false; From 09832caf41319c01592bd1d3817a879022032a35 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 12 Jun 2017 15:21:08 +0200 Subject: [PATCH 40/43] DolphinQt2: Fix memory leak in GameLoader::LoadGame --- Source/Core/DolphinQt2/GameList/GameTracker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinQt2/GameList/GameTracker.cpp b/Source/Core/DolphinQt2/GameList/GameTracker.cpp index 3d541e6559..fb832512b5 100644 --- a/Source/Core/DolphinQt2/GameList/GameTracker.cpp +++ b/Source/Core/DolphinQt2/GameList/GameTracker.cpp @@ -143,8 +143,8 @@ void GameLoader::LoadGame(const QString& path) { if (!DiscIO::ShouldHideFromGameList(path.toStdString())) { - GameFile* game = new GameFile(path); + auto game = QSharedPointer::create(path); if (game->IsValid()) - emit GameLoaded(QSharedPointer(game)); + emit GameLoaded(game); } } From 3fd0d39a853ddb677e8dccd045b8ccae38be1429 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 13 Jun 2017 15:52:02 +0200 Subject: [PATCH 41/43] DirectoryBlob: Write partition headers properly --- Source/Core/DiscIO/DirectoryBlob.cpp | 43 ++++++++++++++++++++++------ Source/Core/DiscIO/DirectoryBlob.h | 4 +-- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 5a92d6c88c..ab53bd3af7 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -491,7 +491,7 @@ void DirectoryBlobReader::SetPartitions(std::vector&& partiti Write32(static_cast(partitions[i].type), offset_in_table, &m_partition_table); offset_in_table += 4; - SetTMDAndTicket(partitions[i].partition.GetRootDirectory(), partition_address); + SetPartitionHeader(partitions[i].partition, partition_address); const u64 partition_data_size = partitions[i].partition.GetDataSize(); m_partitions.emplace(partition_address, std::move(partitions[i].partition)); @@ -505,24 +505,49 @@ void DirectoryBlobReader::SetPartitions(std::vector&& partiti m_partition_table.data()); } -void DirectoryBlobReader::SetTMDAndTicket(const std::string& partition_root, u64 partition_address) +// This function sets the header that's shortly before the start of the encrypted +// area, not the header that's right at the beginning of the encrypted area +void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& partition, + u64 partition_address) { constexpr u32 TICKET_OFFSET = 0x0; constexpr u32 TICKET_SIZE = 0x2a4; constexpr u32 TMD_OFFSET = 0x2c0; constexpr u32 MAX_TMD_SIZE = 0x49e4; + constexpr u32 H3_OFFSET = 0x4000; + constexpr u32 H3_SIZE = 0x18000; + + const std::string& partition_root = partition.GetRootDirectory(); + AddFileToContents(&m_nonpartition_contents, partition_root + "ticket.bin", partition_address + TICKET_OFFSET, TICKET_SIZE); + const DiscContent& tmd = AddFileToContents(&m_nonpartition_contents, partition_root + "tmd.bin", partition_address + TMD_OFFSET, MAX_TMD_SIZE); - constexpr u32 TMD_HEADER_SIZE = 8; - m_tmd_headers.emplace_back(TMD_HEADER_SIZE); - std::vector& tmd_header = m_tmd_headers.back(); - Write32(static_cast(tmd.GetSize()), 0x0, &tmd_header); - Write32(TMD_OFFSET >> 2, 0x4, &tmd_header); - m_nonpartition_contents.emplace(partition_address + TICKET_SIZE, TMD_HEADER_SIZE, - tmd_header.data()); + const u64 cert_offset = Common::AlignUp(TMD_OFFSET + tmd.GetSize(), 0x20ull); + const u64 max_cert_size = H3_OFFSET - cert_offset; + const DiscContent& cert = AddFileToContents(&m_nonpartition_contents, partition_root + "cert.bin", + partition_address + cert_offset, max_cert_size); + + AddFileToContents(&m_nonpartition_contents, partition_root + "h3.bin", + partition_address + H3_OFFSET, H3_SIZE); + + constexpr u32 PARTITION_HEADER_SIZE = 0x1c; + constexpr u32 DATA_OFFSET = 0x20000; + const u64 data_size = Common::AlignUp(partition.GetDataSize(), 0x7c00) / 0x7c00 * 0x8000; + m_partition_headers.emplace_back(PARTITION_HEADER_SIZE); + std::vector& partition_header = m_partition_headers.back(); + Write32(static_cast(tmd.GetSize()), 0x0, &partition_header); + Write32(TMD_OFFSET >> 2, 0x4, &partition_header); + Write32(static_cast(cert.GetSize()), 0x8, &partition_header); + Write32(static_cast(cert_offset >> 2), 0x0C, &partition_header); + Write32(H3_OFFSET >> 2, 0x10, &partition_header); + Write32(DATA_OFFSET >> 2, 0x14, &partition_header); + Write32(static_cast(data_size >> 2), 0x18, &partition_header); + + m_nonpartition_contents.emplace(partition_address + TICKET_SIZE, PARTITION_HEADER_SIZE, + partition_header.data()); } DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory, diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 18fca46726..97bff45e83 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -146,7 +146,7 @@ private: const std::string& game_partition_root); void SetWiiRegionData(const std::string& game_partition_root); void SetPartitions(std::vector&& partitions); - void SetTMDAndTicket(const std::string& partition_root, u64 partition_address); + void SetPartitionHeader(const DirectoryBlobPartition& partition, u64 partition_address); // For GameCube: DirectoryBlobPartition m_gamecube_pseudopartition; @@ -160,7 +160,7 @@ private: std::vector m_disk_header_nonpartition; std::vector m_partition_table; std::vector m_wii_region_data; - std::vector> m_tmd_headers; + std::vector> m_partition_headers; u64 m_data_size; }; From d0c322f6e6cf5b574d4f54eb38df82c52c288671 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 18 Jul 2017 15:53:04 +0200 Subject: [PATCH 42/43] DirectoryBlob: Don't silently set GC region to NTSC-J if bi2.bin is missing We were already handling the Wii region in region.bin in this way. --- Source/Core/DiscIO/DirectoryBlob.cpp | 18 ++++++++++++++---- Source/Core/DiscIO/DirectoryBlob.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index ab53bd3af7..a91472fb63 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -56,6 +56,9 @@ enum class PartitionType : u32 // There are more types used by Super Smash Bros. Brawl, but they don't have special names }; +// 0xFF is an arbitrarily picked value. Note that we can't use 0x00, because that means NTSC-J +constexpr u32 INVALID_REGION = 0xFF; + constexpr u8 ENTRY_SIZE = 0x0c; constexpr u8 FILE_ENTRY = 0; constexpr u8 DIRECTORY_ENTRY = 1; @@ -422,9 +425,6 @@ void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_roo { m_wii_region_data.resize(0x10, 0x00); m_wii_region_data.resize(0x20, 0x80); - - // 0xFF is an arbitrarily picked value. Note that we can't use 0x00, because that means NTSC-J - constexpr u32 INVALID_REGION = 0xFF; Write32(INVALID_REGION, 0, &m_wii_region_data); const std::string region_bin_path = game_partition_root + "disc/region.bin"; @@ -590,7 +590,17 @@ void DirectoryBlobPartition::SetBI2() { constexpr u64 BI2_ADDRESS = 0x440; constexpr u64 BI2_SIZE = 0x2000; - AddFileToContents(&m_contents, m_root_directory + "sys/bi2.bin", BI2_ADDRESS, BI2_SIZE); + m_bi2.resize(BI2_SIZE); + + if (!m_is_wii) + Write32(INVALID_REGION, 0x18, &m_bi2); + + const std::string bi2_path = m_root_directory + "sys/bi2.bin"; + const size_t bytes_read = ReadFileToVector(bi2_path, &m_bi2); + if (!m_is_wii && bytes_read < 0x1C) + ERROR_LOG(DISCIO, "Couldn't read region from %s", bi2_path.c_str()); + + m_contents.emplace(BI2_ADDRESS, BI2_SIZE, m_bi2.data()); } u64 DirectoryBlobPartition::SetApploader() diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 97bff45e83..5547f19110 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -95,6 +95,7 @@ private: std::set m_contents; std::vector m_disk_header; + std::vector m_bi2; std::vector m_apploader; std::vector m_fst_data; From b6c6a04f9552c804fdb6a5a9eae2b51fd902d3ef Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 18 Jul 2017 21:06:35 +0200 Subject: [PATCH 43/43] DirectoryBlob: Standardize the spelling of disc DirectoryBlob was using disk in some places and disc in other places. --- Source/Core/DiscIO/DirectoryBlob.cpp | 44 ++++++++++++++-------------- Source/Core/DiscIO/DirectoryBlob.h | 6 ++-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index a91472fb63..364405aa01 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -399,26 +399,26 @@ u64 DirectoryBlobReader::GetDataSize() const void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& partition_header, const std::string& game_partition_root) { - constexpr u64 NONPARTITION_DISKHEADER_ADDRESS = 0; - constexpr u64 NONPARTITION_DISKHEADER_SIZE = 0x100; + constexpr u64 NONPARTITION_DISCHEADER_ADDRESS = 0; + constexpr u64 NONPARTITION_DISCHEADER_SIZE = 0x100; - m_disk_header_nonpartition.resize(NONPARTITION_DISKHEADER_SIZE); + m_disc_header_nonpartition.resize(NONPARTITION_DISCHEADER_SIZE); const size_t header_bin_bytes_read = - ReadFileToVector(game_partition_root + "disc/header.bin", &m_disk_header_nonpartition); + ReadFileToVector(game_partition_root + "disc/header.bin", &m_disc_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); + partition_header.data() + m_disc_header_nonpartition.size(), + m_disc_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; + m_disc_header_nonpartition[0x60] = 0; if (header_bin_bytes_read < 0x61) - m_disk_header_nonpartition[0x61] = 0; + m_disc_header_nonpartition[0x61] = 0; - m_nonpartition_contents.emplace(NONPARTITION_DISKHEADER_ADDRESS, NONPARTITION_DISKHEADER_SIZE, - m_disk_header_nonpartition.data()); + m_nonpartition_contents.emplace(NONPARTITION_DISCHEADER_ADDRESS, NONPARTITION_DISCHEADER_SIZE, + m_disc_header_nonpartition.data()); } void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_root) @@ -561,15 +561,15 @@ DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory void DirectoryBlobPartition::SetDiscHeaderAndDiscType(std::optional is_wii) { - constexpr u64 DISKHEADER_ADDRESS = 0; - constexpr u64 DISKHEADER_SIZE = 0x440; + constexpr u64 DISCHEADER_ADDRESS = 0; + constexpr u64 DISCHEADER_SIZE = 0x440; - m_disk_header.resize(DISKHEADER_SIZE); + m_disc_header.resize(DISCHEADER_SIZE); const std::string boot_bin_path = m_root_directory + "sys/boot.bin"; - if (ReadFileToVector(boot_bin_path, &m_disk_header) < 0x20) + if (ReadFileToVector(boot_bin_path, &m_disc_header) < 0x20) ERROR_LOG(DISCIO, "%s doesn't exist or is too small", boot_bin_path.c_str()); - m_contents.emplace(DISKHEADER_ADDRESS, DISKHEADER_SIZE, m_disk_header.data()); + m_contents.emplace(DISCHEADER_ADDRESS, DISCHEADER_SIZE, m_disc_header.data()); if (is_wii.has_value()) { @@ -577,8 +577,8 @@ void DirectoryBlobPartition::SetDiscHeaderAndDiscType(std::optional is_wii } else { - m_is_wii = Common::swap32(&m_disk_header[0x18]) == 0x5d1c9ea3; - const bool is_gc = Common::swap32(&m_disk_header[0x1c]) == 0xc2339f3d; + m_is_wii = Common::swap32(&m_disc_header[0x18]) == 0x5d1c9ea3; + const bool is_gc = Common::swap32(&m_disc_header[0x1c]) == 0xc2339f3d; if (m_is_wii == is_gc) ERROR_LOG(DISCIO, "Couldn't detect disc type based on %s", boot_bin_path.c_str()); } @@ -644,7 +644,7 @@ u64 DirectoryBlobPartition::SetDOL(u64 dol_address) const DiscContent& dol = AddFileToContents(&m_contents, m_root_directory + "sys/main.dol", dol_address); - Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disk_header); + Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disc_header); // Return FST address, 32 byte aligned (plus 32 byte padding) return Common::AlignUp(dol_address + dol.GetSize() + 0x20, 0x20ull); @@ -664,7 +664,7 @@ void DirectoryBlobPartition::BuildFST(u64 fst_address) const u64 name_table_offset = total_entries * ENTRY_SIZE; m_fst_data.resize(name_table_offset + name_table_size); - // 32 KiB aligned start of data on disk + // 32 KiB aligned start of data on disc u64 current_data_address = Common::AlignUp(fst_address + m_fst_data.size(), 0x8000ull); u32 fst_offset = 0; // Offset within FST data @@ -681,9 +681,9 @@ void DirectoryBlobPartition::BuildFST(u64 fst_address) _assert_(Common::AlignUp(name_offset, 1ull << m_address_shift) == name_table_size); // write FST size and location - Write32((u32)(fst_address >> m_address_shift), 0x0424, &m_disk_header); - 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); + Write32((u32)(fst_address >> m_address_shift), 0x0424, &m_disc_header); + Write32((u32)(m_fst_data.size() >> m_address_shift), 0x0428, &m_disc_header); + Write32((u32)(m_fst_data.size() >> m_address_shift), 0x042c, &m_disc_header); m_contents.emplace(fst_address, m_fst_data.size(), m_fst_data.data()); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 5547f19110..666694e508 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -73,7 +73,7 @@ public: bool IsWii() const { return m_is_wii; } u64 GetDataSize() const { return m_data_size; } const std::string& GetRootDirectory() const { return m_root_directory; } - const std::vector& GetHeader() const { return m_disk_header; } + const std::vector& GetHeader() const { return m_disc_header; } const std::set& GetContents() const { return m_contents; } private: void SetDiscHeaderAndDiscType(std::optional is_wii); @@ -94,7 +94,7 @@ private: u64* data_offset, u32 parent_entry_index, u64 name_table_offset); std::set m_contents; - std::vector m_disk_header; + std::vector m_disc_header; std::vector m_bi2; std::vector m_apploader; std::vector m_fst_data; @@ -158,7 +158,7 @@ private: bool m_is_wii; - std::vector m_disk_header_nonpartition; + std::vector m_disc_header_nonpartition; std::vector m_partition_table; std::vector m_wii_region_data; std::vector> m_partition_headers;