From 37c09343d82efec3f758f4ad08ccb59686fd8a10 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 7 Jun 2017 20:32:09 +0200 Subject: 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/DiscIO/DirectoryBlob.cpp | 506 +++++++++++++++++++++++++++++++++++ 1 file changed, 506 insertions(+) create mode 100644 Source/Core/DiscIO/DirectoryBlob.cpp (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp new file mode 100644 index 0000000000..9425869f26 --- /dev/null +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -0,0 +1,506 @@ +// Copyright 2008 Dolphin Emulator Project +// 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 "Common/Align.h" +#include "Common/Assert.h" +#include "Common/CommonPaths.h" +#include "Common/CommonTypes.h" +#include "Common/File.h" +#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" + +namespace DiscIO +{ +static u32 ComputeNameSize(const File::FSTEntry& parent_entry); +static std::string ASCIIToUppercase(std::string str); +static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry); + +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 +#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) +{ + // create the default disk header + SetGameID("AGBJ01"); + SetName("Default name"); + + // 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(); +} + +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_disk.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; + + // zero fill to start of file data + PadToAddress(fileIter->first, &offset, &length, &buffer); + + while (fileIter != m_virtual_disk.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) + return false; + + u64 fileSize = file.GetSize(); + + if (fileOffset < fileSize) + { + 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); + } + } + + 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); +} + +bool DirectoryBlobReader::SupportsReadWiiDecrypted() const +{ + return m_is_wii; +} + +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)); +} + +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; +} + +u64 DirectoryBlobReader::GetRawSize() const +{ + // Not implemented + return 0; +} + +u64 DirectoryBlobReader::GetDataSize() const +{ + // Not implemented + return 0; +} + +void DirectoryBlobReader::SetDiskTypeWii() +{ + Write32(0x5d1c9ea3, 0x18, &m_disk_header); + memset(&m_disk_header[0x1c], 0, 4); + + m_is_wii = true; + m_address_shift = 2; +} + +void DirectoryBlobReader::SetDiskTypeGC() +{ + memset(&m_disk_header[0x18], 0, 4); + Write32(0xc2339f3d, 0x1c, &m_disk_header); + + m_is_wii = false; + m_address_shift = 0; +} + +bool DirectoryBlobReader::SetApploader(const std::string& apploader) +{ + if (!apploader.empty()) + { + 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()) + { + 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()); + + // 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; + } +} + +void DirectoryBlobReader::SetDOLAndDiskType(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) + m_fst_address = Common::AlignUp(m_dol_address + m_dol.size() + 0x20, 0x20ull); +} + +void DirectoryBlobReader::BuildFST() +{ + m_fst_data.clear(); + + File::FSTEntry rootEntry = File::ScanDirectoryTree(m_root_directory + "files/", true); + + 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 + + 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; + + u32 fst_offset = 0; // Offset within FST data + u32 name_offset = 0; // Offset within name table + u32 root_offset = 0; // Offset of root of FST + + // 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); + + // 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); + + // write FST size and location + 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); +} + +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 +{ + 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) +{ + m_fst_data[(*entry_offset)++] = type; + + m_fst_data[(*entry_offset)++] = (name_offset >> 16) & 0xff; + m_fst_data[(*entry_offset)++] = (name_offset >> 8) & 0xff; + m_fst_data[(*entry_offset)++] = (name_offset)&0xff; + + Write32((u32)(data_offset >> address_shift), *entry_offset, &m_fst_data); + *entry_offset += 4; + + Write32((u32)length, *entry_offset, &m_fst_data); + *entry_offset += 4; +} + +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 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; + + // Sort for determinism + std::sort(sorted_entries.begin(), sorted_entries.end(), [](const File::FSTEntry& one, + const File::FSTEntry& two) { + const std::string one_upper = ASCIIToUppercase(one.virtualName); + const std::string two_upper = ASCIIToUppercase(two.virtualName); + return one_upper == two_upper ? one.virtualName < two.virtualName : one_upper < two_upper; + }); + + for (const File::FSTEntry& entry : sorted_entries) + { + if (entry.isDirectory) + { + 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); + + WriteDirectory(entry, fst_offset, name_offset, data_offset, entry_index); + } + else + { + // put entry in FST + WriteEntryData(fst_offset, FILE_ENTRY, *name_offset, *data_offset, entry.size, + 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); + + // 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); + } + } +} + +static u32 ComputeNameSize(const File::FSTEntry& parent_entry) +{ + u32 name_size = 0; + for (const File::FSTEntry& entry : parent_entry.children) + { + if (entry.isDirectory) + name_size += ComputeNameSize(entry); + + name_size += (u32)entry.virtualName.length() + 1; + } + return name_size; +} + +static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry& parent_entry) +{ + for (File::FSTEntry& entry : parent_entry.children) + { + if (entry.isDirectory) + ConvertUTF8NamesToSHIFTJIS(entry); + + entry.virtualName = UTF8ToSHIFTJIS(entry.virtualName); + } +} + +static std::string ASCIIToUppercase(std::string str) +{ + std::transform(str.begin(), str.end(), str.begin(), + [](char c) { return std::toupper(c, std::locale::classic()); }); + return str; +} + +} // namespace -- cgit v1.2.3 From b8d8c7370f9f9dabdf3964b403e4ae7666740136 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 7 Jun 2017 21:13:24 +0200 Subject: DirectoryBlob: Move constants to .cpp file --- Source/Core/DiscIO/DirectoryBlob.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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 -- cgit v1.2.3 From e1321b131d9e3386a4be17592363d72b13a15f66 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 16:07:01 +0200 Subject: DirectoryBlob: Create a DiscContent class for use in m_virtual_disc --- Source/Core/DiscIO/DirectoryBlob.cpp | 98 ++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 37 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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(); - - if (fileOffset < fileSize) - { - 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; + ++it; - if (fileIter != m_virtual_disk.end()) + if (it != m_virtual_disc.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); -- cgit v1.2.3 From 936ef5b9dde767698fc2a61b1d2b2c2f867f60f0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 16:37:51 +0200 Subject: DirectoryBlob: Let DiscContent be backed by memory instead of file --- Source/Core/DiscIO/DirectoryBlob.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From a0fa350ca651f3ecbeb2b06e107c49c506bf995e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 18:30:05 +0200 Subject: DirectoryBlob: Use DiscContent for everything in ReadPartition --- Source/Core/DiscIO/DirectoryBlob.cpp | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From 3f9eec9ae4d7d4285811ec5cea016f3edb418143 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 18:43:52 +0200 Subject: 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 +++++++++--------------------------- 1 file changed, 18 insertions(+), 57 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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 { -- cgit v1.2.3 From 02610d4b28f631880f0ed34c344095caaf3b48a4 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 18:56:09 +0200 Subject: DirectoryBlob: Use DISCIO instead of DVDINTERFACE for logging --- Source/Core/DiscIO/DirectoryBlob.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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); } } -- cgit v1.2.3 From 71578b468dda2e3d2425a909d873e1a3eb8dbef0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 8 Jun 2017 22:11:31 +0200 Subject: DirectoryBlob: Support tickets and TMDs --- Source/Core/DiscIO/DirectoryBlob.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From 4cc8d3091cab23c8d76646099266209f45c872bb Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 12:08:17 +0200 Subject: DirectoryBlob: Require header file (boot.bin) --- Source/Core/DiscIO/DirectoryBlob.cpp | 101 ++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 42 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; + + if (m_is_wii) + { + m_disk_header_nonpartition.resize(NONPARTITION_DISKHEADER_SIZE); - m_is_wii = false; - m_address_shift = 0; + 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) -- cgit v1.2.3 From a6bbf7e21b7ae1c0d11feb3acb88875b7b6e30ca Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 12:45:34 +0200 Subject: DirectoryBlob: Don't keep DOL in memory --- Source/Core/DiscIO/DirectoryBlob.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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() -- cgit v1.2.3 From 251828ccc0d449ff9da1c823c7fb5aee6c4ace73 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 12:56:36 +0200 Subject: Don't check validity twice when creating DirectoryBlob --- Source/Core/DiscIO/DirectoryBlob.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From 975b2b40fab867f95acb7e5266996e8f17e3e3fd Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 21:39:26 +0200 Subject: DirectoryBlob: Support bi2.bin --- Source/Core/DiscIO/DirectoryBlob.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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()); -- cgit v1.2.3 From 8afa230787b7ea945841cb28c149d4c7db31f593 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 9 Jun 2017 21:42:26 +0200 Subject: 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(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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()); -- cgit v1.2.3 From c73f6b6c260d4db8c84b3eb8eac17ccc491028eb Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 08:46:21 +0200 Subject: DirectoryBlob: Add ReadFileToVector function --- Source/Core/DiscIO/DirectoryBlob.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From 8747b1b6ab2e579ccc78745c1b7252014f92252e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 09:53:36 +0200 Subject: DirectoryBlob: Support region.bin --- Source/Core/DiscIO/DirectoryBlob.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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()) -- cgit v1.2.3 From 1258d18f214d036d03d3507b86933f1d4638f6cf Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:27:46 +0200 Subject: DirectoryBlob: Restructure SetApploader --- Source/Core/DiscIO/DirectoryBlob.cpp | 47 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; + 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); + success = true; + } } - 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; } + + return success; } void DirectoryBlobReader::SetDOL() -- cgit v1.2.3 From 5a00bda490aa49a5baaeba652087f7e7794f9c42 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:37:06 +0200 Subject: DirectoryBlob: Move content emplacement out of the constructor --- Source/Core/DiscIO/DirectoryBlob.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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, -- cgit v1.2.3 From c4879aa48dd29928e64516d4367be9328700989d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:38:59 +0200 Subject: DirectoryBlob: Split out setting TMD and ticket to new function --- Source/Core/DiscIO/DirectoryBlob.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From b28ec0b7eed764c4d642f9e9a1013bc05a401e65 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 10:41:49 +0200 Subject: DirectoryBlob: Split out setting partition table to new function --- Source/Core/DiscIO/DirectoryBlob.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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); -- cgit v1.2.3 From 31d8322c5a0732ae631ee6f8226c6b7c5527cff5 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 11:24:11 +0200 Subject: 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 ++++++++++++------------------------ 1 file changed, 15 insertions(+), 29 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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, -- cgit v1.2.3 From ef39b4da4611169bab695d3943df794430cd7c45 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 11:54:41 +0200 Subject: 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 | 45 +++++++++++++++++------------------- 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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,35 +330,32 @@ 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())) { - m_apploader.resize(0x20); - // Make sure BS2 HLE doesn't try to run the apploader - Write32(static_cast(-1), 0x10, &m_apploader); + ERROR_LOG(DISCIO, "%s couldn't be accessed or is too small", path.c_str()); } else { - std::string data; - if (!File::ReadFileToString(apploader, data)) - { - PanicAlertT("Apploader unable to load from file"); - } + 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 - { - 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()); - } - } + 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); } m_virtual_disc.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data()); -- cgit v1.2.3 From 0d4ad0e39e633d911cced0ecb13b90d873c78271 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 13:02:16 +0200 Subject: DirectoryBlob: Remove m_fst_name_offset --- Source/Core/DiscIO/DirectoryBlob.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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); -- cgit v1.2.3 From 2ea0a1a08657835657dda07c7bd1ee37d7a408c3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 13:06:39 +0200 Subject: DirectoryBlob: Make some constants local --- Source/Core/DiscIO/DirectoryBlob.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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) -- cgit v1.2.3 From ab4762c4c24626c06941ed8f5de6bec616e53095 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 13:20:23 +0200 Subject: DirectoryBlob: Split out setting BI2 to new function --- Source/Core/DiscIO/DirectoryBlob.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From 953ca9cee193a6459ae78e28b387d9f49f6be755 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 14:42:41 +0200 Subject: DirectoryBlob: Make PadToAddress and Write32 static --- Source/Core/DiscIO/DirectoryBlob.cpp | 44 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From ba0ee3f54b50cebc60a5303c0c3b591844f03838 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 15:54:26 +0200 Subject: DirectoryBlob: Prepare for supporting multiple partitions --- Source/Core/DiscIO/DirectoryBlob.cpp | 103 +++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 47 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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::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 DirectoryBlobReader::SetBI2() +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 -- cgit v1.2.3 From fb09874f79eedf4b2cd0c5d49d2a42ecc5b21f18 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 16:14:32 +0200 Subject: 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(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From a3ee61e1a97899a0d29f15cdebf6a6589aa444dd Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 17:31:03 +0200 Subject: DirectoryBlob: Let DirectoryBlob force GC/Wii for partition --- Source/Core/DiscIO/DirectoryBlob.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; } -- cgit v1.2.3 From d84bee3ff4bf084ccb10fd176244a436b50e40d4 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 17:51:22 +0200 Subject: DirectoryBlob: Prepare more for supporting multiple partitions --- Source/Core/DiscIO/DirectoryBlob.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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) + { + m_gamecube_pseudopartition = std::move(game_partition); + } + else { - SetNonpartitionDiscHeader(m_game_partition.GetHeader()); + 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; + + auto it = m_partitions.find(partition_offset); + if (it == m_partitions.end()) return false; - return ReadInternal(offset, size, buffer, m_game_partition.GetContents()); + return ReadInternal(offset, size, buffer, it->second.GetContents()); } BlobType DirectoryBlobReader::GetBlobType() const -- cgit v1.2.3 From e15b957d531870bd67c2c0257b38004426f8d34b Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 19:07:12 +0200 Subject: DirectoryBlob: Implement GetDataSize() --- Source/Core/DiscIO/DirectoryBlob.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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, -- cgit v1.2.3 From 955ab72b1d0661b1917373d185ed0c9252ea67c5 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Jun 2017 20:11:58 +0200 Subject: DirectoryBlob: Remove m_root_directory from DirectoryBlob --- Source/Core/DiscIO/DirectoryBlob.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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), -- cgit v1.2.3 From 34fd08e7eb0a3cc3bff814a3a6e30403cab12896 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 11 Jun 2017 13:22:13 +0200 Subject: DirectoryBlob: Support multiple partitions --- Source/Core/DiscIO/DirectoryBlob.cpp | 191 +++++++++++++++++++++++++++++------ 1 file changed, 159 insertions(+), 32 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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); + + 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 File::GetSize(*root_directory + "sys/boot.bin") >= 0x20; + 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); + SetWiiRegionData(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); + std::vector partitions; + partitions.emplace_back(std::move(game_partition), PartitionType::Game); - m_partitions.emplace(GAME_PARTITION_ADDRESS, std::move(game_partition)); + 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); + } + } + } + } - SetPartitionTable(); - SetWiiRegionData(game_partition_root); - SetTMDAndTicket(game_partition_root); + 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, -- cgit v1.2.3 From 1ea44f425d071ae8ad2543dea7bdd4eed7945298 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 11 Jun 2017 13:47:03 +0200 Subject: DirectoryBlob: Change ConvertUTF8NamesToSHIFTJIS's parameter to pointer --- Source/Core/DiscIO/DirectoryBlob.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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); } -- cgit v1.2.3 From 5fe3745750af23e1999caac9326ab77738231642 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 11 Jun 2017 14:45:42 +0200 Subject: 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 +++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 6 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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; -- cgit v1.2.3 From 3fd0d39a853ddb677e8dccd045b8ccae38be1429 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 13 Jun 2017 15:52:02 +0200 Subject: DirectoryBlob: Write partition headers properly --- Source/Core/DiscIO/DirectoryBlob.cpp | 43 ++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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, -- cgit v1.2.3 From d0c322f6e6cf5b574d4f54eb38df82c52c288671 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 18 Jul 2017 15:53:04 +0200 Subject: 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 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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() -- cgit v1.2.3 From b6c6a04f9552c804fdb6a5a9eae2b51fd902d3ef Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 18 Jul 2017 21:06:35 +0200 Subject: DirectoryBlob: Standardize the spelling of disc DirectoryBlob was using disk in some places and disc in other places. --- Source/Core/DiscIO/DirectoryBlob.cpp | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp') 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()); -- cgit v1.2.3