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