Merge pull request #12036 from LillyJadeKatrin/deep-copy-volume

Added CopyReader to BlobReader and all subclasses
This commit is contained in:
JMC47 2023-10-01 11:39:37 -04:00 committed by GitHub
commit cd366c4f46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 306 additions and 216 deletions

View file

@ -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();

View file

@ -51,6 +51,8 @@ public:
SharedAccess sh = SharedAccess::Default);
bool Close();
IOFile Duplicate(const char openmode[]) const;
template <typename T>
bool ReadArray(T* elements, size_t count, size_t* num_read = nullptr)
{

View file

@ -64,6 +64,7 @@ public:
virtual ~BlobReader() {}
virtual BlobType GetBlobType() const = 0;
virtual std::unique_ptr<BlobReader> CopyReader() const = 0;
virtual u64 GetRawSize() const = 0;
virtual u64 GetDataSize() const = 0;

View file

@ -40,6 +40,11 @@ std::unique_ptr<CISOFileReader> CISOFileReader::Create(File::IOFile file)
return nullptr;
}
std::unique_ptr<BlobReader> CISOFileReader::CopyReader() const
{
return Create(m_file.Duplicate("rb"));
}
u64 CISOFileReader::GetDataSize() const
{
return static_cast<u64>(CISO_MAP_SIZE) * m_block_size;

View file

@ -36,6 +36,7 @@ public:
static std::unique_ptr<CISOFileReader> Create(File::IOFile file);
BlobType GetBlobType() const override { return BlobType::CISO; }
std::unique_ptr<BlobReader> CopyReader() const override;
u64 GetRawSize() const override;
u64 GetDataSize() const override;

View file

@ -74,6 +74,11 @@ CompressedBlobReader::~CompressedBlobReader()
{
}
std::unique_ptr<BlobReader> 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
{

View file

@ -50,6 +50,7 @@ public:
const CompressedBlobHeader& GetHeader() const { return m_header; }
BlobType GetBlobType() const override { return BlobType::GCZ; }
std::unique_ptr<BlobReader> CopyReader() const override;
u64 GetRawSize() const override { return m_file_size; }
u64 GetDataSize() const override { return m_header.data_size; }

View file

@ -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<const u8*>(m_content_source))
else if (std::holds_alternative<ContentMemory>(m_content_source))
{
const u8* const content_pointer = std::get<const u8*>(m_content_source) + offset_in_content;
std::copy(content_pointer, content_pointer + bytes_to_read, *buffer);
const auto& content = std::get<ContentMemory>(m_content_source);
std::copy(content->begin() + offset_in_content,
content->begin() + offset_in_content + bytes_to_read, *buffer);
}
else if (std::holds_alternative<ContentPartition>(m_content_source))
{
const auto& content = std::get<ContentPartition>(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<ContentVolume>(m_content_source))
{
const auto& source = std::get<ContentVolume>(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<ContentFixedByte>(m_content_source);
std::fill_n(*buffer, bytes_to_read, source.m_byte);
}
else if (std::holds_alternative<ContentByteVector>(m_content_source))
{
const ContentByteVector& source = std::get<ContentByteVector>(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<DiscContent>::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<u8> 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<PartitionWithType> 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<u8> 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<u8> 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<u8> 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<PartitionType>(*type));
partitions.emplace_back(DirectoryBlobPartition(m_wrapped_volume.get(), partition, m_is_wii,
nullptr, nullptr, this),
static_cast<PartitionType>(*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<BlobReader> DirectoryBlobReader::CopyReader() const
{
return std::unique_ptr<DirectoryBlobReader>(new DirectoryBlobReader(*this));
}
u64 DirectoryBlobReader::GetRawSize() const
{
// Not implemented
@ -558,28 +575,25 @@ void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector<u8>& parti
std::vector<u8> 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<u8>& 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<u8> region_data(0x10, 0x00);
region_data.resize(WII_REGION_DATA_SIZE, 0x80);
Write32(INVALID_REGION, 0, &region_data);
std::copy_n(wii_region_data.begin(),
std::min<size_t>(wii_region_data.size(), WII_REGION_DATA_SIZE),
m_wii_region_data.begin());
std::min<size_t>(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<PartitionWithType>&& partitions)
@ -634,14 +647,14 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& 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<u8> 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<PartitionWithType>&& partiti
if (partitions[i].type == PartitionType::Game)
partition_address = std::max(partition_address, STANDARD_GAME_PARTITION_ADDRESS);
Write32(static_cast<u32>(partition_address >> 2), offset_in_table, &m_partition_table);
Write32(static_cast<u32>(partition_address >> 2), offset_in_table, &partition_table);
offset_in_table += 4;
Write32(static_cast<u32>(partitions[i].type), offset_in_table, &m_partition_table);
Write32(static_cast<u32>(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<PartitionWithType>&& 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<u8> 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<u8> 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<u8> 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<u8> 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<u8>& partition_header = m_extra_data.emplace_back(PARTITION_HEADER_SIZE);
std::vector<u8> partition_header(PARTITION_HEADER_SIZE);
Write32(static_cast<u32>(tmd_size), 0x0, &partition_header);
Write32(TMD_OFFSET >> 2, 0x4, &partition_header);
Write32(static_cast<u32>(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<u32>(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<u8> 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<BuilderContentSource> 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<bool> is_wii)
: m_root_directory(root_directory)
{
SetDiscHeaderFromFile(m_root_directory + "sys/boot.bin");
SetDiscType(is_wii);
std::vector<u8> 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<u8> data)
{
std::vector<BuilderContentSource> 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::vector<u8>>(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<u8>
return node;
}
static std::vector<u8> ExtractNodeToVector(std::vector<FSTBuilderNode>* nodes, void* userdata)
static std::vector<u8> ExtractNodeToVector(std::vector<FSTBuilderNode>* nodes, void* userdata,
DirectoryBlobReader* blob)
{
std::vector<u8> data;
const auto it =
@ -858,7 +876,7 @@ static std::vector<u8> ExtractNodeToVector(std::vector<FSTBuilderNode>* 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<bool> is_wii,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes, FSTBuilderNode* dol_node)>&
fst_callback)
fst_callback,
DirectoryBlobReader* blob)
: m_wrapped_partition(partition)
{
std::vector<FSTBuilderNode> sys_nodes;
@ -874,17 +893,16 @@ DirectoryBlobPartition::DirectoryBlobPartition(
std::vector<u8> 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<u8> 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<u8> 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<BuilderContentSource> 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<u8> 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<bool> is_wii)
void DirectoryBlobPartition::SetDiscType(std::optional<bool> is_wii,
const std::vector<u8>& disc_header)
{
if (is_wii.has_value())
{
@ -954,8 +960,8 @@ void DirectoryBlobPartition::SetDiscType(std::optional<bool> 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<bool> is_wii)
void DirectoryBlobPartition::SetBI2FromFile(const std::string& bi2_path)
{
m_bi2.resize(BI2_SIZE);
std::vector<u8> 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<u8> 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<u8> 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<u8> 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<u32>(-1), 0x10, &m_apploader);
Write32(static_cast<u32>(-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<u8>* disc_header)
{
const u64 dol_size = m_contents.CheckSizeAndAdd(dol_address, path);
Write32(static_cast<u32>(dol_address >> m_address_shift), 0x0420, &m_disc_header);
Write32(static_cast<u32>(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<u8>* 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<u32>(dol_address >> m_address_shift), 0x0420, &m_disc_header);
Write32(static_cast<u32>(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<FSTBuilderNode> 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<u8>* 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<FSTBuilderNode>* fst)
@ -1118,10 +1126,9 @@ static size_t RecalculateFolderSizes(std::vector<FSTBuilderNode>* fst)
return size;
}
void DirectoryBlobPartition::BuildFST(std::vector<FSTBuilderNode> root_nodes, u64 fst_address)
void DirectoryBlobPartition::BuildFST(std::vector<FSTBuilderNode> root_nodes, u64 fst_address,
std::vector<u8>* 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<FSTBuilderNode> 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<u8> 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, &current_data_address, root_offset,
name_table_offset);
WriteDirectory(&fst_data, &root_nodes, &fst_offset, &name_offset, &current_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<u8>* 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<u8>* 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<FSTBuilderNode>* parent_entries,
void DirectoryBlobPartition::WriteDirectory(std::vector<u8>* fst_data,
std::vector<FSTBuilderNode>* 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<FSTBuilderNode>* 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();

View file

@ -46,13 +46,13 @@ struct ContentFile
u64 m_offset = 0;
};
// Content chunk that's just a direct block of memory
typedef std::shared_ptr<std::vector<u8>> 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<u8> m_bytes;
};
using ContentSource = std::variant<ContentFile, // File
const u8*, // Memory
ContentMemory, // Memory/Byte Sequence
ContentPartition, // Partition
ContentVolume, // Volume
ContentFixedByte, // Fixed value padding
ContentByteVector // Byte sequence
ContentFixedByte // Fixed value padding
>;
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 <typename T>
void AddReference(u64 offset, const std::vector<T>& vector)
void Add(u64 offset, std::vector<u8> vector)
{
return Add(offset, vector.size() * sizeof(T), reinterpret_cast<const u8*>(vector.data()));
size_t vector_size = vector.size();
return Add(offset, vector_size, std::make_shared<std::vector<u8>>(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<DiscContent> m_contents;
@ -194,11 +184,11 @@ public:
DiscIO::VolumeDisc* volume, const DiscIO::Partition& partition, std::optional<bool> is_wii,
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* 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<u8>& GetHeader() const { return m_disc_header; }
const DiscContentContainer& GetContents() const { return m_contents; }
const std::optional<DiscIO::Partition>& GetWrappedPartition() const
{
@ -217,9 +206,7 @@ public:
void SetKey(std::array<u8, VolumeWii::AES_KEY_SIZE> key) { m_key = key; }
private:
void SetDiscHeaderFromFile(const std::string& boot_bin_path);
void SetDiscHeader(std::vector<u8> boot_bin);
void SetDiscType(std::optional<bool> is_wii);
void SetDiscType(std::optional<bool> is_wii, const std::vector<u8>& disc_header);
void SetBI2FromFile(const std::string& bi2_path);
void SetBI2(std::vector<u8> bi2);
@ -227,25 +214,24 @@ private:
u64 SetApploaderFromFile(const std::string& path);
u64 SetApploader(std::vector<u8> 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<u8>* disc_header);
u64 SetDOL(FSTBuilderNode dol_node, u64 dol_address, std::vector<u8>* disc_header);
void BuildFSTFromFolder(const std::string& fst_root_path, u64 fst_address);
void BuildFST(std::vector<FSTBuilderNode> root_nodes, u64 fst_address);
void BuildFSTFromFolder(const std::string& fst_root_path, u64 fst_address,
std::vector<u8>* disc_header);
void BuildFST(std::vector<FSTBuilderNode> root_nodes, u64 fst_address,
std::vector<u8>* 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<FSTBuilderNode>* parent_entries, u32* fst_offset,
u32* name_offset, u64* data_offset, u32 parent_entry_index,
void WriteEntryData(std::vector<u8>* fst_data, u32* entry_offset, u8 type, u32 name_offset,
u64 data_offset, u64 length, u32 address_shift);
void WriteEntryName(std::vector<u8>* fst_data, u32* name_offset, const std::string& name,
u64 name_table_offset);
void WriteDirectory(std::vector<u8>* fst_data, std::vector<FSTBuilderNode>* parent_entries,
u32* fst_offset, u32* name_offset, u64* data_offset, u32 parent_entry_index,
u64 name_table_offset);
DiscContentContainer m_contents;
std::vector<u8> m_disc_header;
std::vector<u8> m_bi2;
std::vector<u8> m_apploader;
std::vector<u8> m_fst_data;
std::array<u8, VolumeWii::AES_KEY_SIZE> m_key{};
@ -271,9 +257,6 @@ public:
const std::function<void(std::vector<FSTBuilderNode>* 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<BlobReader> CopyReader() const override;
u64 GetRawSize() const override;
u64 GetDataSize() const override;
@ -311,6 +295,7 @@ private:
const std::function<void(std::vector<FSTBuilderNode>* fst_nodes)>& sys_callback,
const std::function<void(std::vector<FSTBuilderNode>* 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<PartitionWithType>&& 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<u8> m_disc_header_nonpartition;
std::vector<u8> m_partition_table;
std::vector<u8> m_wii_region_data;
std::vector<std::vector<u8>> m_extra_data;
u64 m_data_size;
std::unique_ptr<DiscIO::VolumeDisc> m_wrapped_volume;

View file

@ -22,7 +22,6 @@
namespace DiscIO
{
DiscScrubber::DiscScrubber() = default;
DiscScrubber::~DiscScrubber() = default;
bool DiscScrubber::SetupScrub(const Volume& disc)
{

View file

@ -27,7 +27,6 @@ class DiscScrubber final
{
public:
DiscScrubber();
~DiscScrubber();
bool SetupScrub(const Volume& disc);

View file

@ -28,6 +28,11 @@ std::unique_ptr<PlainFileReader> PlainFileReader::Create(File::IOFile file)
return nullptr;
}
std::unique_ptr<BlobReader> 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))

View file

@ -19,6 +19,7 @@ public:
static std::unique_ptr<PlainFileReader> Create(File::IOFile file);
BlobType GetBlobType() const override { return BlobType::PLAIN; }
std::unique_ptr<BlobReader> CopyReader() const override;
u64 GetRawSize() const override { return m_size; }
u64 GetDataSize() const override { return m_size; }

View file

@ -160,11 +160,20 @@ std::unique_ptr<NFSFileReader> NFSFileReader::Create(File::IOFile first_file,
NFSFileReader::NFSFileReader(std::vector<NFSLBARange> lba_ranges, std::vector<File::IOFile> 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<BlobReader> NFSFileReader::CopyReader() const
{
std::vector<File::IOFile> new_files{};
for (const File::IOFile& file : m_files)
new_files.push_back(file.Duplicate("rb"));
return std::unique_ptr<NFSFileReader>(
new NFSFileReader(m_lba_ranges, std::move(new_files), m_key, m_raw_size));
}
u64 NFSFileReader::GetDataSize() const
{
return m_data_size;

View file

@ -45,6 +45,7 @@ public:
const std::string& directory_path);
BlobType GetBlobType() const override { return BlobType::NFS; }
std::unique_ptr<BlobReader> CopyReader() const override;
u64 GetRawSize() const override;
u64 GetDataSize() const override;
@ -86,6 +87,7 @@ private:
std::unique_ptr<Common::AES::Context> m_aes_context;
u64 m_raw_size;
u64 m_data_size;
Key m_key;
};
} // namespace DiscIO

View file

@ -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<ContentFile>(after->m_source))
{
std::get<ContentFile>(after->m_source).m_offset += before->m_size;
else if (std::holds_alternative<const u8*>(after->m_source))
std::get<const u8*>(after->m_source) += before->m_size;
}
else if (std::holds_alternative<ContentMemory>(after->m_source))
{
after->m_source = std::make_shared<std::vector<u8>>(
std::get<ContentMemory>(after->m_source)->begin() + before->m_size,
std::get<ContentMemory>(after->m_source)->end());
}
else if (std::holds_alternative<ContentPartition>(after->m_source))
{
std::get<ContentPartition>(after->m_source).m_offset += before->m_size;
}
else if (std::holds_alternative<ContentVolume>(after->m_source))
{
std::get<ContentVolume>(after->m_source).m_offset += before->m_size;
}
}
static void ApplyPatchToFile(const Patch& patch, DiscIO::FSTBuilderNode* file_node,

View file

@ -37,6 +37,11 @@ std::unique_ptr<ScrubbedBlob> ScrubbedBlob::Create(const std::string& path)
return std::unique_ptr<ScrubbedBlob>(new ScrubbedBlob(std::move(blob), std::move(scrubber)));
}
std::unique_ptr<BlobReader> ScrubbedBlob::CopyReader() const
{
return std::unique_ptr<ScrubbedBlob>(new ScrubbedBlob(m_blob_reader->CopyReader(), m_scrubber));
}
bool ScrubbedBlob::Read(u64 offset, u64 size, u8* out_ptr)
{
while (size > 0)

View file

@ -19,6 +19,7 @@ public:
static std::unique_ptr<ScrubbedBlob> Create(const std::string& path);
BlobType GetBlobType() const override { return m_blob_reader->GetBlobType(); }
std::unique_ptr<BlobReader> CopyReader() const override;
u64 GetRawSize() const override { return m_blob_reader->GetRawSize(); }
u64 GetDataSize() const override { return m_blob_reader->GetDataSize(); }

View file

@ -56,6 +56,17 @@ std::unique_ptr<SplitPlainFileReader> SplitPlainFileReader::Create(std::string_v
return std::unique_ptr<SplitPlainFileReader>(new SplitPlainFileReader(std::move(files)));
}
std::unique_ptr<BlobReader> SplitPlainFileReader::CopyReader() const
{
std::vector<SingleFile> 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<SplitPlainFileReader>(new SplitPlainFileReader(std::move(new_files)));
}
bool SplitPlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
{
if (offset >= m_size)

View file

@ -21,6 +21,7 @@ public:
static std::unique_ptr<SplitPlainFileReader> Create(std::string_view first_file_path);
BlobType GetBlobType() const override { return BlobType::SPLIT_PLAIN; }
std::unique_ptr<BlobReader> CopyReader() const override;
u64 GetRawSize() const override { return m_size; }
u64 GetDataSize() const override { return m_size; }

View file

@ -98,6 +98,11 @@ TGCFileReader::TGCFileReader(File::IOFile file) : m_file(std::move(file))
}
}
std::unique_ptr<BlobReader> TGCFileReader::CopyReader() const
{
return Create(m_file.Duplicate("rb"));
}
u64 TGCFileReader::GetDataSize() const
{
return m_size - Common::swap32(m_header.tgc_header_size);

View file

@ -42,6 +42,7 @@ public:
static std::unique_ptr<TGCFileReader> Create(File::IOFile file);
BlobType GetBlobType() const override { return BlobType::TGC; }
std::unique_ptr<BlobReader> CopyReader() const override;
u64 GetRawSize() const override { return m_size; }
u64 GetDataSize() const override;

View file

@ -33,6 +33,12 @@ VolumeFileBlobReader::VolumeFileBlobReader(const Volume& volume, const Partition
{
}
std::unique_ptr<BlobReader> VolumeFileBlobReader::CopyReader() const
{
ASSERT_MSG(DISCIO, false, "Unimplemented");
return nullptr;
}
u64 VolumeFileBlobReader::GetDataSize() const
{
return m_file_info->GetSize();

View file

@ -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<BlobReader> CopyReader() const override;
u64 GetRawSize() const override;
u64 GetDataSize() const override;

View file

@ -79,7 +79,7 @@ std::pair<int, int> GetAllowedCompressionLevels(WIARVZCompressionType compressio
template <bool RVZ>
WIARVZFileReader<RVZ>::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<RVZ>::GetBlobType() const
return RVZ ? BlobType::RVZ : BlobType::WIA;
}
template <bool RVZ>
std::unique_ptr<BlobReader> WIARVZFileReader<RVZ>::CopyReader() const
{
return Create(m_file.Duplicate("rb"), m_path);
}
template <bool RVZ>
std::string WIARVZFileReader<RVZ>::GetCompressionMethod() const
{

View file

@ -49,6 +49,7 @@ public:
static std::unique_ptr<WIARVZFileReader> Create(File::IOFile file, const std::string& path);
BlobType GetBlobType() const override;
std::unique_ptr<BlobReader> 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<u64>::max();
WiiEncryptionCache m_encryption_cache;

View file

@ -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<BlobReader> WbfsFileReader::CopyReader() const
{
auto retval =
std::unique_ptr<WbfsFileReader>(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;

View file

@ -23,6 +23,7 @@ public:
static std::unique_ptr<WbfsFileReader> Create(File::IOFile file, const std::string& path);
BlobType GetBlobType() const override { return BlobType::WBFS; }
std::unique_ptr<BlobReader> 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);