325 changes: 167 additions & 158 deletions Source/Core/DiscIO/DirectoryBlob.cpp

Large diffs are not rendered by default.

80 changes: 31 additions & 49 deletions Source/Core/DiscIO/DirectoryBlob.h
Expand Up @@ -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;

Expand All @@ -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;
};
Expand All @@ -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
Expand Down Expand Up @@ -147,7 +137,7 @@ class DiscContent
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); }
Expand All @@ -170,16 +160,16 @@ class DiscContent
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;
Expand All @@ -194,19 +184,18 @@ class 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);

// 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;

bool IsWii() const { return m_is_wii; }
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
{
Expand All @@ -217,35 +206,32 @@ class DirectoryBlobPartition
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);

// Returns DOL address
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{};

Expand All @@ -271,9 +257,6 @@ class DirectoryBlobReader : public BlobReader
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;

Expand All @@ -282,6 +265,7 @@ class DirectoryBlobReader : public BlobReader
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;
Expand Down Expand Up @@ -311,6 +295,7 @@ class DirectoryBlobReader : public BlobReader
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;

Expand All @@ -326,6 +311,8 @@ class DirectoryBlobReader : public BlobReader
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;

Expand All @@ -337,11 +324,6 @@ class DirectoryBlobReader : public BlobReader
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;
Expand Down
1 change: 0 additions & 1 deletion Source/Core/DiscIO/DiscScrubber.cpp
Expand Up @@ -22,7 +22,6 @@
namespace DiscIO
{
DiscScrubber::DiscScrubber() = default;
DiscScrubber::~DiscScrubber() = default;

bool DiscScrubber::SetupScrub(const Volume& disc)
{
Expand Down
1 change: 0 additions & 1 deletion Source/Core/DiscIO/DiscScrubber.h
Expand Up @@ -27,7 +27,6 @@ class DiscScrubber final
{
public:
DiscScrubber();
~DiscScrubber();

bool SetupScrub(const Volume& disc);

Expand Down
5 changes: 5 additions & 0 deletions Source/Core/DiscIO/FileBlob.cpp
Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DiscIO/FileBlob.h
Expand Up @@ -19,6 +19,7 @@ class PlainFileReader : public BlobReader
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; }
Expand Down
11 changes: 10 additions & 1 deletion Source/Core/DiscIO/NFSBlob.cpp
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DiscIO/NFSBlob.h
Expand Up @@ -45,6 +45,7 @@ class NFSFileReader : public BlobReader
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;
Expand Down Expand Up @@ -86,6 +87,7 @@ class NFSFileReader : public BlobReader
std::unique_ptr<Common::AES::Context> m_aes_context;
u64 m_raw_size;
u64 m_data_size;
Key m_key;
};

} // namespace DiscIO
14 changes: 12 additions & 2 deletions Source/Core/DiscIO/RiivolutionPatcher.cpp
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/DiscIO/ScrubbedBlob.cpp
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DiscIO/ScrubbedBlob.h
Expand Up @@ -19,6 +19,7 @@ class ScrubbedBlob : public BlobReader
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(); }
Expand Down
11 changes: 11 additions & 0 deletions Source/Core/DiscIO/SplitFileBlob.cpp
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DiscIO/SplitFileBlob.h
Expand Up @@ -21,6 +21,7 @@ class SplitPlainFileReader final : public BlobReader
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; }
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/DiscIO/TGCBlob.cpp
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DiscIO/TGCBlob.h
Expand Up @@ -42,6 +42,7 @@ class TGCFileReader final : public BlobReader
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;
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/DiscIO/VolumeFileBlobReader.cpp
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DiscIO/VolumeFileBlobReader.h
Expand Up @@ -22,6 +22,7 @@ class VolumeFileBlobReader final : public BlobReader
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;
Expand Down
8 changes: 7 additions & 1 deletion Source/Core/DiscIO/WIABlob.cpp
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
{
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DiscIO/WIABlob.h
Expand Up @@ -49,6 +49,7 @@ class WIARVZFileReader : public BlobReader
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); }
Expand Down Expand Up @@ -365,6 +366,7 @@ class WIARVZFileReader : public BlobReader
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;
Expand Down
12 changes: 11 additions & 1 deletion Source/Core/DiscIO/WbfsBlob.cpp
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/DiscIO/WbfsBlob.h
Expand Up @@ -23,6 +23,7 @@ class WbfsFileReader : public BlobReader
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;
Expand All @@ -36,7 +37,7 @@ class WbfsFileReader : public BlobReader
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);
Expand Down