@@ -10,23 +10,24 @@
namespace DiscIO
{
std::unique_ptr<VolumeFileBlobReader> VolumeFileBlobReader::Create(const Volume& volume,
const FileSystem& file_system,
const Partition& partition,
const std::string& file_path)
{
if (!file_system.IsValid())
const FileSystem* file_system = volume.GetFileSystem(partition);
if (!file_system)
return nullptr;

std::unique_ptr<FileInfo> file_info = file_system.FindFileInfo(file_path);
std::unique_ptr<FileInfo> file_info = file_system->FindFileInfo(file_path);
if (!file_info || file_info->IsDirectory())
return nullptr;

return std::unique_ptr<VolumeFileBlobReader>{
new VolumeFileBlobReader(volume, file_system, std::move(file_info))};
new VolumeFileBlobReader(volume, partition, std::move(file_info))};
}

VolumeFileBlobReader::VolumeFileBlobReader(const Volume& volume, const FileSystem& file_system,
VolumeFileBlobReader::VolumeFileBlobReader(const Volume& volume, const Partition& partition,
std::unique_ptr<FileInfo> file_info)
: m_volume(volume), m_file_system(file_system), m_file_info(std::move(file_info))
: m_volume(volume), m_partition(partition), m_file_info(std::move(file_info))
{
}

@@ -45,7 +46,6 @@ bool VolumeFileBlobReader::Read(u64 offset, u64 length, u8* out_ptr)
if (offset + length > m_file_info->GetSize())
return false;

return m_volume.Read(m_file_info->GetOffset() + offset, length, out_ptr,
m_file_system.GetPartition());
return m_volume.Read(m_file_info->GetOffset() + offset, length, out_ptr, m_partition);
}
} // namespace
@@ -13,26 +13,26 @@
namespace DiscIO
{
class FileInfo;
class FileSystem;
struct Partition;
class Volume;

class VolumeFileBlobReader final : public BlobReader
{
public:
static std::unique_ptr<VolumeFileBlobReader>
Create(const Volume& volume, const FileSystem& file_system, const std::string& file_path);
Create(const Volume& volume, const Partition& partition, const std::string& file_path);

BlobType GetBlobType() const override { return BlobType::PLAIN; }
u64 GetDataSize() const override;
u64 GetRawSize() const override;
bool Read(u64 offset, u64 length, u8* out_ptr) override;

private:
VolumeFileBlobReader(const Volume& volume, const FileSystem& file_system,
VolumeFileBlobReader(const Volume& volume, const Partition& partition,
std::unique_ptr<FileInfo> file_info);

const Volume& m_volume;
const FileSystem& m_file_system;
const Partition& m_partition;
std::unique_ptr<FileInfo> m_file_info;
};
} // namespace
@@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <cinttypes>
#include <cstddef>
#include <map>
#include <memory>
@@ -20,6 +21,7 @@
#include "DiscIO/Blob.h"
#include "DiscIO/DiscExtractor.h"
#include "DiscIO/Enums.h"
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h"
#include "DiscIO/VolumeGC.h"
@@ -29,6 +31,13 @@ namespace DiscIO
VolumeGC::VolumeGC(std::unique_ptr<BlobReader> reader) : m_pReader(std::move(reader))
{
_assert_(m_pReader);

m_file_system = [this]() -> std::unique_ptr<FileSystem> {
auto file_system = std::make_unique<FileSystemGCWii>(this, PARTITION_NONE);
return file_system->IsValid() ? std::move(file_system) : nullptr;
};

m_converted_banner = [this] { return LoadBannerFile(); };
}

VolumeGC::~VolumeGC()
@@ -43,6 +52,11 @@ bool VolumeGC::Read(u64 _Offset, u64 _Length, u8* _pBuffer, const Partition& par
return m_pReader->Read(_Offset, _Length, _pBuffer);
}

const FileSystem* VolumeGC::GetFileSystem(const Partition& partition) const
{
return m_file_system->get();
}

std::string VolumeGC::GetGameID(const Partition& partition) const
{
static const std::string NO_UID("NO_UID");
@@ -113,40 +127,34 @@ std::string VolumeGC::GetInternalName(const Partition& partition) const

std::map<Language, std::string> VolumeGC::GetShortNames() const
{
LoadBannerFile();
return m_short_names;
return m_converted_banner->short_names;
}

std::map<Language, std::string> VolumeGC::GetLongNames() const
{
LoadBannerFile();
return m_long_names;
return m_converted_banner->long_names;
}

std::map<Language, std::string> VolumeGC::GetShortMakers() const
{
LoadBannerFile();
return m_short_makers;
return m_converted_banner->short_makers;
}

std::map<Language, std::string> VolumeGC::GetLongMakers() const
{
LoadBannerFile();
return m_long_makers;
return m_converted_banner->long_makers;
}

std::map<Language, std::string> VolumeGC::GetDescriptions() const
{
LoadBannerFile();
return m_descriptions;
return m_converted_banner->descriptions;
}

std::vector<u32> VolumeGC::GetBanner(int* width, int* height) const
{
LoadBannerFile();
*width = m_image_width;
*height = m_image_height;
return m_image_buffer;
*width = m_converted_banner->image_width;
*height = m_converted_banner->image_height;
return m_converted_banner->image_buffer;
}

std::string VolumeGC::GetApploaderDate(const Partition& partition) const
@@ -183,39 +191,19 @@ Platform VolumeGC::GetVolumeType() const
return Platform::GAMECUBE_DISC;
}

void VolumeGC::LoadBannerFile() const
VolumeGC::ConvertedGCBanner VolumeGC::LoadBannerFile() const
{
// If opening.bnr has been loaded already, return immediately
if (m_banner_loaded)
return;

m_banner_loaded = true;

GCBanner banner_file;
std::unique_ptr<FileSystem> file_system(CreateFileSystem(this, PARTITION_NONE));
if (!file_system)
return;

std::unique_ptr<FileInfo> file_info = file_system->FindFileInfo("opening.bnr");
if (!file_info)
return;

size_t file_size = static_cast<size_t>(file_info->GetSize());
constexpr int BNR1_MAGIC = 0x31524e42;
constexpr int BNR2_MAGIC = 0x32524e42;
if (file_size != BNR1_SIZE && file_size != BNR2_SIZE)
{
WARN_LOG(DISCIO, "Invalid opening.bnr. Size: %0zx", file_size);
return;
}

if (file_size != ReadFile(*this, PARTITION_NONE, file_info.get(),
reinterpret_cast<u8*>(&banner_file), file_size))
const u64 file_size = ReadFile(*this, PARTITION_NONE, "opening.bnr",
reinterpret_cast<u8*>(&banner_file), sizeof(GCBanner));
if (file_size < 4)
{
WARN_LOG(DISCIO, "Could not read opening.bnr.");
return;
return {}; // Return early so that we don't access the uninitialized banner_file.id
}

constexpr u32 BNR1_MAGIC = 0x31524e42;
constexpr u32 BNR2_MAGIC = 0x32524e42;
bool is_bnr1;
if (banner_file.id == BNR1_MAGIC && file_size == BNR1_SIZE)
{
@@ -228,14 +216,17 @@ void VolumeGC::LoadBannerFile() const
else
{
WARN_LOG(DISCIO, "Invalid opening.bnr. Type: %0x Size: %0zx", banner_file.id, file_size);
return;
return {};
}

ExtractBannerInformation(banner_file, is_bnr1);
return ExtractBannerInformation(banner_file, is_bnr1);
}

void VolumeGC::ExtractBannerInformation(const GCBanner& banner_file, bool is_bnr1) const
VolumeGC::ConvertedGCBanner VolumeGC::ExtractBannerInformation(const GCBanner& banner_file,
bool is_bnr1) const
{
ConvertedGCBanner banner;

u32 number_of_languages = 0;
Language start_language = Language::LANGUAGE_UNKNOWN;

@@ -251,11 +242,11 @@ void VolumeGC::ExtractBannerInformation(const GCBanner& banner_file, bool is_bnr
start_language = Language::LANGUAGE_ENGLISH;
}

m_image_width = GC_BANNER_WIDTH;
m_image_height = GC_BANNER_HEIGHT;
m_image_buffer = std::vector<u32>(m_image_width * m_image_height);
ColorUtil::decode5A3image(m_image_buffer.data(), banner_file.image, m_image_width,
m_image_height);
banner.image_width = GC_BANNER_WIDTH;
banner.image_height = GC_BANNER_HEIGHT;
banner.image_buffer = std::vector<u32>(GC_BANNER_WIDTH * GC_BANNER_HEIGHT);
ColorUtil::decode5A3image(banner.image_buffer.data(), banner_file.image, GC_BANNER_WIDTH,
GC_BANNER_HEIGHT);

for (u32 i = 0; i < number_of_languages; ++i)
{
@@ -264,24 +255,26 @@ void VolumeGC::ExtractBannerInformation(const GCBanner& banner_file, bool is_bnr

std::string description = DecodeString(info.description);
if (!description.empty())
m_descriptions[language] = description;
banner.descriptions.emplace(language, description);

std::string short_name = DecodeString(info.short_name);
if (!short_name.empty())
m_short_names[language] = short_name;
banner.short_names.emplace(language, short_name);

std::string long_name = DecodeString(info.long_name);
if (!long_name.empty())
m_long_names[language] = long_name;
banner.long_names.emplace(language, long_name);

std::string short_maker = DecodeString(info.short_maker);
if (!short_maker.empty())
m_short_makers[language] = short_maker;
banner.short_makers.emplace(language, short_maker);

std::string long_maker = DecodeString(info.long_maker);
if (!long_maker.empty())
m_long_makers[language] = long_maker;
banner.long_makers.emplace(language, long_maker);
}

return banner;
}

} // namespace
@@ -11,6 +11,8 @@
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/Lazy.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h"

// --- this volume type is used for GC disc images ---
@@ -20,6 +22,7 @@ namespace DiscIO
class BlobReader;
enum class BlobType;
enum class Country;
class FileSystem;
enum class Language;
enum class Region;
enum class Platform;
@@ -31,6 +34,7 @@ class VolumeGC : public Volume
~VolumeGC();
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer,
const Partition& partition = PARTITION_NONE) const override;
const FileSystem* GetFileSystem(const Partition& partition = PARTITION_NONE) const override;
std::string GetGameID(const Partition& partition = PARTITION_NONE) const override;
std::string GetMakerID(const Partition& partition = PARTITION_NONE) const override;
std::optional<u16> GetRevision(const Partition& partition = PARTITION_NONE) const override;
@@ -75,23 +79,28 @@ class VolumeGC : public Volume
// (only one for BNR1 type)
};

void LoadBannerFile() const;
void ExtractBannerInformation(const GCBanner& banner_file, bool is_bnr1) const;
struct ConvertedGCBanner
{
std::map<Language, std::string> short_names;
std::map<Language, std::string> long_names;
std::map<Language, std::string> short_makers;
std::map<Language, std::string> long_makers;
std::map<Language, std::string> descriptions;

std::vector<u32> image_buffer;
int image_height = 0;
int image_width = 0;
};

ConvertedGCBanner LoadBannerFile() const;
ConvertedGCBanner ExtractBannerInformation(const GCBanner& banner_file, bool is_bnr1) const;

static const size_t BNR1_SIZE = sizeof(GCBanner) - sizeof(GCBannerInformation) * 5;
static const size_t BNR2_SIZE = sizeof(GCBanner);

mutable std::map<Language, std::string> m_short_names;

mutable std::map<Language, std::string> m_long_names;
mutable std::map<Language, std::string> m_short_makers;
mutable std::map<Language, std::string> m_long_makers;
mutable std::map<Language, std::string> m_descriptions;
Common::Lazy<ConvertedGCBanner> m_converted_banner;

mutable bool m_banner_loaded = false;
mutable std::vector<u32> m_image_buffer;
mutable int m_image_height = 0;
mutable int m_image_width = 0;
Common::Lazy<std::unique_ptr<FileSystem>> m_file_system;

std::unique_ptr<BlobReader> m_pReader;
};
@@ -65,6 +65,12 @@ bool VolumeWAD::Read(u64 offset, u64 length, u8* buffer, const Partition& partit
return m_reader->Read(offset, length, buffer);
}

const FileSystem* VolumeWAD::GetFileSystem(const Partition& partition) const
{
// TODO: Implement this?
return nullptr;
}

Region VolumeWAD::GetRegion() const
{
if (!m_tmd.IsValid())
@@ -23,6 +23,7 @@ namespace DiscIO
class BlobReader;
enum class BlobType;
enum class Country;
class FileSystem;
enum class Language;
enum class Region;
enum class Platform;
@@ -34,6 +35,7 @@ class VolumeWAD : public Volume
~VolumeWAD();
bool Read(u64 offset, u64 length, u8* buffer,
const Partition& partition = PARTITION_NONE) const override;
const FileSystem* GetFileSystem(const Partition& partition = PARTITION_NONE) const override;
std::optional<u64> GetTitleID(const Partition& partition = PARTITION_NONE) const override;
const IOS::ES::TMDReader& GetTMD(const Partition& partition = PARTITION_NONE) const override;
std::string GetGameID(const Partition& partition = PARTITION_NONE) const override;
@@ -26,6 +26,7 @@
#include "DiscIO/Blob.h"
#include "DiscIO/DiscExtractor.h"
#include "DiscIO/Enums.h"
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h"

@@ -111,10 +112,17 @@ VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
return aes_context;
};

auto get_file_system = [this, partition]() -> std::unique_ptr<FileSystem> {
auto file_system = std::make_unique<FileSystemGCWii>(this, partition);
return file_system->IsValid() ? std::move(file_system) : nullptr;
};

m_partitions.emplace(
partition, PartitionDetails{Common::Lazy<std::unique_ptr<mbedtls_aes_context>>(get_key),
Common::Lazy<IOS::ES::TicketReader>(get_ticket),
Common::Lazy<IOS::ES::TMDReader>(get_tmd), *partition_type});
Common::Lazy<IOS::ES::TMDReader>(get_tmd),
Common::Lazy<std::unique_ptr<FileSystem>>(get_file_system),
*partition_type});
}
}
}
@@ -220,6 +228,12 @@ const IOS::ES::TMDReader& VolumeWii::GetTMD(const Partition& partition) const
return it != m_partitions.end() ? *it->second.tmd : INVALID_TMD;
}

const FileSystem* VolumeWii::GetFileSystem(const Partition& partition) const
{
auto it = m_partitions.find(partition);
return it != m_partitions.end() ? it->second.file_system->get() : nullptr;
}

u64 VolumeWii::PartitionOffsetToRawOffset(u64 offset, const Partition& partition)
{
if (partition == PARTITION_NONE)
@@ -287,13 +301,8 @@ std::string VolumeWii::GetInternalName(const Partition& partition) const

std::map<Language, std::string> VolumeWii::GetLongNames() const
{
std::unique_ptr<FileSystem> file_system(CreateFileSystem(this, GetGamePartition()));
if (!file_system)
return {};

std::vector<u8> opening_bnr(NAMES_TOTAL_BYTES);
std::unique_ptr<FileInfo> file_info = file_system->FindFileInfo("opening.bnr");
opening_bnr.resize(ReadFile(*this, GetGamePartition(), file_info.get(), opening_bnr.data(),
opening_bnr.resize(ReadFile(*this, GetGamePartition(), "opening.bnr", opening_bnr.data(),
opening_bnr.size(), 0x5C));
return ReadWiiNames(opening_bnr);
}
@@ -14,15 +14,17 @@
#include "Common/CommonTypes.h"
#include "Common/Lazy.h"
#include "Core/IOS/ES/Formats.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h"

// --- this volume type is used for encrypted Wii images ---
// --- this volume type is used for Wii disc images ---

namespace DiscIO
{
class BlobReader;
enum class BlobType;
enum class Country;
class FileSystem;
enum class Language;
enum class Region;
enum class Platform;
@@ -39,6 +41,7 @@ class VolumeWii : public Volume
std::optional<u64> GetTitleID(const Partition& partition) const override;
const IOS::ES::TicketReader& GetTicket(const Partition& partition) const override;
const IOS::ES::TMDReader& GetTMD(const Partition& partition) const override;
const FileSystem* GetFileSystem(const Partition& partition) const override;
std::string GetGameID(const Partition& partition) const override;
std::string GetMakerID(const Partition& partition) const override;
std::optional<u16> GetRevision(const Partition& partition) const override;
@@ -72,6 +75,7 @@ class VolumeWii : public Volume
Common::Lazy<std::unique_ptr<mbedtls_aes_context>> key;
Common::Lazy<IOS::ES::TicketReader> ticket;
Common::Lazy<IOS::ES::TMDReader> tmd;
Common::Lazy<std::unique_ptr<FileSystem>> file_system;
u32 type;
};

@@ -85,8 +85,7 @@ void FilesystemWidget::PopulateView()

for (size_t i = 0; i < partitions.size(); i++)
{
std::unique_ptr<DiscIO::FileSystem> file_system(
DiscIO::CreateFileSystem(m_volume.get(), partitions[i]));
const DiscIO::FileSystem* file_system = m_volume->GetFileSystem(partitions[i]);

auto* item = new QStandardItem(tr("Partition %1").arg(i));
item->setEditable(false);
@@ -104,10 +103,7 @@ void FilesystemWidget::PopulateView()
}

if (partitions.empty())
{
PopulateDirectory(-1, disc,
DiscIO::CreateFileSystem(m_volume.get(), DiscIO::PARTITION_NONE)->GetRoot());
}
PopulateDirectory(-1, disc, m_volume->GetFileSystem(DiscIO::PARTITION_NONE)->GetRoot());
}

void FilesystemWidget::PopulateDirectory(int partition_id, QStandardItem* root,
@@ -237,9 +233,7 @@ void FilesystemWidget::ExtractSystemData(const DiscIO::Partition& partition, con
void FilesystemWidget::ExtractDirectory(const DiscIO::Partition& partition, const QString path,
const QString& out)
{
std::unique_ptr<DiscIO::FileSystem> filesystem(
DiscIO::CreateFileSystem(m_volume.get(), partition));

const DiscIO::FileSystem* filesystem = m_volume->GetFileSystem(partition);
std::unique_ptr<DiscIO::FileInfo> info = filesystem->FindFileInfo(path.toStdString());
u32 size = info->GetTotalChildren();

@@ -251,7 +245,7 @@ void FilesystemWidget::ExtractDirectory(const DiscIO::Partition& partition, cons
bool all = path.isEmpty();

DiscIO::ExportDirectory(
*m_volume, filesystem->GetPartition(), *info, true, path.toStdString(), out.toStdString(),
*m_volume, partition, *info, true, path.toStdString(), out.toStdString(),
[all, dialog](const std::string& current) {
dialog->setLabelText(
(all ? QObject::tr("Extracting All Files...") : QObject::tr("Extracting Directory..."))
@@ -268,8 +262,7 @@ void FilesystemWidget::ExtractDirectory(const DiscIO::Partition& partition, cons
void FilesystemWidget::ExtractFile(const DiscIO::Partition& partition, const QString& path,
const QString& out)
{
std::unique_ptr<DiscIO::FileSystem> filesystem(
DiscIO::CreateFileSystem(m_volume.get(), partition));
const DiscIO::FileSystem* filesystem = m_volume->GetFileSystem(partition);
bool success = DiscIO::ExportFile(
*m_volume, partition, filesystem->FindFileInfo(path.toStdString()).get(), out.toStdString());

@@ -36,11 +36,8 @@ namespace
class WiiPartition final : public wxTreeItemData
{
public:
WiiPartition(std::unique_ptr<DiscIO::FileSystem> filesystem_) : filesystem{std::move(filesystem_)}
{
}

std::unique_ptr<DiscIO::FileSystem> filesystem;
WiiPartition(const DiscIO::Partition& partition_) : partition(partition_) {}
DiscIO::Partition partition;
};

enum : int
@@ -86,6 +83,13 @@ void CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
}
}

void CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
const DiscIO::FileSystem* file_system)
{
if (file_system)
CreateDirectoryTree(tree_ctrl, parent, file_system->GetRoot());
}

WiiPartition* FindWiiPartition(wxTreeCtrl* tree_ctrl, const wxString& label)
{
wxTreeItemIdValue cookie;
@@ -154,30 +158,22 @@ bool FilesystemPanel::PopulateFileSystemTree()
{
for (size_t i = 0; i < partitions.size(); ++i)
{
std::unique_ptr<DiscIO::FileSystem> file_system(
DiscIO::CreateFileSystem(m_opened_iso.get(), partitions[i]));
if (file_system)
{
wxTreeItemId partition_root = m_tree_ctrl->AppendItem(
m_tree_ctrl->GetRootItem(), wxString::Format(_("Partition %zu"), i), ICON_DISC);
wxTreeItemId partition_root = m_tree_ctrl->AppendItem(
m_tree_ctrl->GetRootItem(), wxString::Format(_("Partition %zu"), i), ICON_DISC);

WiiPartition* const partition = new WiiPartition(std::move(file_system));
WiiPartition* const partition = new WiiPartition(partitions[i]);

m_tree_ctrl->SetItemData(partition_root, partition);
CreateDirectoryTree(m_tree_ctrl, partition_root, partition->filesystem->GetRoot());
m_tree_ctrl->SetItemData(partition_root, partition);
CreateDirectoryTree(m_tree_ctrl, partition_root, m_opened_iso->GetFileSystem(partitions[i]));

if (partitions[i] == m_opened_iso->GetGamePartition())
m_tree_ctrl->Expand(partition_root);
}
if (partitions[i] == m_opened_iso->GetGamePartition())
m_tree_ctrl->Expand(partition_root);
}
}
else
{
m_filesystem = DiscIO::CreateFileSystem(m_opened_iso.get(), DiscIO::PARTITION_NONE);
if (!m_filesystem)
return false;

CreateDirectoryTree(m_tree_ctrl, m_tree_ctrl->GetRootItem(), m_filesystem->GetRoot());
CreateDirectoryTree(m_tree_ctrl, m_tree_ctrl->GetRootItem(),
m_opened_iso->GetFileSystem(DiscIO::PARTITION_NONE));
}

return true;
@@ -256,7 +252,7 @@ void FilesystemPanel::OnExtractSystemData(wxCommandEvent& event)
const auto* const selection_data = m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection());
const auto* const wii_partition = static_cast<const WiiPartition*>(selection_data);

partition = wii_partition->filesystem->GetPartition();
partition = wii_partition->partition;
}
else
{
@@ -293,23 +289,23 @@ void FilesystemPanel::OnExtractAll(wxCommandEvent& event)
{
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(item));
const std::optional<u32> partition_type =
*m_opened_iso->GetPartitionType(partition->filesystem->GetPartition());
*m_opened_iso->GetPartitionType(partition->partition);
if (partition_type)
{
const std::string partition_name = DiscIO::DirectoryNameForPartitionType(*partition_type);
ExtractPartition(std_extract_path + '/' + partition_name, *partition->filesystem);
ExtractPartition(std_extract_path + '/' + partition_name, partition->partition);
}
item = m_tree_ctrl->GetNextChild(root, cookie);
}
}
else if (m_has_partitions && !first_item_selected)
{
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(selection));
ExtractPartition(std_extract_path, *partition->filesystem);
ExtractPartition(std_extract_path, partition->partition);
}
else
{
ExtractPartition(std_extract_path, *m_filesystem);
ExtractPartition(std_extract_path, DiscIO::PARTITION_NONE);
}
}

@@ -326,9 +322,8 @@ void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))
const auto selection = m_tree_ctrl->GetSelection();
WiiPartition* partition =
static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection()));
std::future<bool> is_valid = std::async(std::launch::async, [&] {
return m_opened_iso->CheckIntegrity(partition->filesystem->GetPartition());
});
std::future<bool> is_valid = std::async(
std::launch::async, [&] { return m_opened_iso->CheckIntegrity(partition->partition); });

while (is_valid.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
dialog.Pulse();
@@ -350,23 +345,26 @@ void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))

void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const
{
const std::pair<wxString, const DiscIO::FileSystem&> path = BuildFilePathFromSelection();
DiscIO::ExportFile(*m_opened_iso, path.second.GetPartition(),
path.second.FindFileInfo(WxStrToStr(path.first)).get(),
const std::pair<wxString, DiscIO::Partition> path = BuildFilePathFromSelection();
DiscIO::ExportFile(*m_opened_iso, path.second, WxStrToStr(path.first),
WxStrToStr(output_file_path));
}

void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder)
{
const std::pair<wxString, const DiscIO::FileSystem&> path = BuildDirectoryPathFromSelection();
const std::pair<wxString, DiscIO::Partition> path = BuildDirectoryPathFromSelection();
ExtractDirectories(WxStrToStr(path.first), WxStrToStr(output_folder), path.second);
}

void FilesystemPanel::ExtractDirectories(const std::string& full_path,
const std::string& output_folder,
const DiscIO::FileSystem& filesystem)
const DiscIO::Partition& partition)
{
std::unique_ptr<DiscIO::FileInfo> file_info = filesystem.FindFileInfo(full_path);
const DiscIO::FileSystem* file_system = m_opened_iso->GetFileSystem(partition);
if (!file_system)
return;

std::unique_ptr<DiscIO::FileInfo> file_info = file_system->FindFileInfo(full_path);
u32 size = file_info->GetTotalChildren();
u32 progress = 0;

@@ -376,7 +374,7 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);

DiscIO::ExportDirectory(
*m_opened_iso, filesystem.GetPartition(), *file_info, true, full_path, output_folder,
*m_opened_iso, partition, *file_info, true, full_path, output_folder,
[&](const std::string& path) {
dialog.SetTitle(wxString::Format(
"%s : %d%%", dialog_title.c_str(),
@@ -388,13 +386,13 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
}

void FilesystemPanel::ExtractPartition(const std::string& output_folder,
const DiscIO::FileSystem& filesystem)
const DiscIO::Partition& partition)
{
ExtractDirectories("", output_folder + "/files", filesystem);
DiscIO::ExportSystemData(*m_opened_iso, filesystem.GetPartition(), output_folder);
ExtractDirectories("", output_folder + "/files", partition);
DiscIO::ExportSystemData(*m_opened_iso, partition, output_folder);
}

std::pair<wxString, const DiscIO::FileSystem&> FilesystemPanel::BuildFilePathFromSelection() const
std::pair<wxString, DiscIO::Partition> FilesystemPanel::BuildFilePathFromSelection() const
{
const wxTreeItemId root_node = m_tree_ctrl->GetRootItem();
wxTreeItemId node = m_tree_ctrl->GetSelection();
@@ -417,22 +415,21 @@ std::pair<wxString, const DiscIO::FileSystem&> FilesystemPanel::BuildFilePathFro
{
const size_t slash_index = file_path.find('/');
const wxString partition_label = file_path.substr(0, slash_index);
const auto* const partition = FindWiiPartition(m_tree_ctrl, partition_label);
const WiiPartition* const partition = FindWiiPartition(m_tree_ctrl, partition_label);

// Remove "Partition x/"
file_path.erase(0, slash_index + 1);

return {file_path, *partition->filesystem};
return {file_path, partition->partition};
}
else
{
return {file_path, *m_filesystem};
return {file_path, DiscIO::PARTITION_NONE};
}
}

std::pair<wxString, const DiscIO::FileSystem&>
FilesystemPanel::BuildDirectoryPathFromSelection() const
std::pair<wxString, DiscIO::Partition> FilesystemPanel::BuildDirectoryPathFromSelection() const
{
const std::pair<wxString, const DiscIO::FileSystem&> result = BuildFilePathFromSelection();
const std::pair<wxString, DiscIO::Partition> result = BuildFilePathFromSelection();
return {result.first + DIR_SEP_CHR, result.second};
}
@@ -15,7 +15,7 @@ class wxTreeEvent;

namespace DiscIO
{
class FileSystem;
struct Partition;
class Volume;
}

@@ -51,16 +51,15 @@ class FilesystemPanel final : public wxPanel
void ExtractSingleFile(const wxString& output_file_path) const;
void ExtractSingleDirectory(const wxString& output_folder);
void ExtractDirectories(const std::string& full_path, const std::string& output_folder,
const DiscIO::FileSystem& filesystem);
void ExtractPartition(const std::string& output_folder, const DiscIO::FileSystem& filesystem);
const DiscIO::Partition& partition);
void ExtractPartition(const std::string& output_folder, const DiscIO::Partition& partition);

std::pair<wxString, const DiscIO::FileSystem&> BuildFilePathFromSelection() const;
std::pair<wxString, const DiscIO::FileSystem&> BuildDirectoryPathFromSelection() const;
std::pair<wxString, DiscIO::Partition> BuildFilePathFromSelection() const;
std::pair<wxString, DiscIO::Partition> BuildDirectoryPathFromSelection() const;

wxTreeCtrl* m_tree_ctrl;

const std::unique_ptr<DiscIO::Volume>& m_opened_iso;

std::unique_ptr<DiscIO::FileSystem> m_filesystem;
bool m_has_partitions;
};