diff --git a/Source/Core/Common/IOFile.cpp b/Source/Core/Common/IOFile.cpp index cf7762ea68..cc22979bbe 100644 --- a/Source/Core/Common/IOFile.cpp +++ b/Source/Core/Common/IOFile.cpp @@ -101,6 +101,15 @@ bool IOFile::Close() return m_good; } +IOFile IOFile::Duplicate(const char openmode[]) const +{ +#ifdef _WIN32 + return IOFile(_fdopen(_dup(_fileno(m_file)), openmode)); +#else // _WIN32 + return IOFile(fdopen(dup(fileno(m_file)), openmode)); +#endif // _WIN32 +} + void IOFile::SetHandle(std::FILE* file) { Close(); diff --git a/Source/Core/Common/IOFile.h b/Source/Core/Common/IOFile.h index 62fdd7186e..4b12c31888 100644 --- a/Source/Core/Common/IOFile.h +++ b/Source/Core/Common/IOFile.h @@ -51,6 +51,8 @@ public: SharedAccess sh = SharedAccess::Default); bool Close(); + IOFile Duplicate(const char openmode[]) const; + template bool ReadArray(T* elements, size_t count, size_t* num_read = nullptr) { diff --git a/Source/Core/DiscIO/Blob.h b/Source/Core/DiscIO/Blob.h index 1777f9fcaa..29f6fb5b3f 100644 --- a/Source/Core/DiscIO/Blob.h +++ b/Source/Core/DiscIO/Blob.h @@ -64,6 +64,7 @@ public: virtual ~BlobReader() {} virtual BlobType GetBlobType() const = 0; + virtual std::unique_ptr CopyReader() const = 0; virtual u64 GetRawSize() const = 0; virtual u64 GetDataSize() const = 0; diff --git a/Source/Core/DiscIO/CISOBlob.cpp b/Source/Core/DiscIO/CISOBlob.cpp index 28408402b8..001c462694 100644 --- a/Source/Core/DiscIO/CISOBlob.cpp +++ b/Source/Core/DiscIO/CISOBlob.cpp @@ -40,6 +40,11 @@ std::unique_ptr CISOFileReader::Create(File::IOFile file) return nullptr; } +std::unique_ptr CISOFileReader::CopyReader() const +{ + return Create(m_file.Duplicate("rb")); +} + u64 CISOFileReader::GetDataSize() const { return static_cast(CISO_MAP_SIZE) * m_block_size; diff --git a/Source/Core/DiscIO/CISOBlob.h b/Source/Core/DiscIO/CISOBlob.h index ddbd5d0719..a3cd2ead82 100644 --- a/Source/Core/DiscIO/CISOBlob.h +++ b/Source/Core/DiscIO/CISOBlob.h @@ -36,6 +36,7 @@ public: static std::unique_ptr Create(File::IOFile file); BlobType GetBlobType() const override { return BlobType::CISO; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override; u64 GetDataSize() const override; diff --git a/Source/Core/DiscIO/CompressedBlob.cpp b/Source/Core/DiscIO/CompressedBlob.cpp index 139a1e6d17..629cedfe7c 100644 --- a/Source/Core/DiscIO/CompressedBlob.cpp +++ b/Source/Core/DiscIO/CompressedBlob.cpp @@ -74,6 +74,11 @@ CompressedBlobReader::~CompressedBlobReader() { } +std::unique_ptr CompressedBlobReader::CopyReader() const +{ + return Create(m_file.Duplicate("rb"), m_file_name); +} + // IMPORTANT: Calling this function invalidates all earlier pointers gotten from this function. u64 CompressedBlobReader::GetBlockCompressedSize(u64 block_num) const { diff --git a/Source/Core/DiscIO/CompressedBlob.h b/Source/Core/DiscIO/CompressedBlob.h index c828b1ad2b..c7c892cd13 100644 --- a/Source/Core/DiscIO/CompressedBlob.h +++ b/Source/Core/DiscIO/CompressedBlob.h @@ -50,6 +50,7 @@ public: const CompressedBlobHeader& GetHeader() const { return m_header; } BlobType GetBlobType() const override { return BlobType::GCZ; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override { return m_file_size; } u64 GetDataSize() const override { return m_header.data_size; } diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 193d74c244..1970d49b44 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -82,7 +82,7 @@ u64 DiscContent::GetSize() const return m_size; } -bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const +bool DiscContent::Read(u64* offset, u64* length, u8** buffer, DirectoryBlobReader* blob) const { if (m_size == 0) return true; @@ -104,15 +104,15 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const return false; } } - else if (std::holds_alternative(m_content_source)) + else if (std::holds_alternative(m_content_source)) { - const u8* const content_pointer = std::get(m_content_source) + offset_in_content; - std::copy(content_pointer, content_pointer + bytes_to_read, *buffer); + const auto& content = std::get(m_content_source); + std::copy(content->begin() + offset_in_content, + content->begin() + offset_in_content + bytes_to_read, *buffer); } else if (std::holds_alternative(m_content_source)) { const auto& content = std::get(m_content_source); - DirectoryBlobReader* blob = content.m_reader; const u64 decrypted_size = m_size * VolumeWii::BLOCK_DATA_SIZE / VolumeWii::BLOCK_TOTAL_SIZE; if (!blob->EncryptPartitionData(content.m_offset + offset_in_content, bytes_to_read, *buffer, content.m_partition_data_offset, decrypted_size)) @@ -123,8 +123,8 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const else if (std::holds_alternative(m_content_source)) { const auto& source = std::get(m_content_source); - if (!source.m_volume->Read(source.m_offset + offset_in_content, bytes_to_read, *buffer, - source.m_partition)) + if (!blob->GetWrappedVolume()->Read(source.m_offset + offset_in_content, bytes_to_read, + *buffer, source.m_partition)) { return false; } @@ -134,12 +134,6 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const const ContentFixedByte& source = std::get(m_content_source); std::fill_n(*buffer, bytes_to_read, source.m_byte); } - else if (std::holds_alternative(m_content_source)) - { - const ContentByteVector& source = std::get(m_content_source); - std::copy(source.m_bytes.begin() + offset_in_content, - source.m_bytes.begin() + offset_in_content + bytes_to_read, *buffer); - } else { PanicAlertFmt("DirectoryBlob: Invalid content source in DiscContent."); @@ -174,7 +168,7 @@ u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, u64 max_size, const std::s return size; } -bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const +bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer, DirectoryBlobReader* blob) const { // Determine which DiscContent the offset refers to std::set::const_iterator it = m_contents.upper_bound(DiscContent(offset)); @@ -187,7 +181,7 @@ bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const if (length == 0) return true; - if (!it->Read(&offset, &length, &buffer)) + if (!it->Read(&offset, &length, &buffer, blob)) return false; ++it; @@ -388,7 +382,10 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, } else { - SetNonpartitionDiscHeaderFromFile(game_partition.GetHeader(), game_partition_root); + std::vector disc_header(DISCHEADER_SIZE); + game_partition.GetContents().Read(DISCHEADER_ADDRESS, DISCHEADER_SIZE, disc_header.data(), + this); + SetNonpartitionDiscHeaderFromFile(disc_header, game_partition_root); SetWiiRegionDataFromFile(game_partition_root); std::vector partitions; @@ -426,7 +423,7 @@ DirectoryBlobReader::DirectoryBlobReader( { DirectoryBlobPartition game_partition(m_wrapped_volume.get(), m_wrapped_volume->GetGamePartition(), std::nullopt, - sys_callback, fst_callback); + sys_callback, fst_callback, this); m_is_wii = game_partition.IsWii(); if (!m_is_wii) @@ -440,11 +437,15 @@ DirectoryBlobReader::DirectoryBlobReader( std::vector header_bin(WII_NONPARTITION_DISCHEADER_SIZE); if (!m_wrapped_volume->Read(WII_NONPARTITION_DISCHEADER_ADDRESS, WII_NONPARTITION_DISCHEADER_SIZE, header_bin.data(), - PARTITION_NONE)) + PARTITION_NONE), + m_wrapped_volume.get()) { header_bin.clear(); } - SetNonpartitionDiscHeader(game_partition.GetHeader(), std::move(header_bin)); + std::vector disc_header(DISCHEADER_SIZE); + game_partition.GetContents().Read(DISCHEADER_ADDRESS, DISCHEADER_SIZE, disc_header.data(), + this); + SetNonpartitionDiscHeader(disc_header, std::move(header_bin)); std::vector wii_region_data(WII_REGION_DATA_SIZE); if (!m_wrapped_volume->Read(WII_REGION_DATA_ADDRESS, WII_REGION_DATA_SIZE, @@ -465,9 +466,9 @@ DirectoryBlobReader::DirectoryBlobReader( auto type = m_wrapped_volume->GetPartitionType(partition); if (type) { - partitions.emplace_back( - DirectoryBlobPartition(m_wrapped_volume.get(), partition, m_is_wii, nullptr, nullptr), - static_cast(*type)); + partitions.emplace_back(DirectoryBlobPartition(m_wrapped_volume.get(), partition, m_is_wii, + nullptr, nullptr, this), + static_cast(*type)); } } @@ -475,13 +476,24 @@ DirectoryBlobReader::DirectoryBlobReader( } } +DirectoryBlobReader::DirectoryBlobReader(const DirectoryBlobReader& rhs) + : m_gamecube_pseudopartition(rhs.m_gamecube_pseudopartition), + m_nonpartition_contents(rhs.m_nonpartition_contents), m_partitions(rhs.m_partitions), + m_encryption_cache(this), m_is_wii(rhs.m_is_wii), m_encrypted(rhs.m_encrypted), + m_data_size(rhs.m_data_size), + m_wrapped_volume(rhs.m_wrapped_volume ? + CreateDisc(rhs.m_wrapped_volume->GetBlobReader().CopyReader()) : + nullptr) +{ +} + bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer) { if (offset + length > m_data_size) return false; return (m_is_wii ? m_nonpartition_contents : m_gamecube_pseudopartition.GetContents()) - .Read(offset, length, buffer); + .Read(offset, length, buffer, this); } const DirectoryBlobPartition* DirectoryBlobReader::GetPartition(u64 offset, u64 size, @@ -510,7 +522,7 @@ bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, if (!partition) return false; - return partition->GetContents().Read(offset, size, buffer); + return partition->GetContents().Read(offset, size, buffer, this); } bool DirectoryBlobReader::EncryptPartitionData(u64 offset, u64 size, u8* buffer, @@ -522,7 +534,7 @@ bool DirectoryBlobReader::EncryptPartitionData(u64 offset, u64 size, u8* buffer, return false; if (!m_encrypted) - return it->second.GetContents().Read(offset, size, buffer); + return it->second.GetContents().Read(offset, size, buffer, this); return m_encryption_cache.EncryptGroups(offset, size, buffer, partition_data_offset, partition_data_decrypted_size, it->second.GetKey()); @@ -533,6 +545,11 @@ BlobType DirectoryBlobReader::GetBlobType() const return BlobType::DIRECTORY; } +std::unique_ptr DirectoryBlobReader::CopyReader() const +{ + return std::unique_ptr(new DirectoryBlobReader(*this)); +} + u64 DirectoryBlobReader::GetRawSize() const { // Not implemented @@ -558,28 +575,25 @@ void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector& parti std::vector header_bin) { const size_t header_bin_size = header_bin.size(); - m_disc_header_nonpartition = std::move(header_bin); - m_disc_header_nonpartition.resize(WII_NONPARTITION_DISCHEADER_SIZE); + header_bin.resize(WII_NONPARTITION_DISCHEADER_SIZE); // If header.bin is missing or smaller than expected, use the content of sys/boot.bin instead - if (header_bin_size < m_disc_header_nonpartition.size()) + if (header_bin_size < header_bin.size()) { std::copy(partition_header.data() + header_bin_size, - partition_header.data() + m_disc_header_nonpartition.size(), - m_disc_header_nonpartition.data() + header_bin_size); + partition_header.data() + header_bin.size(), header_bin.data() + header_bin_size); } // 0x60 and 0x61 are the only differences between the partition and non-partition headers if (header_bin_size < 0x60) - m_disc_header_nonpartition[0x60] = 0; + header_bin[0x60] = 0; if (header_bin_size < 0x61) - m_disc_header_nonpartition[0x61] = 0; + header_bin[0x61] = 0; - m_encrypted = std::all_of(m_disc_header_nonpartition.data() + 0x60, - m_disc_header_nonpartition.data() + 0x64, [](u8 x) { return x == 0; }); + m_encrypted = + std::all_of(header_bin.data() + 0x60, header_bin.data() + 0x64, [](u8 x) { return x == 0; }); - m_nonpartition_contents.AddReference(WII_NONPARTITION_DISCHEADER_ADDRESS, - m_disc_header_nonpartition); + m_nonpartition_contents.Add(WII_NONPARTITION_DISCHEADER_ADDRESS, std::move(header_bin)); } void DirectoryBlobReader::SetWiiRegionDataFromFile(const std::string& game_partition_root) @@ -594,20 +608,19 @@ void DirectoryBlobReader::SetWiiRegionDataFromFile(const std::string& game_parti void DirectoryBlobReader::SetWiiRegionData(const std::vector& wii_region_data, const std::string& log_path) { - m_wii_region_data.resize(0x10, 0x00); - m_wii_region_data.resize(WII_REGION_DATA_SIZE, 0x80); - Write32(INVALID_REGION, 0, &m_wii_region_data); + std::vector region_data(0x10, 0x00); + region_data.resize(WII_REGION_DATA_SIZE, 0x80); + Write32(INVALID_REGION, 0, ®ion_data); std::copy_n(wii_region_data.begin(), - std::min(wii_region_data.size(), WII_REGION_DATA_SIZE), - m_wii_region_data.begin()); + std::min(wii_region_data.size(), WII_REGION_DATA_SIZE), region_data.begin()); if (wii_region_data.size() < 0x4) ERROR_LOG_FMT(DISCIO, "Couldn't read region from {}", log_path); else if (wii_region_data.size() < 0x20) ERROR_LOG_FMT(DISCIO, "Couldn't read age ratings from {}", log_path); - m_nonpartition_contents.AddReference(WII_REGION_DATA_ADDRESS, m_wii_region_data); + m_nonpartition_contents.Add(WII_REGION_DATA_ADDRESS, std::move(region_data)); } void DirectoryBlobReader::SetPartitions(std::vector&& partitions) @@ -634,14 +647,14 @@ void DirectoryBlobReader::SetPartitions(std::vector&& partiti 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); + std::vector partition_table(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); + Write32(subtable_1_size, 0x0, &partition_table); + Write32((PARTITION_TABLE_ADDRESS + PARTITION_SUBTABLE1_OFFSET) >> 2, 0x4, &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); + Write32(subtable_2_size, 0x8, &partition_table); + Write32((PARTITION_TABLE_ADDRESS + PARTITION_SUBTABLE2_OFFSET) >> 2, 0xC, &partition_table); } constexpr u64 STANDARD_UPDATE_PARTITION_ADDRESS = 0x50000; @@ -656,9 +669,9 @@ void DirectoryBlobReader::SetPartitions(std::vector&& partiti 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); + Write32(static_cast(partition_address >> 2), offset_in_table, &partition_table); offset_in_table += 4; - Write32(static_cast(partitions[i].type), offset_in_table, &m_partition_table); + Write32(static_cast(partitions[i].type), offset_in_table, &partition_table); offset_in_table += 4; SetPartitionHeader(&partitions[i].partition, partition_address); @@ -671,14 +684,14 @@ void DirectoryBlobReader::SetPartitions(std::vector&& partiti const u64 partition_data_offset = partition_address + PARTITION_DATA_OFFSET; m_partitions.emplace(partition_data_offset, std::move(partitions[i].partition)); m_nonpartition_contents.Add(partition_data_offset, encrypted_data_size, - ContentPartition{this, 0, partition_data_offset}); + ContentPartition{0, partition_data_offset}); const u64 unaligned_next_partition_address = VolumeWii::OffsetInHashedPartitionToRawOffset( data_size, Partition(partition_address), PARTITION_DATA_OFFSET); partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull); } m_data_size = partition_address; - m_nonpartition_contents.AddReference(PARTITION_TABLE_ADDRESS, m_partition_table); + m_nonpartition_contents.Add(PARTITION_TABLE_ADDRESS, std::move(partition_table)); } // This function sets the header that's shortly before the start of the encrypted @@ -695,13 +708,12 @@ void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition, u64 ticket_size; if (wrapped_partition) { - const auto& ticket = m_wrapped_volume->GetTicket(*wrapped_partition).GetBytes(); - auto& new_ticket = m_extra_data.emplace_back(ticket); + std::vector new_ticket = m_wrapped_volume->GetTicket(*wrapped_partition).GetBytes(); if (new_ticket.size() > WII_PARTITION_TICKET_SIZE) new_ticket.resize(WII_PARTITION_TICKET_SIZE); ticket_size = new_ticket.size(); - m_nonpartition_contents.AddReference(partition_address + WII_PARTITION_TICKET_ADDRESS, - new_ticket); + m_nonpartition_contents.Add(partition_address + WII_PARTITION_TICKET_ADDRESS, + std::move(new_ticket)); } else { @@ -713,12 +725,11 @@ void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition, u64 tmd_size; if (wrapped_partition) { - const auto& tmd = m_wrapped_volume->GetTMD(*wrapped_partition).GetBytes(); - auto& new_tmd = m_extra_data.emplace_back(tmd); + std::vector new_tmd = m_wrapped_volume->GetTMD(*wrapped_partition).GetBytes(); if (new_tmd.size() > IOS::ES::MAX_TMD_SIZE) new_tmd.resize(IOS::ES::MAX_TMD_SIZE); tmd_size = new_tmd.size(); - m_nonpartition_contents.AddReference(partition_address + TMD_OFFSET, new_tmd); + m_nonpartition_contents.Add(partition_address + TMD_OFFSET, std::move(new_tmd)); } else { @@ -732,12 +743,11 @@ void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition, u64 cert_size; if (wrapped_partition) { - const auto& cert = m_wrapped_volume->GetCertificateChain(*wrapped_partition); - auto& new_cert = m_extra_data.emplace_back(cert); + std::vector new_cert = m_wrapped_volume->GetCertificateChain(*wrapped_partition); if (new_cert.size() > max_cert_size) new_cert.resize(max_cert_size); cert_size = new_cert.size(); - m_nonpartition_contents.AddReference(partition_address + cert_offset, new_cert); + m_nonpartition_contents.Add(partition_address + cert_offset, std::move(new_cert)); } else { @@ -753,11 +763,11 @@ void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition, wrapped_partition->offset + WII_PARTITION_H3_OFFSET_ADDRESS, PARTITION_NONE); if (offset) { - auto& new_h3 = m_extra_data.emplace_back(WII_PARTITION_H3_SIZE); + std::vector new_h3(WII_PARTITION_H3_SIZE); if (m_wrapped_volume->Read(wrapped_partition->offset + *offset, new_h3.size(), new_h3.data(), PARTITION_NONE)) { - m_nonpartition_contents.AddReference(partition_address + H3_OFFSET, new_h3); + m_nonpartition_contents.Add(partition_address + H3_OFFSET, std::move(new_h3)); } } } @@ -770,7 +780,7 @@ void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition, constexpr u32 PARTITION_HEADER_SIZE = 0x1c; const u64 data_size = Common::AlignUp(partition->GetDataSize(), 0x7c00) / 0x7c00 * 0x8000; - std::vector& partition_header = m_extra_data.emplace_back(PARTITION_HEADER_SIZE); + std::vector partition_header(PARTITION_HEADER_SIZE); Write32(static_cast(tmd_size), 0x0, &partition_header); Write32(TMD_OFFSET >> 2, 0x4, &partition_header); Write32(static_cast(cert_size), 0x8, &partition_header); @@ -779,12 +789,12 @@ void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition, Write32(PARTITION_DATA_OFFSET >> 2, 0x14, &partition_header); Write32(static_cast(data_size >> 2), 0x18, &partition_header); - m_nonpartition_contents.AddReference(partition_address + WII_PARTITION_TICKET_SIZE, - partition_header); + m_nonpartition_contents.Add(partition_address + WII_PARTITION_TICKET_SIZE, + std::move(partition_header)); std::vector ticket_buffer(ticket_size); m_nonpartition_contents.Read(partition_address + WII_PARTITION_TICKET_ADDRESS, ticket_size, - ticket_buffer.data()); + ticket_buffer.data(), this); IOS::ES::TicketReader ticket(std::move(ticket_buffer)); if (ticket.IsValid()) partition->SetKey(ticket.GetTitleKey()); @@ -807,8 +817,8 @@ static void GenerateBuilderNodesFromFileSystem(const DiscIO::VolumeDisc& volume, else { std::vector source; - source.emplace_back(BuilderContentSource{ - 0, file_info.GetSize(), ContentVolume{file_info.GetOffset(), &volume, partition}}); + source.emplace_back(BuilderContentSource{0, file_info.GetSize(), + ContentVolume{file_info.GetOffset(), partition}}); nodes->emplace_back( FSTBuilderNode{file_info.GetName(), file_info.GetSize(), std::move(source)}); } @@ -819,19 +829,26 @@ DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory std::optional is_wii) : m_root_directory(root_directory) { - SetDiscHeaderFromFile(m_root_directory + "sys/boot.bin"); - SetDiscType(is_wii); + std::vector disc_header(DISCHEADER_SIZE); + if (ReadFileToVector(m_root_directory + "sys/boot.bin", &disc_header) < 0x20) + ERROR_LOG_FMT(DISCIO, "{} doesn't exist or is too small", m_root_directory + "sys/boot.bin"); + + SetDiscType(is_wii, disc_header); SetBI2FromFile(m_root_directory + "sys/bi2.bin"); const u64 dol_address = SetApploaderFromFile(m_root_directory + "sys/apploader.img"); - const u64 fst_address = SetDOLFromFile(m_root_directory + "sys/main.dol", dol_address); - BuildFSTFromFolder(m_root_directory + "files/", fst_address); + const u64 fst_address = + SetDOLFromFile(m_root_directory + "sys/main.dol", dol_address, &disc_header); + BuildFSTFromFolder(m_root_directory + "files/", fst_address, &disc_header); + + m_contents.Add(DISCHEADER_ADDRESS, disc_header); } static void FillSingleFileNode(FSTBuilderNode* node, std::vector data) { std::vector contents; const size_t size = data.size(); - contents.emplace_back(BuilderContentSource{0, size, ContentByteVector{std::move(data)}}); + contents.emplace_back( + BuilderContentSource{0, size, std::make_shared>(std::move(data))}); node->m_size = size; node->m_content = std::move(contents); } @@ -844,7 +861,8 @@ static FSTBuilderNode BuildSingleFileNode(std::string filename, std::vector return node; } -static std::vector ExtractNodeToVector(std::vector* nodes, void* userdata) +static std::vector ExtractNodeToVector(std::vector* nodes, void* userdata, + DirectoryBlobReader* blob) { std::vector data; const auto it = @@ -858,7 +876,7 @@ static std::vector ExtractNodeToVector(std::vector* nodes, v for (auto& content : it->GetFileContent()) tmp.Add(content.m_offset, content.m_size, std::move(content.m_source)); data.resize(it->m_size); - tmp.Read(0, it->m_size, data.data()); + tmp.Read(0, it->m_size, data.data(), blob); return data; } @@ -866,7 +884,8 @@ DirectoryBlobPartition::DirectoryBlobPartition( DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional is_wii, const std::function* fst_nodes)>& sys_callback, const std::function* fst_nodes, FSTBuilderNode* dol_node)>& - fst_callback) + fst_callback, + DirectoryBlobReader* blob) : m_wrapped_partition(partition) { std::vector sys_nodes; @@ -874,17 +893,16 @@ DirectoryBlobPartition::DirectoryBlobPartition( std::vector disc_header(DISCHEADER_SIZE); if (!volume->Read(DISCHEADER_ADDRESS, DISCHEADER_SIZE, disc_header.data(), partition)) disc_header.clear(); - sys_nodes.emplace_back(BuildSingleFileNode("boot.bin", std::move(disc_header), &m_disc_header)); + sys_nodes.emplace_back(BuildSingleFileNode("boot.bin", std::move(disc_header), &disc_header)); std::vector bi2(BI2_SIZE); if (!volume->Read(BI2_ADDRESS, BI2_SIZE, bi2.data(), partition)) bi2.clear(); - sys_nodes.emplace_back(BuildSingleFileNode("bi2.bin", std::move(bi2), &m_bi2)); + sys_nodes.emplace_back(BuildSingleFileNode("bi2.bin", std::move(bi2), &bi2)); std::vector apploader; const auto apploader_size = GetApploaderSize(*volume, partition); - auto& apploader_node = - sys_nodes.emplace_back(FSTBuilderNode{"apploader.img", 0, {}, &m_apploader}); + auto& apploader_node = sys_nodes.emplace_back(FSTBuilderNode{"apploader.img", 0, {}, &apploader}); if (apploader_size) { apploader.resize(*apploader_size); @@ -896,11 +914,12 @@ DirectoryBlobPartition::DirectoryBlobPartition( if (sys_callback) sys_callback(&sys_nodes); - SetDiscHeader(ExtractNodeToVector(&sys_nodes, &m_disc_header)); - SetDiscType(is_wii); - SetBI2(ExtractNodeToVector(&sys_nodes, &m_bi2)); + disc_header = ExtractNodeToVector(&sys_nodes, &disc_header, blob); + disc_header.resize(DISCHEADER_SIZE); + SetDiscType(is_wii, disc_header); + SetBI2(ExtractNodeToVector(&sys_nodes, &bi2, blob)); const u64 new_dol_address = - SetApploader(ExtractNodeToVector(&sys_nodes, &m_apploader), "apploader"); + SetApploader(ExtractNodeToVector(&sys_nodes, &apploader, blob), "apploader"); FSTBuilderNode dol_node{"main.dol", 0, {}}; const auto dol_offset = GetBootDOLOffset(*volume, partition); @@ -911,7 +930,7 @@ DirectoryBlobPartition::DirectoryBlobPartition( { std::vector dol_contents; dol_contents.emplace_back( - BuilderContentSource{0, *dol_size, ContentVolume{*dol_offset, volume, partition}}); + BuilderContentSource{0, *dol_size, ContentVolume{*dol_offset, partition}}); dol_node.m_size = *dol_size; dol_node.m_content = std::move(dol_contents); } @@ -926,27 +945,14 @@ DirectoryBlobPartition::DirectoryBlobPartition( if (fst_callback) fst_callback(&nodes, &dol_node); - const u64 new_fst_address = SetDOL(std::move(dol_node), new_dol_address); - BuildFST(std::move(nodes), new_fst_address); + const u64 new_fst_address = SetDOL(std::move(dol_node), new_dol_address, &disc_header); + BuildFST(std::move(nodes), new_fst_address, &disc_header); + + m_contents.Add(DISCHEADER_ADDRESS, disc_header); } -void DirectoryBlobPartition::SetDiscHeaderFromFile(const std::string& boot_bin_path) -{ - m_disc_header.resize(DISCHEADER_SIZE); - if (ReadFileToVector(boot_bin_path, &m_disc_header) < 0x20) - ERROR_LOG_FMT(DISCIO, "{} doesn't exist or is too small", boot_bin_path); - - m_contents.AddReference(DISCHEADER_ADDRESS, m_disc_header); -} - -void DirectoryBlobPartition::SetDiscHeader(std::vector boot_bin) -{ - m_disc_header = std::move(boot_bin); - m_disc_header.resize(DISCHEADER_SIZE); - m_contents.AddReference(DISCHEADER_ADDRESS, m_disc_header); -} - -void DirectoryBlobPartition::SetDiscType(std::optional is_wii) +void DirectoryBlobPartition::SetDiscType(std::optional is_wii, + const std::vector& disc_header) { if (is_wii.has_value()) { @@ -954,8 +960,8 @@ void DirectoryBlobPartition::SetDiscType(std::optional is_wii) } else { - m_is_wii = Common::swap32(&m_disc_header[0x18]) == WII_DISC_MAGIC; - const bool is_gc = Common::swap32(&m_disc_header[0x1c]) == GAMECUBE_DISC_MAGIC; + m_is_wii = Common::swap32(&disc_header[0x18]) == WII_DISC_MAGIC; + const bool is_gc = Common::swap32(&disc_header[0x1c]) == GAMECUBE_DISC_MAGIC; if (m_is_wii == is_gc) { ERROR_LOG_FMT(DISCIO, "Couldn't detect disc type based on disc header; assuming {}", @@ -968,28 +974,27 @@ void DirectoryBlobPartition::SetDiscType(std::optional is_wii) void DirectoryBlobPartition::SetBI2FromFile(const std::string& bi2_path) { - m_bi2.resize(BI2_SIZE); + std::vector bi2(BI2_SIZE); if (!m_is_wii) - Write32(INVALID_REGION, 0x18, &m_bi2); + Write32(INVALID_REGION, 0x18, &bi2); - const size_t bytes_read = ReadFileToVector(bi2_path, &m_bi2); + const size_t bytes_read = ReadFileToVector(bi2_path, &bi2); if (!m_is_wii && bytes_read < 0x1C) ERROR_LOG_FMT(DISCIO, "Couldn't read region from {}", bi2_path); - m_contents.AddReference(BI2_ADDRESS, m_bi2); + m_contents.Add(BI2_ADDRESS, std::move(bi2)); } void DirectoryBlobPartition::SetBI2(std::vector bi2) { const size_t bi2_size = bi2.size(); - m_bi2 = std::move(bi2); - m_bi2.resize(BI2_SIZE); + bi2.resize(BI2_SIZE); if (!m_is_wii && bi2_size < 0x1C) - Write32(INVALID_REGION, 0x18, &m_bi2); + Write32(INVALID_REGION, 0x18, &bi2); - m_contents.AddReference(BI2_ADDRESS, m_bi2); + m_contents.Add(BI2_ADDRESS, std::move(bi2)); } u64 DirectoryBlobPartition::SetApploaderFromFile(const std::string& path) @@ -1004,16 +1009,15 @@ u64 DirectoryBlobPartition::SetApploader(std::vector apploader, const std::s { bool success = false; - m_apploader = std::move(apploader); - if (m_apploader.size() < 0x20) + if (apploader.size() < 0x20) { ERROR_LOG_FMT(DISCIO, "{} couldn't be accessed or is too small", log_path); } else { - const size_t apploader_size = 0x20 + Common::swap32(*(u32*)&m_apploader[0x14]) + - Common::swap32(*(u32*)&m_apploader[0x18]); - if (apploader_size != m_apploader.size()) + const size_t apploader_size = + 0x20 + Common::swap32(*(u32*)&apploader[0x14]) + Common::swap32(*(u32*)&apploader[0x18]); + if (apploader_size != apploader.size()) ERROR_LOG_FMT(DISCIO, "{} is the wrong size... Is it really an apploader?", log_path); else success = true; @@ -1021,33 +1025,36 @@ u64 DirectoryBlobPartition::SetApploader(std::vector apploader, const std::s if (!success) { - m_apploader.resize(0x20); + apploader.resize(0x20); // Make sure BS2 HLE doesn't try to run the apploader - Write32(static_cast(-1), 0x10, &m_apploader); + Write32(static_cast(-1), 0x10, &apploader); } - m_contents.AddReference(APPLOADER_ADDRESS, m_apploader); + size_t apploader_size = apploader.size(); + m_contents.Add(APPLOADER_ADDRESS, std::move(apploader)); // Return DOL address, 32 byte aligned (plus 32 byte padding) - return Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); + return Common::AlignUp(APPLOADER_ADDRESS + apploader_size + 0x20, 0x20ull); } -u64 DirectoryBlobPartition::SetDOLFromFile(const std::string& path, u64 dol_address) +u64 DirectoryBlobPartition::SetDOLFromFile(const std::string& path, u64 dol_address, + std::vector* disc_header) { const u64 dol_size = m_contents.CheckSizeAndAdd(dol_address, path); - Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disc_header); + Write32(static_cast(dol_address >> m_address_shift), 0x0420, disc_header); // Return FST address, 32 byte aligned (plus 32 byte padding) return Common::AlignUp(dol_address + dol_size + 0x20, 0x20ull); } -u64 DirectoryBlobPartition::SetDOL(FSTBuilderNode dol_node, u64 dol_address) +u64 DirectoryBlobPartition::SetDOL(FSTBuilderNode dol_node, u64 dol_address, + std::vector* disc_header) { for (auto& content : dol_node.GetFileContent()) m_contents.Add(dol_address + content.m_offset, content.m_size, std::move(content.m_source)); - Write32(static_cast(dol_address >> m_address_shift), 0x0420, &m_disc_header); + Write32(static_cast(dol_address >> m_address_shift), 0x0420, disc_header); // Return FST address, 32 byte aligned (plus 32 byte padding) return Common::AlignUp(dol_address + dol_node.m_size + 0x20, 0x20ull); @@ -1075,10 +1082,11 @@ static std::vector ConvertFSTEntriesToBuilderNodes(const File::F return nodes; } -void DirectoryBlobPartition::BuildFSTFromFolder(const std::string& fst_root_path, u64 fst_address) +void DirectoryBlobPartition::BuildFSTFromFolder(const std::string& fst_root_path, u64 fst_address, + std::vector* disc_header) { auto nodes = ConvertFSTEntriesToBuilderNodes(File::ScanDirectoryTree(fst_root_path, true)); - BuildFST(std::move(nodes), fst_address); + BuildFST(std::move(nodes), fst_address, disc_header); } static void ConvertUTF8NamesToSHIFTJIS(std::vector* fst) @@ -1118,10 +1126,9 @@ static size_t RecalculateFolderSizes(std::vector* fst) return size; } -void DirectoryBlobPartition::BuildFST(std::vector root_nodes, u64 fst_address) +void DirectoryBlobPartition::BuildFST(std::vector root_nodes, u64 fst_address, + std::vector* disc_header) { - m_fst_data.clear(); - ConvertUTF8NamesToSHIFTJIS(&root_nodes); u32 name_table_size = Common::AlignUp(ComputeNameSize(root_nodes), 1ull << m_address_shift); @@ -1130,59 +1137,61 @@ void DirectoryBlobPartition::BuildFST(std::vector root_nodes, u6 u64 total_entries = RecalculateFolderSizes(&root_nodes) + 1; const u64 name_table_offset = total_entries * ENTRY_SIZE; - m_fst_data.resize(name_table_offset + name_table_size); + std::vector fst_data(name_table_offset + name_table_size); // 32 KiB aligned start of data on disc - u64 current_data_address = Common::AlignUp(fst_address + m_fst_data.size(), 0x8000ull); + u64 current_data_address = Common::AlignUp(fst_address + fst_data.size(), 0x8000ull); 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); + WriteEntryData(&fst_data, &fst_offset, DIRECTORY_ENTRY, 0, 0, total_entries, m_address_shift); - WriteDirectory(&root_nodes, &fst_offset, &name_offset, ¤t_data_address, root_offset, - name_table_offset); + WriteDirectory(&fst_data, &root_nodes, &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); // write FST size and location - 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); + Write32((u32)(fst_address >> m_address_shift), 0x0424, disc_header); + Write32((u32)(fst_data.size() >> m_address_shift), 0x0428, disc_header); + Write32((u32)(fst_data.size() >> m_address_shift), 0x042c, disc_header); - m_contents.AddReference(fst_address, m_fst_data); + m_contents.Add(fst_address, std::move(fst_data)); m_data_size = current_data_address; } -void DirectoryBlobPartition::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, - u64 data_offset, u64 length, u32 address_shift) +void DirectoryBlobPartition::WriteEntryData(std::vector* fst_data, u32* entry_offset, u8 type, + u32 name_offset, u64 data_offset, u64 length, + u32 address_shift) { - m_fst_data[(*entry_offset)++] = type; + (*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; + (*fst_data)[(*entry_offset)++] = (name_offset >> 16) & 0xff; + (*fst_data)[(*entry_offset)++] = (name_offset >> 8) & 0xff; + (*fst_data)[(*entry_offset)++] = (name_offset)&0xff; - Write32((u32)(data_offset >> address_shift), *entry_offset, &m_fst_data); + Write32((u32)(data_offset >> address_shift), *entry_offset, fst_data); *entry_offset += 4; - Write32((u32)length, *entry_offset, &m_fst_data); + Write32((u32)length, *entry_offset, fst_data); *entry_offset += 4; } -void DirectoryBlobPartition::WriteEntryName(u32* name_offset, const std::string& name, - u64 name_table_offset) +void DirectoryBlobPartition::WriteEntryName(std::vector* fst_data, 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); + strncpy((char*)&(*fst_data)[*name_offset + name_table_offset], name.c_str(), name.length() + 1); *name_offset += (u32)(name.length() + 1); } -void DirectoryBlobPartition::WriteDirectory(std::vector* parent_entries, +void DirectoryBlobPartition::WriteDirectory(std::vector* fst_data, + std::vector* parent_entries, u32* fst_offset, u32* name_offset, u64* data_offset, u32 parent_entry_index, u64 name_table_offset) { @@ -1204,20 +1213,20 @@ void DirectoryBlobPartition::WriteDirectory(std::vector* parent_ if (entry.IsFolder()) { u32 entry_index = *fst_offset / ENTRY_SIZE; - WriteEntryData(fst_offset, DIRECTORY_ENTRY, *name_offset, parent_entry_index, + WriteEntryData(fst_data, fst_offset, DIRECTORY_ENTRY, *name_offset, parent_entry_index, entry_index + entry.m_size + 1, 0); - WriteEntryName(name_offset, entry.m_filename, name_table_offset); + WriteEntryName(fst_data, name_offset, entry.m_filename, name_table_offset); auto& child_nodes = entry.GetFolderContent(); - WriteDirectory(&child_nodes, fst_offset, name_offset, data_offset, entry_index, + WriteDirectory(fst_data, &child_nodes, 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.m_size, + WriteEntryData(fst_data, fst_offset, FILE_ENTRY, *name_offset, *data_offset, entry.m_size, m_address_shift); - WriteEntryName(name_offset, entry.m_filename, name_table_offset); + WriteEntryName(fst_data, name_offset, entry.m_filename, name_table_offset); // write entry to virtual disc auto& contents = entry.GetFileContent(); diff --git a/Source/Core/DiscIO/DirectoryBlob.h b/Source/Core/DiscIO/DirectoryBlob.h index 16c3cc4609..39fe05b163 100644 --- a/Source/Core/DiscIO/DirectoryBlob.h +++ b/Source/Core/DiscIO/DirectoryBlob.h @@ -46,13 +46,13 @@ struct ContentFile u64 m_offset = 0; }; +// Content chunk that's just a direct block of memory +typedef std::shared_ptr> ContentMemory; + // Content chunk that loads data from a DirectoryBlobReader. // Intented for representing a partition within a disc. struct ContentPartition { - // The reader to read data from. - DirectoryBlobReader* m_reader; - // Offset from the start of the partition for the first byte represented by this chunk. u64 m_offset = 0; @@ -66,9 +66,6 @@ struct ContentVolume // Offset from the start of the volume for the first byte represented by this chunk. u64 m_offset = 0; - // The volume to read data from. - const Volume* m_volume = nullptr; - // The partition passed to the Volume's Read() method. Partition m_partition; }; @@ -80,18 +77,11 @@ struct ContentFixedByte u8 m_byte = 0; }; -// Content chunk representing an arbitrary byte sequence that's stored within the struct itself. -struct ContentByteVector -{ - std::vector m_bytes; -}; - using ContentSource = std::variant; struct BuilderContentSource @@ -147,7 +137,7 @@ public: u64 GetOffset() const; u64 GetEndOffset() const; u64 GetSize() const; - bool Read(u64* offset, u64* length, u8** buffer) const; + bool Read(u64* offset, u64* length, u8** buffer, DirectoryBlobReader* blob) const; bool operator==(const DiscContent& other) const { return GetEndOffset() == other.GetEndOffset(); } bool operator!=(const DiscContent& other) const { return !(*this == other); } @@ -170,16 +160,16 @@ private: class DiscContentContainer { public: - template - void AddReference(u64 offset, const std::vector& vector) + void Add(u64 offset, std::vector vector) { - return Add(offset, vector.size() * sizeof(T), reinterpret_cast(vector.data())); + size_t vector_size = vector.size(); + return Add(offset, vector_size, std::make_shared>(std::move(vector))); } void Add(u64 offset, u64 size, ContentSource source); u64 CheckSizeAndAdd(u64 offset, const std::string& path); u64 CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path); - bool Read(u64 offset, u64 length, u8* buffer) const; + bool Read(u64 offset, u64 length, u8* buffer, DirectoryBlobReader* blob) const; private: std::set m_contents; @@ -194,11 +184,11 @@ public: DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional is_wii, const std::function* fst_nodes)>& sys_callback, const std::function* fst_nodes, FSTBuilderNode* dol_node)>& - fst_callback); + fst_callback, + DirectoryBlobReader* blob); - // We do not allow copying, because it might mess up the pointers inside DiscContents - DirectoryBlobPartition(const DirectoryBlobPartition&) = delete; - DirectoryBlobPartition& operator=(const DirectoryBlobPartition&) = delete; + DirectoryBlobPartition(const DirectoryBlobPartition&) = default; + DirectoryBlobPartition& operator=(const DirectoryBlobPartition&) = default; DirectoryBlobPartition(DirectoryBlobPartition&&) = default; DirectoryBlobPartition& operator=(DirectoryBlobPartition&&) = default; @@ -206,7 +196,6 @@ public: u64 GetDataSize() const { return m_data_size; } void SetDataSize(u64 size) { m_data_size = size; } const std::string& GetRootDirectory() const { return m_root_directory; } - const std::vector& GetHeader() const { return m_disc_header; } const DiscContentContainer& GetContents() const { return m_contents; } const std::optional& GetWrappedPartition() const { @@ -217,9 +206,7 @@ public: void SetKey(std::array key) { m_key = key; } private: - void SetDiscHeaderFromFile(const std::string& boot_bin_path); - void SetDiscHeader(std::vector boot_bin); - void SetDiscType(std::optional is_wii); + void SetDiscType(std::optional is_wii, const std::vector& disc_header); void SetBI2FromFile(const std::string& bi2_path); void SetBI2(std::vector bi2); @@ -227,25 +214,24 @@ private: u64 SetApploaderFromFile(const std::string& path); u64 SetApploader(std::vector apploader, const std::string& log_path); // Returns FST address - u64 SetDOLFromFile(const std::string& path, u64 dol_address); - u64 SetDOL(FSTBuilderNode dol_node, u64 dol_address); + u64 SetDOLFromFile(const std::string& path, u64 dol_address, std::vector* disc_header); + u64 SetDOL(FSTBuilderNode dol_node, u64 dol_address, std::vector* disc_header); - void BuildFSTFromFolder(const std::string& fst_root_path, u64 fst_address); - void BuildFST(std::vector root_nodes, u64 fst_address); + void BuildFSTFromFolder(const std::string& fst_root_path, u64 fst_address, + std::vector* disc_header); + void BuildFST(std::vector root_nodes, u64 fst_address, + std::vector* disc_header); // FST creation - void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, - u32 address_shift); - void WriteEntryName(u32* name_offset, const std::string& name, u64 name_table_offset); - void WriteDirectory(std::vector* parent_entries, u32* fst_offset, - u32* name_offset, u64* data_offset, u32 parent_entry_index, + void WriteEntryData(std::vector* fst_data, u32* entry_offset, u8 type, u32 name_offset, + u64 data_offset, u64 length, u32 address_shift); + void WriteEntryName(std::vector* fst_data, u32* name_offset, const std::string& name, + u64 name_table_offset); + void WriteDirectory(std::vector* fst_data, std::vector* parent_entries, + u32* fst_offset, u32* name_offset, u64* data_offset, u32 parent_entry_index, u64 name_table_offset); DiscContentContainer m_contents; - std::vector m_disc_header; - std::vector m_bi2; - std::vector m_apploader; - std::vector m_fst_data; std::array m_key{}; @@ -271,9 +257,6 @@ public: const std::function* fst_nodes, FSTBuilderNode* dol_node)>& fst_callback); - // We do not allow copying, because it might mess up the pointers inside DiscContents - DirectoryBlobReader(const DirectoryBlobReader&) = delete; - DirectoryBlobReader& operator=(const DirectoryBlobReader&) = delete; DirectoryBlobReader(DirectoryBlobReader&&) = default; DirectoryBlobReader& operator=(DirectoryBlobReader&&) = default; @@ -282,6 +265,7 @@ public: bool ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_data_offset) override; BlobType GetBlobType() const override; + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override; u64 GetDataSize() const override; @@ -311,6 +295,7 @@ private: const std::function* fst_nodes)>& sys_callback, const std::function* fst_nodes, FSTBuilderNode* dol_node)>& fst_callback); + explicit DirectoryBlobReader(const DirectoryBlobReader& rhs); const DirectoryBlobPartition* GetPartition(u64 offset, u64 size, u64 partition_data_offset) const; @@ -326,6 +311,8 @@ private: void SetPartitions(std::vector&& partitions); void SetPartitionHeader(DirectoryBlobPartition* partition, u64 partition_address); + DiscIO::VolumeDisc* GetWrappedVolume() { return m_wrapped_volume.get(); } + // For GameCube: DirectoryBlobPartition m_gamecube_pseudopartition; @@ -337,11 +324,6 @@ private: bool m_is_wii; bool m_encrypted; - std::vector m_disc_header_nonpartition; - std::vector m_partition_table; - std::vector m_wii_region_data; - std::vector> m_extra_data; - u64 m_data_size; std::unique_ptr m_wrapped_volume; diff --git a/Source/Core/DiscIO/DiscScrubber.cpp b/Source/Core/DiscIO/DiscScrubber.cpp index 957fde32b9..41d59a03c2 100644 --- a/Source/Core/DiscIO/DiscScrubber.cpp +++ b/Source/Core/DiscIO/DiscScrubber.cpp @@ -22,7 +22,6 @@ namespace DiscIO { DiscScrubber::DiscScrubber() = default; -DiscScrubber::~DiscScrubber() = default; bool DiscScrubber::SetupScrub(const Volume& disc) { diff --git a/Source/Core/DiscIO/DiscScrubber.h b/Source/Core/DiscIO/DiscScrubber.h index 87528fba3b..cf69615fdd 100644 --- a/Source/Core/DiscIO/DiscScrubber.h +++ b/Source/Core/DiscIO/DiscScrubber.h @@ -27,7 +27,6 @@ class DiscScrubber final { public: DiscScrubber(); - ~DiscScrubber(); bool SetupScrub(const Volume& disc); diff --git a/Source/Core/DiscIO/FileBlob.cpp b/Source/Core/DiscIO/FileBlob.cpp index 6011f45ca9..97b95d1b8d 100644 --- a/Source/Core/DiscIO/FileBlob.cpp +++ b/Source/Core/DiscIO/FileBlob.cpp @@ -28,6 +28,11 @@ std::unique_ptr PlainFileReader::Create(File::IOFile file) return nullptr; } +std::unique_ptr PlainFileReader::CopyReader() const +{ + return Create(m_file.Duplicate("rb")); +} + bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { if (m_file.Seek(offset, File::SeekOrigin::Begin) && m_file.ReadBytes(out_ptr, nbytes)) diff --git a/Source/Core/DiscIO/FileBlob.h b/Source/Core/DiscIO/FileBlob.h index 1f8bb8bcf6..66514e8a4b 100644 --- a/Source/Core/DiscIO/FileBlob.h +++ b/Source/Core/DiscIO/FileBlob.h @@ -19,6 +19,7 @@ public: static std::unique_ptr Create(File::IOFile file); BlobType GetBlobType() const override { return BlobType::PLAIN; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override { return m_size; } u64 GetDataSize() const override { return m_size; } diff --git a/Source/Core/DiscIO/NFSBlob.cpp b/Source/Core/DiscIO/NFSBlob.cpp index 3960fff75e..4b33596802 100644 --- a/Source/Core/DiscIO/NFSBlob.cpp +++ b/Source/Core/DiscIO/NFSBlob.cpp @@ -160,11 +160,20 @@ std::unique_ptr NFSFileReader::Create(File::IOFile first_file, NFSFileReader::NFSFileReader(std::vector lba_ranges, std::vector files, Key key, u64 raw_size) : m_lba_ranges(std::move(lba_ranges)), m_files(std::move(files)), - m_aes_context(Common::AES::CreateContextDecrypt(key.data())), m_raw_size(raw_size) + m_aes_context(Common::AES::CreateContextDecrypt(key.data())), m_raw_size(raw_size), m_key(key) { m_data_size = CalculateExpectedDataSize(m_lba_ranges); } +std::unique_ptr NFSFileReader::CopyReader() const +{ + std::vector new_files{}; + for (const File::IOFile& file : m_files) + new_files.push_back(file.Duplicate("rb")); + return std::unique_ptr( + new NFSFileReader(m_lba_ranges, std::move(new_files), m_key, m_raw_size)); +} + u64 NFSFileReader::GetDataSize() const { return m_data_size; diff --git a/Source/Core/DiscIO/NFSBlob.h b/Source/Core/DiscIO/NFSBlob.h index c17687471d..78f7b871cb 100644 --- a/Source/Core/DiscIO/NFSBlob.h +++ b/Source/Core/DiscIO/NFSBlob.h @@ -45,6 +45,7 @@ public: const std::string& directory_path); BlobType GetBlobType() const override { return BlobType::NFS; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override; u64 GetDataSize() const override; @@ -86,6 +87,7 @@ private: std::unique_ptr m_aes_context; u64 m_raw_size; u64 m_data_size; + Key m_key; }; } // namespace DiscIO diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index 309e9e5ea1..9362a3930a 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -234,13 +234,23 @@ static void SplitAt(BuilderContentSource* before, BuilderContentSource* after, u after->m_offset += before->m_size; after->m_size = end - split_at; if (std::holds_alternative(after->m_source)) + { std::get(after->m_source).m_offset += before->m_size; - else if (std::holds_alternative(after->m_source)) - std::get(after->m_source) += before->m_size; + } + else if (std::holds_alternative(after->m_source)) + { + after->m_source = std::make_shared>( + std::get(after->m_source)->begin() + before->m_size, + std::get(after->m_source)->end()); + } else if (std::holds_alternative(after->m_source)) + { std::get(after->m_source).m_offset += before->m_size; + } else if (std::holds_alternative(after->m_source)) + { std::get(after->m_source).m_offset += before->m_size; + } } static void ApplyPatchToFile(const Patch& patch, DiscIO::FSTBuilderNode* file_node, diff --git a/Source/Core/DiscIO/ScrubbedBlob.cpp b/Source/Core/DiscIO/ScrubbedBlob.cpp index 84a123e4de..dd8908e303 100644 --- a/Source/Core/DiscIO/ScrubbedBlob.cpp +++ b/Source/Core/DiscIO/ScrubbedBlob.cpp @@ -37,6 +37,11 @@ std::unique_ptr ScrubbedBlob::Create(const std::string& path) return std::unique_ptr(new ScrubbedBlob(std::move(blob), std::move(scrubber))); } +std::unique_ptr ScrubbedBlob::CopyReader() const +{ + return std::unique_ptr(new ScrubbedBlob(m_blob_reader->CopyReader(), m_scrubber)); +} + bool ScrubbedBlob::Read(u64 offset, u64 size, u8* out_ptr) { while (size > 0) diff --git a/Source/Core/DiscIO/ScrubbedBlob.h b/Source/Core/DiscIO/ScrubbedBlob.h index fa5648630b..bd129f65b0 100644 --- a/Source/Core/DiscIO/ScrubbedBlob.h +++ b/Source/Core/DiscIO/ScrubbedBlob.h @@ -19,6 +19,7 @@ public: static std::unique_ptr Create(const std::string& path); BlobType GetBlobType() const override { return m_blob_reader->GetBlobType(); } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override { return m_blob_reader->GetRawSize(); } u64 GetDataSize() const override { return m_blob_reader->GetDataSize(); } diff --git a/Source/Core/DiscIO/SplitFileBlob.cpp b/Source/Core/DiscIO/SplitFileBlob.cpp index f3a0895614..4756088a40 100644 --- a/Source/Core/DiscIO/SplitFileBlob.cpp +++ b/Source/Core/DiscIO/SplitFileBlob.cpp @@ -56,6 +56,17 @@ std::unique_ptr SplitPlainFileReader::Create(std::string_v return std::unique_ptr(new SplitPlainFileReader(std::move(files))); } +std::unique_ptr SplitPlainFileReader::CopyReader() const +{ + std::vector new_files{}; + for (const SingleFile& file : m_files) + { + new_files.push_back( + {.file = file.file.Duplicate("rb"), .offset = file.offset, .size = file.size}); + } + return std::unique_ptr(new SplitPlainFileReader(std::move(new_files))); +} + bool SplitPlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { if (offset >= m_size) diff --git a/Source/Core/DiscIO/SplitFileBlob.h b/Source/Core/DiscIO/SplitFileBlob.h index 4b3c635150..d3268dca80 100644 --- a/Source/Core/DiscIO/SplitFileBlob.h +++ b/Source/Core/DiscIO/SplitFileBlob.h @@ -21,6 +21,7 @@ public: static std::unique_ptr Create(std::string_view first_file_path); BlobType GetBlobType() const override { return BlobType::SPLIT_PLAIN; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override { return m_size; } u64 GetDataSize() const override { return m_size; } diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp index c61d0763a4..94ad394861 100644 --- a/Source/Core/DiscIO/TGCBlob.cpp +++ b/Source/Core/DiscIO/TGCBlob.cpp @@ -98,6 +98,11 @@ TGCFileReader::TGCFileReader(File::IOFile file) : m_file(std::move(file)) } } +std::unique_ptr TGCFileReader::CopyReader() const +{ + return Create(m_file.Duplicate("rb")); +} + u64 TGCFileReader::GetDataSize() const { return m_size - Common::swap32(m_header.tgc_header_size); diff --git a/Source/Core/DiscIO/TGCBlob.h b/Source/Core/DiscIO/TGCBlob.h index 2db1c9e8b7..2952f2809f 100644 --- a/Source/Core/DiscIO/TGCBlob.h +++ b/Source/Core/DiscIO/TGCBlob.h @@ -42,6 +42,7 @@ public: static std::unique_ptr Create(File::IOFile file); BlobType GetBlobType() const override { return BlobType::TGC; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override { return m_size; } u64 GetDataSize() const override; diff --git a/Source/Core/DiscIO/VolumeFileBlobReader.cpp b/Source/Core/DiscIO/VolumeFileBlobReader.cpp index f6be7e3a34..7cbc06e589 100644 --- a/Source/Core/DiscIO/VolumeFileBlobReader.cpp +++ b/Source/Core/DiscIO/VolumeFileBlobReader.cpp @@ -33,6 +33,12 @@ VolumeFileBlobReader::VolumeFileBlobReader(const Volume& volume, const Partition { } +std::unique_ptr VolumeFileBlobReader::CopyReader() const +{ + ASSERT_MSG(DISCIO, false, "Unimplemented"); + return nullptr; +} + u64 VolumeFileBlobReader::GetDataSize() const { return m_file_info->GetSize(); diff --git a/Source/Core/DiscIO/VolumeFileBlobReader.h b/Source/Core/DiscIO/VolumeFileBlobReader.h index 89b87a9470..58d349a0d4 100644 --- a/Source/Core/DiscIO/VolumeFileBlobReader.h +++ b/Source/Core/DiscIO/VolumeFileBlobReader.h @@ -22,6 +22,7 @@ public: Create(const Volume& volume, const Partition& partition, std::string_view file_path); BlobType GetBlobType() const override { return BlobType::PLAIN; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override; u64 GetDataSize() const override; diff --git a/Source/Core/DiscIO/WIABlob.cpp b/Source/Core/DiscIO/WIABlob.cpp index 65c6aaa484..a9496fe5a0 100644 --- a/Source/Core/DiscIO/WIABlob.cpp +++ b/Source/Core/DiscIO/WIABlob.cpp @@ -79,7 +79,7 @@ std::pair GetAllowedCompressionLevels(WIARVZCompressionType compressio template WIARVZFileReader::WIARVZFileReader(File::IOFile file, const std::string& path) - : m_file(std::move(file)), m_encryption_cache(this) + : m_file(std::move(file)), m_path(path), m_encryption_cache(this) { m_valid = Initialize(path); } @@ -286,6 +286,12 @@ BlobType WIARVZFileReader::GetBlobType() const return RVZ ? BlobType::RVZ : BlobType::WIA; } +template +std::unique_ptr WIARVZFileReader::CopyReader() const +{ + return Create(m_file.Duplicate("rb"), m_path); +} + template std::string WIARVZFileReader::GetCompressionMethod() const { diff --git a/Source/Core/DiscIO/WIABlob.h b/Source/Core/DiscIO/WIABlob.h index 633c5801ce..c5a5476c09 100644 --- a/Source/Core/DiscIO/WIABlob.h +++ b/Source/Core/DiscIO/WIABlob.h @@ -49,6 +49,7 @@ public: static std::unique_ptr Create(File::IOFile file, const std::string& path); BlobType GetBlobType() const override; + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override { return Common::swap64(m_header_1.wia_file_size); } u64 GetDataSize() const override { return Common::swap64(m_header_1.iso_file_size); } @@ -365,6 +366,7 @@ private: WIARVZCompressionType m_compression_type; File::IOFile m_file; + std::string m_path; Chunk m_cached_chunk; u64 m_cached_chunk_offset = std::numeric_limits::max(); WiiEncryptionCache m_encryption_cache; diff --git a/Source/Core/DiscIO/WbfsBlob.cpp b/Source/Core/DiscIO/WbfsBlob.cpp index d35b0b76a4..d61799a77a 100644 --- a/Source/Core/DiscIO/WbfsBlob.cpp +++ b/Source/Core/DiscIO/WbfsBlob.cpp @@ -29,7 +29,8 @@ WbfsFileReader::WbfsFileReader(File::IOFile file, const std::string& path) { if (!AddFileToList(std::move(file))) return; - OpenAdditionalFiles(path); + if (!path.empty()) + OpenAdditionalFiles(path); if (!ReadHeader()) return; m_good = true; @@ -47,6 +48,15 @@ WbfsFileReader::~WbfsFileReader() { } +std::unique_ptr WbfsFileReader::CopyReader() const +{ + auto retval = + std::unique_ptr(new WbfsFileReader(m_files[0].file.Duplicate("rb"))); + for (size_t ix = 1; ix < m_files.size(); ix++) + retval->AddFileToList(m_files[ix].file.Duplicate("rb")); + return retval; +} + u64 WbfsFileReader::GetDataSize() const { return WII_SECTOR_COUNT * WII_SECTOR_SIZE; diff --git a/Source/Core/DiscIO/WbfsBlob.h b/Source/Core/DiscIO/WbfsBlob.h index a981790f1c..52af3f9e06 100644 --- a/Source/Core/DiscIO/WbfsBlob.h +++ b/Source/Core/DiscIO/WbfsBlob.h @@ -23,6 +23,7 @@ public: static std::unique_ptr Create(File::IOFile file, const std::string& path); BlobType GetBlobType() const override { return BlobType::WBFS; } + std::unique_ptr CopyReader() const override; u64 GetRawSize() const override { return m_size; } u64 GetDataSize() const override; @@ -36,7 +37,7 @@ public: bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - WbfsFileReader(File::IOFile file, const std::string& path); + WbfsFileReader(File::IOFile file, const std::string& path = ""); void OpenAdditionalFiles(const std::string& path); bool AddFileToList(File::IOFile file);