Merge pull request #5870 from JosJuice/lazy-filesystem

DiscIO: Use Common::Lazy more
This commit is contained in:
Leo Lam 2017-09-15 19:30:05 +02:00 committed by GitHub
commit 7cb8d6612c
23 changed files with 237 additions and 249 deletions

View File

@ -21,6 +21,16 @@ public:
Lazy() : m_value(T()) {} Lazy() : m_value(T()) {}
Lazy(const std::variant<T, std::function<T()>>& value) : m_value(value) {} Lazy(const std::variant<T, std::function<T()>>& value) : m_value(value) {}
Lazy(std::variant<T, std::function<T()>>&& value) : m_value(std::move(value)) {} Lazy(std::variant<T, std::function<T()>>&& value) : m_value(std::move(value)) {}
const Lazy<T>& operator=(const std::variant<T, std::function<T()>>& value)
{
m_value = value;
return *this;
}
const Lazy<T>& operator=(std::variant<T, std::function<T()>>&& value)
{
m_value = std::move(value);
return *this;
}
const T& operator*() const { return *ComputeValue(); } const T& operator*() const { return *ComputeValue(); }
const T* operator->() const { return ComputeValue(); } const T* operator->() const { return ComputeValue(); }
T& operator*() { return *ComputeValue(); } T& operator*() { return *ComputeValue(); }

View File

@ -116,7 +116,6 @@ void Stop()
{ {
StopDVDThread(); StopDVDThread();
s_disc.reset(); s_disc.reset();
FileMonitor::SetFileSystem(nullptr);
} }
static void StopDVDThread() static void StopDVDThread()
@ -160,14 +159,9 @@ void DoState(PointerWrap& p)
if (had_disc != HasDisc()) if (had_disc != HasDisc())
{ {
if (had_disc) if (had_disc)
{
PanicAlertT("An inserted disc was expected but not found."); PanicAlertT("An inserted disc was expected but not found.");
}
else else
{
s_disc.reset(); s_disc.reset();
FileMonitor::SetFileSystem(nullptr);
}
} }
// TODO: Savestates can be smaller if the buffers of results aren't saved, // TODO: Savestates can be smaller if the buffers of results aren't saved,
@ -185,7 +179,6 @@ void SetDisc(std::unique_ptr<DiscIO::Volume> disc)
{ {
WaitUntilIdle(); WaitUntilIdle();
s_disc = std::move(disc); s_disc = std::move(disc);
FileMonitor::SetFileSystem(s_disc.get());
} }
bool HasDisc() bool HasDisc()
@ -356,7 +349,7 @@ static void DVDThread()
ReadRequest request; ReadRequest request;
while (s_request_queue.Pop(request)) while (s_request_queue.Pop(request))
{ {
FileMonitor::Log(request.dvd_offset, request.partition); FileMonitor::Log(*s_disc, request.partition, request.dvd_offset);
std::vector<u8> buffer(request.length); std::vector<u8> buffer(request.length);
if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition)) if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))

View File

@ -21,10 +21,7 @@
namespace FileMonitor namespace FileMonitor
{ {
static const DiscIO::Volume* s_volume; static DiscIO::Partition s_previous_partition;
static bool s_new_volume = false;
static std::unique_ptr<DiscIO::FileSystem> s_filesystem;
static DiscIO::Partition s_partition;
static std::string s_previous_file; static std::string s_previous_file;
// Filtered files // Filtered files
@ -53,42 +50,19 @@ static bool IsSoundFile(const std::string& filename)
return extensions.find(extension) != extensions.end(); return extensions.find(extension) != extensions.end();
} }
void SetFileSystem(const DiscIO::Volume* volume) void Log(const DiscIO::Volume& volume, const DiscIO::Partition& partition, u64 offset)
{
// Instead of creating the file system object right away, we will let Log
// create it later once we know that it actually will get used
s_volume = volume;
s_new_volume = true;
}
// Logs access to files in the file system set by SetFileSystem
void Log(u64 offset, const DiscIO::Partition& partition)
{ {
// Do nothing if the log isn't selected // Do nothing if the log isn't selected
if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING)) if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING))
return; return;
// If the volume or partition changed, load the filesystem of the new partition const DiscIO::FileSystem* file_system = volume.GetFileSystem(partition);
if (s_new_volume || s_partition != partition)
{
// Discs with partitions don't have PARTITION_NONE filesystems,
// so let's not waste time trying to read one
const bool reading_from_partition = partition != DiscIO::PARTITION_NONE;
const bool disc_has_partitions = !s_volume->GetPartitions().empty();
if (reading_from_partition != disc_has_partitions)
return;
s_new_volume = false;
s_filesystem = DiscIO::CreateFileSystem(s_volume, partition);
s_partition = partition;
s_previous_file.clear();
}
// Do nothing if there is no valid file system // Do nothing if there is no valid file system
if (!s_filesystem) if (!file_system)
return; return;
const std::unique_ptr<DiscIO::FileInfo> file_info = s_filesystem->FindFileInfo(offset); const std::unique_ptr<DiscIO::FileInfo> file_info = file_system->FindFileInfo(offset);
// Do nothing if no file was found at that offset // Do nothing if no file was found at that offset
if (!file_info) if (!file_info)
@ -97,7 +71,7 @@ void Log(u64 offset, const DiscIO::Partition& partition)
const std::string path = file_info->GetPath(); const std::string path = file_info->GetPath();
// Do nothing if we found the same file again // Do nothing if we found the same file again
if (s_previous_file == path) if (s_previous_partition == partition && s_previous_file == path)
return; return;
const std::string size_string = ThousandSeparate(file_info->GetSize() / 1000, 7); const std::string size_string = ThousandSeparate(file_info->GetSize() / 1000, 7);
@ -109,6 +83,7 @@ void Log(u64 offset, const DiscIO::Partition& partition)
WARN_LOG(FILEMON, "%s", log_string.c_str()); WARN_LOG(FILEMON, "%s", log_string.c_str());
// Update the last accessed file // Update the last accessed file
s_previous_partition = partition;
s_previous_file = path; s_previous_file = path;
} }

View File

@ -14,9 +14,5 @@ class Volume;
namespace FileMonitor namespace FileMonitor
{ {
// Can be called with nullptr to set the file system to nothing. When not called void Log(const DiscIO::Volume& volume, const DiscIO::Partition& partition, u64 offset);
// with nullptr, the volume must remain valid until the next SetFileSystem call.
void SetFileSystem(const DiscIO::Volume* volume);
// Logs access to files in the file system set by SetFileSystem
void Log(u64 offset, const DiscIO::Partition& partition);
} }

View File

@ -552,7 +552,7 @@ private:
UpdateCallback m_update_callback; UpdateCallback m_update_callback;
std::unique_ptr<DiscIO::Volume> m_volume; std::unique_ptr<DiscIO::Volume> m_volume;
std::unique_ptr<DiscIO::FileSystem> m_disc_fs; DiscIO::Partition m_partition;
}; };
UpdateResult DiscSystemUpdater::DoDiscUpdate() UpdateResult DiscSystemUpdater::DoDiscUpdate()
@ -578,16 +578,21 @@ UpdateResult DiscSystemUpdater::DoDiscUpdate()
return UpdateResult::MissingUpdatePartition; return UpdateResult::MissingUpdatePartition;
} }
m_disc_fs = DiscIO::CreateFileSystem(m_volume.get(), *update_partition); m_partition = *update_partition;
if (!m_disc_fs || !m_disc_fs->IsValid())
return UpdateResult::DiscReadFailed;
return UpdateFromManifest("__update.inf"); return UpdateFromManifest("__update.inf");
} }
UpdateResult DiscSystemUpdater::UpdateFromManifest(const std::string& manifest_name) UpdateResult DiscSystemUpdater::UpdateFromManifest(const std::string& manifest_name)
{ {
const std::unique_ptr<DiscIO::FileInfo> update_manifest = m_disc_fs->FindFileInfo(manifest_name); const DiscIO::FileSystem* disc_fs = m_volume->GetFileSystem(m_partition);
if (!disc_fs)
{
ERROR_LOG(CORE, "Could not read the update partition file system");
return UpdateResult::DiscReadFailed;
}
const std::unique_ptr<DiscIO::FileInfo> update_manifest = disc_fs->FindFileInfo(manifest_name);
if (!update_manifest || if (!update_manifest ||
(update_manifest->GetSize() - sizeof(ManifestHeader)) % sizeof(Entry) != 0) (update_manifest->GetSize() - sizeof(ManifestHeader)) % sizeof(Entry) != 0)
{ {
@ -604,8 +609,8 @@ UpdateResult DiscSystemUpdater::UpdateFromManifest(const std::string& manifest_n
for (u32 i = 0; i < num_entries; ++i) for (u32 i = 0; i < num_entries; ++i)
{ {
const u32 offset = sizeof(ManifestHeader) + sizeof(Entry) * i; const u32 offset = sizeof(ManifestHeader) + sizeof(Entry) * i;
if (entry.size() != DiscIO::ReadFile(*m_volume, m_disc_fs->GetPartition(), if (entry.size() != DiscIO::ReadFile(*m_volume, m_partition, update_manifest.get(),
update_manifest.get(), entry.data(), entry.size(), offset)) entry.data(), entry.size(), offset))
{ {
ERROR_LOG(CORE, "Failed to read update information from update manifest"); ERROR_LOG(CORE, "Failed to read update information from update manifest");
return UpdateResult::DiscReadFailed; return UpdateResult::DiscReadFailed;
@ -654,14 +659,13 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs,
return UpdateResult::AlreadyUpToDate; return UpdateResult::AlreadyUpToDate;
// Import the WAD. // Import the WAD.
const std::unique_ptr<DiscIO::FileInfo> wad_file = m_disc_fs->FindFileInfo(path); auto blob = DiscIO::VolumeFileBlobReader::Create(*m_volume, m_partition, path);
if (!wad_file) if (!blob)
{ {
ERROR_LOG(CORE, "Failed to get info for %s", path.c_str()); ERROR_LOG(CORE, "Could not find %s", path.c_str());
return UpdateResult::DiscReadFailed; return UpdateResult::DiscReadFailed;
} }
const DiscIO::WiiWAD wad{std::move(blob)};
const DiscIO::WiiWAD wad{DiscIO::VolumeFileBlobReader::Create(*m_volume, *m_disc_fs, path)};
return InstallWAD(m_ios, wad) ? UpdateResult::Succeeded : UpdateResult::ImportFailed; return InstallWAD(m_ios, wad) ? UpdateResult::Succeeded : UpdateResult::ImportFailed;
} }

View File

@ -61,6 +61,17 @@ u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* f
return read_length; return read_length;
} }
u64 ReadFile(const Volume& volume, const Partition& partition, const std::string& path, u8* buffer,
u64 max_buffer_size, u64 offset_in_file)
{
const FileSystem* file_system = volume.GetFileSystem(partition);
if (!file_system)
return 0;
return ReadFile(volume, partition, file_system->FindFileInfo(path).get(), buffer, max_buffer_size,
offset_in_file);
}
bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size, bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size,
const std::string& export_filename) const std::string& export_filename)
{ {
@ -98,6 +109,16 @@ bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo
export_filename); export_filename);
} }
bool ExportFile(const Volume& volume, const Partition& partition, const std::string& path,
const std::string& export_filename)
{
const FileSystem* file_system = volume.GetFileSystem(partition);
if (!file_system)
return false;
return ExportFile(volume, partition, file_system->FindFileInfo(path).get(), export_filename);
}
void ExportDirectory(const Volume& volume, const Partition partition, const FileInfo& directory, void ExportDirectory(const Volume& volume, const Partition partition, const FileInfo& directory,
bool recursive, const std::string& filesystem_path, bool recursive, const std::string& filesystem_path,
const std::string& export_folder, const std::string& export_folder,

View File

@ -19,10 +19,14 @@ std::string DirectoryNameForPartitionType(u32 partition_type);
u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0); u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0);
u64 ReadFile(const Volume& volume, const Partition& partition, const std::string& path, u8* buffer,
u64 max_buffer_size, u64 offset_in_file = 0);
bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size, bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size,
const std::string& export_filename); const std::string& export_filename);
bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
const std::string& export_filename); const std::string& export_filename);
bool ExportFile(const Volume& volume, const Partition& partition, const std::string& path,
const std::string& export_filename);
// update_progress is called once for each child (file or directory). // update_progress is called once for each child (file or directory).
// If update_progress returns true, the extraction gets cancelled. // If update_progress returns true, the extraction gets cancelled.

View File

@ -182,7 +182,7 @@ bool DiscScrubber::ParseDisc()
// Operations dealing with encrypted space are done here // Operations dealing with encrypted space are done here
bool DiscScrubber::ParsePartitionData(const Partition& partition, PartitionHeader* header) bool DiscScrubber::ParsePartitionData(const Partition& partition, PartitionHeader* header)
{ {
std::unique_ptr<FileSystem> filesystem(CreateFileSystem(m_disc.get(), partition)); const FileSystem* filesystem = m_disc->GetFileSystem(partition);
if (!filesystem) if (!filesystem)
{ {
ERROR_LOG(DISCIO, "Failed to read file system for the partition at 0x%" PRIx64, ERROR_LOG(DISCIO, "Failed to read file system for the partition at 0x%" PRIx64,

View File

@ -185,19 +185,19 @@ bool FileInfoGCWii::IsValid(u64 fst_size, const FileInfoGCWii& parent_directory)
} }
FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partition) FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partition)
: FileSystem(volume, partition), m_valid(false), m_root(nullptr, 0, 0, 0) : m_valid(false), m_root(nullptr, 0, 0, 0)
{ {
u8 offset_shift; u8 offset_shift;
// Check if this is a GameCube or Wii disc // Check if this is a GameCube or Wii disc
if (m_volume->ReadSwapped<u32>(0x18, m_partition) == u32(0x5D1C9EA3)) if (volume->ReadSwapped<u32>(0x18, partition) == u32(0x5D1C9EA3))
offset_shift = 2; // Wii file system offset_shift = 2; // Wii file system
else if (m_volume->ReadSwapped<u32>(0x1c, m_partition) == u32(0xC2339F3D)) else if (volume->ReadSwapped<u32>(0x1c, partition) == u32(0xC2339F3D))
offset_shift = 0; // GameCube file system offset_shift = 0; // GameCube file system
else else
return; // Invalid partition (maybe someone removed its data but not its partition table entry) return; // Invalid partition (maybe someone removed its data but not its partition table entry)
const std::optional<u64> fst_offset = GetFSTOffset(*m_volume, m_partition); const std::optional<u64> fst_offset = GetFSTOffset(*volume, partition);
const std::optional<u64> fst_size = GetFSTSize(*m_volume, m_partition); const std::optional<u64> fst_size = GetFSTSize(*volume, partition);
if (!fst_offset || !fst_size) if (!fst_offset || !fst_size)
return; return;
if (*fst_size < FST_ENTRY_SIZE) if (*fst_size < FST_ENTRY_SIZE)
@ -220,7 +220,7 @@ FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partitio
// Read the whole FST // Read the whole FST
m_file_system_table.resize(*fst_size); m_file_system_table.resize(*fst_size);
if (!m_volume->Read(*fst_offset, *fst_size, m_file_system_table.data(), m_partition)) if (!volume->Read(*fst_offset, *fst_size, m_file_system_table.data(), partition))
{ {
ERROR_LOG(DISCIO, "Couldn't read file system table"); ERROR_LOG(DISCIO, "Couldn't read file system table");
return; return;

View File

@ -3,35 +3,11 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "DiscIO/Filesystem.h" #include "DiscIO/Filesystem.h"
#include <memory>
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Volume.h"
namespace DiscIO namespace DiscIO
{ {
FileInfo::~FileInfo() = default; FileInfo::~FileInfo() = default;
FileSystem::FileSystem(const Volume* volume, const Partition& partition)
: m_volume(volume), m_partition(partition)
{
}
FileSystem::~FileSystem() = default; FileSystem::~FileSystem() = default;
std::unique_ptr<FileSystem> CreateFileSystem(const Volume* volume, const Partition& partition)
{
if (!volume)
return nullptr;
std::unique_ptr<FileSystem> filesystem = std::make_unique<FileSystemGCWii>(volume, partition);
if (!filesystem)
return nullptr;
if (!filesystem->IsValid())
filesystem.reset();
return filesystem;
}
} // namespace } // namespace

View File

@ -106,11 +106,9 @@ protected:
class FileSystem class FileSystem
{ {
public: public:
FileSystem(const Volume* volume, const Partition& partition);
virtual ~FileSystem(); virtual ~FileSystem();
// If IsValid is false, GetRoot must not be called. CreateFileSystem // If IsValid is false, GetRoot must not be called.
// takes care of this automatically, so other code is recommended to use it.
virtual bool IsValid() const = 0; virtual bool IsValid() const = 0;
// The object returned by GetRoot and all objects created from it // The object returned by GetRoot and all objects created from it
// are only valid for as long as the file system object is valid. // are only valid for as long as the file system object is valid.
@ -119,14 +117,10 @@ public:
virtual std::unique_ptr<FileInfo> FindFileInfo(const std::string& path) const = 0; virtual std::unique_ptr<FileInfo> FindFileInfo(const std::string& path) const = 0;
// Returns nullptr if not found // Returns nullptr if not found
virtual std::unique_ptr<FileInfo> FindFileInfo(u64 disc_offset) const = 0; virtual std::unique_ptr<FileInfo> FindFileInfo(u64 disc_offset) const = 0;
virtual const Partition GetPartition() const { return m_partition; }
protected:
const Volume* const m_volume;
const Partition m_partition;
}; };
// Returns nullptr if a valid file system could not be created // Calling Volume::GetFileSystem instead of manually constructing a filesystem is recommended,
std::unique_ptr<FileSystem> CreateFileSystem(const Volume* volume, const Partition& partition); // because it will check IsValid for you, will automatically pick the right type of filesystem,
// and will cache the filesystem in case it's needed again later.
} // namespace } // namespace

View File

@ -21,6 +21,7 @@
namespace DiscIO namespace DiscIO
{ {
enum class BlobType; enum class BlobType;
class FileSystem;
struct Partition final struct Partition final
{ {
@ -67,6 +68,8 @@ public:
return INVALID_TICKET; return INVALID_TICKET;
} }
virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; } virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; }
// Returns a non-owning pointer. Returns nullptr if the file system couldn't be read.
virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0;
std::string GetGameID() const { return GetGameID(GetGamePartition()); } std::string GetGameID() const { return GetGameID(GetGamePartition()); }
virtual std::string GetGameID(const Partition& partition) const = 0; virtual std::string GetGameID(const Partition& partition) const = 0;
std::string GetMakerID() const { return GetMakerID(GetGamePartition()); } std::string GetMakerID() const { return GetMakerID(GetGamePartition()); }

View File

@ -10,23 +10,24 @@
namespace DiscIO namespace DiscIO
{ {
std::unique_ptr<VolumeFileBlobReader> VolumeFileBlobReader::Create(const Volume& volume, std::unique_ptr<VolumeFileBlobReader> VolumeFileBlobReader::Create(const Volume& volume,
const FileSystem& file_system, const Partition& partition,
const std::string& file_path) const std::string& file_path)
{ {
if (!file_system.IsValid()) const FileSystem* file_system = volume.GetFileSystem(partition);
if (!file_system)
return nullptr; 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()) if (!file_info || file_info->IsDirectory())
return nullptr; return nullptr;
return std::unique_ptr<VolumeFileBlobReader>{ 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) 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()) if (offset + length > m_file_info->GetSize())
return false; return false;
return m_volume.Read(m_file_info->GetOffset() + offset, length, out_ptr, return m_volume.Read(m_file_info->GetOffset() + offset, length, out_ptr, m_partition);
m_file_system.GetPartition());
} }
} // namespace } // namespace

View File

@ -13,14 +13,14 @@
namespace DiscIO namespace DiscIO
{ {
class FileInfo; class FileInfo;
class FileSystem; struct Partition;
class Volume; class Volume;
class VolumeFileBlobReader final : public BlobReader class VolumeFileBlobReader final : public BlobReader
{ {
public: public:
static std::unique_ptr<VolumeFileBlobReader> 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; } BlobType GetBlobType() const override { return BlobType::PLAIN; }
u64 GetDataSize() const override; u64 GetDataSize() const override;
@ -28,11 +28,11 @@ public:
bool Read(u64 offset, u64 length, u8* out_ptr) override; bool Read(u64 offset, u64 length, u8* out_ptr) override;
private: private:
VolumeFileBlobReader(const Volume& volume, const FileSystem& file_system, VolumeFileBlobReader(const Volume& volume, const Partition& partition,
std::unique_ptr<FileInfo> file_info); std::unique_ptr<FileInfo> file_info);
const Volume& m_volume; const Volume& m_volume;
const FileSystem& m_file_system; const Partition& m_partition;
std::unique_ptr<FileInfo> m_file_info; std::unique_ptr<FileInfo> m_file_info;
}; };
} // namespace } // namespace

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cinttypes>
#include <cstddef> #include <cstddef>
#include <map> #include <map>
#include <memory> #include <memory>
@ -20,6 +21,7 @@
#include "DiscIO/Blob.h" #include "DiscIO/Blob.h"
#include "DiscIO/DiscExtractor.h" #include "DiscIO/DiscExtractor.h"
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Filesystem.h" #include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h" #include "DiscIO/Volume.h"
#include "DiscIO/VolumeGC.h" #include "DiscIO/VolumeGC.h"
@ -29,6 +31,13 @@ namespace DiscIO
VolumeGC::VolumeGC(std::unique_ptr<BlobReader> reader) : m_pReader(std::move(reader)) VolumeGC::VolumeGC(std::unique_ptr<BlobReader> reader) : m_pReader(std::move(reader))
{ {
_assert_(m_pReader); _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() 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); 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 std::string VolumeGC::GetGameID(const Partition& partition) const
{ {
static const std::string NO_UID("NO_UID"); 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 std::map<Language, std::string> VolumeGC::GetShortNames() const
{ {
LoadBannerFile(); return m_converted_banner->short_names;
return m_short_names;
} }
std::map<Language, std::string> VolumeGC::GetLongNames() const std::map<Language, std::string> VolumeGC::GetLongNames() const
{ {
LoadBannerFile(); return m_converted_banner->long_names;
return m_long_names;
} }
std::map<Language, std::string> VolumeGC::GetShortMakers() const std::map<Language, std::string> VolumeGC::GetShortMakers() const
{ {
LoadBannerFile(); return m_converted_banner->short_makers;
return m_short_makers;
} }
std::map<Language, std::string> VolumeGC::GetLongMakers() const std::map<Language, std::string> VolumeGC::GetLongMakers() const
{ {
LoadBannerFile(); return m_converted_banner->long_makers;
return m_long_makers;
} }
std::map<Language, std::string> VolumeGC::GetDescriptions() const std::map<Language, std::string> VolumeGC::GetDescriptions() const
{ {
LoadBannerFile(); return m_converted_banner->descriptions;
return m_descriptions;
} }
std::vector<u32> VolumeGC::GetBanner(int* width, int* height) const std::vector<u32> VolumeGC::GetBanner(int* width, int* height) const
{ {
LoadBannerFile(); *width = m_converted_banner->image_width;
*width = m_image_width; *height = m_converted_banner->image_height;
*height = m_image_height; return m_converted_banner->image_buffer;
return m_image_buffer;
} }
std::string VolumeGC::GetApploaderDate(const Partition& partition) const std::string VolumeGC::GetApploaderDate(const Partition& partition) const
@ -183,39 +191,19 @@ Platform VolumeGC::GetVolumeType() const
return Platform::GAMECUBE_DISC; 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; GCBanner banner_file;
std::unique_ptr<FileSystem> file_system(CreateFileSystem(this, PARTITION_NONE)); const u64 file_size = ReadFile(*this, PARTITION_NONE, "opening.bnr",
if (!file_system) reinterpret_cast<u8*>(&banner_file), sizeof(GCBanner));
return; if (file_size < 4)
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))
{ {
WARN_LOG(DISCIO, "Could not read opening.bnr."); 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; bool is_bnr1;
if (banner_file.id == BNR1_MAGIC && file_size == BNR1_SIZE) if (banner_file.id == BNR1_MAGIC && file_size == BNR1_SIZE)
{ {
@ -228,14 +216,17 @@ void VolumeGC::LoadBannerFile() const
else else
{ {
WARN_LOG(DISCIO, "Invalid opening.bnr. Type: %0x Size: %0zx", banner_file.id, file_size); 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; u32 number_of_languages = 0;
Language start_language = Language::LANGUAGE_UNKNOWN; 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; start_language = Language::LANGUAGE_ENGLISH;
} }
m_image_width = GC_BANNER_WIDTH; banner.image_width = GC_BANNER_WIDTH;
m_image_height = GC_BANNER_HEIGHT; banner.image_height = GC_BANNER_HEIGHT;
m_image_buffer = std::vector<u32>(m_image_width * m_image_height); banner.image_buffer = std::vector<u32>(GC_BANNER_WIDTH * GC_BANNER_HEIGHT);
ColorUtil::decode5A3image(m_image_buffer.data(), banner_file.image, m_image_width, ColorUtil::decode5A3image(banner.image_buffer.data(), banner_file.image, GC_BANNER_WIDTH,
m_image_height); GC_BANNER_HEIGHT);
for (u32 i = 0; i < number_of_languages; ++i) 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); std::string description = DecodeString(info.description);
if (!description.empty()) if (!description.empty())
m_descriptions[language] = description; banner.descriptions.emplace(language, description);
std::string short_name = DecodeString(info.short_name); std::string short_name = DecodeString(info.short_name);
if (!short_name.empty()) 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); std::string long_name = DecodeString(info.long_name);
if (!long_name.empty()) 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); std::string short_maker = DecodeString(info.short_maker);
if (!short_maker.empty()) 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); std::string long_maker = DecodeString(info.long_maker);
if (!long_maker.empty()) if (!long_maker.empty())
m_long_makers[language] = long_maker; banner.long_makers.emplace(language, long_maker);
} }
return banner;
} }
} // namespace } // namespace

View File

@ -11,6 +11,8 @@
#include <vector> #include <vector>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Lazy.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h" #include "DiscIO/Volume.h"
// --- this volume type is used for GC disc images --- // --- this volume type is used for GC disc images ---
@ -20,6 +22,7 @@ namespace DiscIO
class BlobReader; class BlobReader;
enum class BlobType; enum class BlobType;
enum class Country; enum class Country;
class FileSystem;
enum class Language; enum class Language;
enum class Region; enum class Region;
enum class Platform; enum class Platform;
@ -31,6 +34,7 @@ public:
~VolumeGC(); ~VolumeGC();
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool Read(u64 _Offset, u64 _Length, u8* _pBuffer,
const Partition& partition = PARTITION_NONE) const override; 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 GetGameID(const Partition& partition = PARTITION_NONE) const override;
std::string GetMakerID(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; std::optional<u16> GetRevision(const Partition& partition = PARTITION_NONE) const override;
@ -75,23 +79,28 @@ private:
// (only one for BNR1 type) // (only one for BNR1 type)
}; };
void LoadBannerFile() const; struct ConvertedGCBanner
void ExtractBannerInformation(const GCBanner& banner_file, bool is_bnr1) const; {
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 BNR1_SIZE = sizeof(GCBanner) - sizeof(GCBannerInformation) * 5;
static const size_t BNR2_SIZE = sizeof(GCBanner); static const size_t BNR2_SIZE = sizeof(GCBanner);
mutable std::map<Language, std::string> m_short_names; Common::Lazy<ConvertedGCBanner> m_converted_banner;
mutable std::map<Language, std::string> m_long_names; Common::Lazy<std::unique_ptr<FileSystem>> m_file_system;
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;
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;
std::unique_ptr<BlobReader> m_pReader; std::unique_ptr<BlobReader> m_pReader;
}; };

View File

@ -65,6 +65,12 @@ bool VolumeWAD::Read(u64 offset, u64 length, u8* buffer, const Partition& partit
return m_reader->Read(offset, length, buffer); return m_reader->Read(offset, length, buffer);
} }
const FileSystem* VolumeWAD::GetFileSystem(const Partition& partition) const
{
// TODO: Implement this?
return nullptr;
}
Region VolumeWAD::GetRegion() const Region VolumeWAD::GetRegion() const
{ {
if (!m_tmd.IsValid()) if (!m_tmd.IsValid())

View File

@ -23,6 +23,7 @@ namespace DiscIO
class BlobReader; class BlobReader;
enum class BlobType; enum class BlobType;
enum class Country; enum class Country;
class FileSystem;
enum class Language; enum class Language;
enum class Region; enum class Region;
enum class Platform; enum class Platform;
@ -34,6 +35,7 @@ public:
~VolumeWAD(); ~VolumeWAD();
bool Read(u64 offset, u64 length, u8* buffer, bool Read(u64 offset, u64 length, u8* buffer,
const Partition& partition = PARTITION_NONE) const override; 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; std::optional<u64> GetTitleID(const Partition& partition = PARTITION_NONE) const override;
const IOS::ES::TMDReader& GetTMD(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; std::string GetGameID(const Partition& partition = PARTITION_NONE) const override;

View File

@ -26,6 +26,7 @@
#include "DiscIO/Blob.h" #include "DiscIO/Blob.h"
#include "DiscIO/DiscExtractor.h" #include "DiscIO/DiscExtractor.h"
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Filesystem.h" #include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h" #include "DiscIO/Volume.h"
@ -111,10 +112,17 @@ VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
return aes_context; 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( m_partitions.emplace(
partition, PartitionDetails{Common::Lazy<std::unique_ptr<mbedtls_aes_context>>(get_key), partition, PartitionDetails{Common::Lazy<std::unique_ptr<mbedtls_aes_context>>(get_key),
Common::Lazy<IOS::ES::TicketReader>(get_ticket), 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; 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) u64 VolumeWii::PartitionOffsetToRawOffset(u64 offset, const Partition& partition)
{ {
if (partition == PARTITION_NONE) 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::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::vector<u8> opening_bnr(NAMES_TOTAL_BYTES);
std::unique_ptr<FileInfo> file_info = file_system->FindFileInfo("opening.bnr"); opening_bnr.resize(ReadFile(*this, GetGamePartition(), "opening.bnr", opening_bnr.data(),
opening_bnr.resize(ReadFile(*this, GetGamePartition(), file_info.get(), opening_bnr.data(),
opening_bnr.size(), 0x5C)); opening_bnr.size(), 0x5C));
return ReadWiiNames(opening_bnr); return ReadWiiNames(opening_bnr);
} }

View File

@ -14,15 +14,17 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Lazy.h" #include "Common/Lazy.h"
#include "Core/IOS/ES/Formats.h" #include "Core/IOS/ES/Formats.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.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 namespace DiscIO
{ {
class BlobReader; class BlobReader;
enum class BlobType; enum class BlobType;
enum class Country; enum class Country;
class FileSystem;
enum class Language; enum class Language;
enum class Region; enum class Region;
enum class Platform; enum class Platform;
@ -39,6 +41,7 @@ public:
std::optional<u64> GetTitleID(const Partition& partition) const override; std::optional<u64> GetTitleID(const Partition& partition) const override;
const IOS::ES::TicketReader& GetTicket(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 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 GetGameID(const Partition& partition) const override;
std::string GetMakerID(const Partition& partition) const override; std::string GetMakerID(const Partition& partition) const override;
std::optional<u16> GetRevision(const Partition& partition) const override; std::optional<u16> GetRevision(const Partition& partition) const override;
@ -72,6 +75,7 @@ private:
Common::Lazy<std::unique_ptr<mbedtls_aes_context>> key; Common::Lazy<std::unique_ptr<mbedtls_aes_context>> key;
Common::Lazy<IOS::ES::TicketReader> ticket; Common::Lazy<IOS::ES::TicketReader> ticket;
Common::Lazy<IOS::ES::TMDReader> tmd; Common::Lazy<IOS::ES::TMDReader> tmd;
Common::Lazy<std::unique_ptr<FileSystem>> file_system;
u32 type; u32 type;
}; };

View File

@ -85,8 +85,7 @@ void FilesystemWidget::PopulateView()
for (size_t i = 0; i < partitions.size(); i++) for (size_t i = 0; i < partitions.size(); i++)
{ {
std::unique_ptr<DiscIO::FileSystem> file_system( const DiscIO::FileSystem* file_system = m_volume->GetFileSystem(partitions[i]);
DiscIO::CreateFileSystem(m_volume.get(), partitions[i]));
auto* item = new QStandardItem(tr("Partition %1").arg(i)); auto* item = new QStandardItem(tr("Partition %1").arg(i));
item->setEditable(false); item->setEditable(false);
@ -104,10 +103,7 @@ void FilesystemWidget::PopulateView()
} }
if (partitions.empty()) if (partitions.empty())
{ PopulateDirectory(-1, disc, m_volume->GetFileSystem(DiscIO::PARTITION_NONE)->GetRoot());
PopulateDirectory(-1, disc,
DiscIO::CreateFileSystem(m_volume.get(), DiscIO::PARTITION_NONE)->GetRoot());
}
} }
void FilesystemWidget::PopulateDirectory(int partition_id, QStandardItem* root, 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, void FilesystemWidget::ExtractDirectory(const DiscIO::Partition& partition, const QString path,
const QString& out) const QString& out)
{ {
std::unique_ptr<DiscIO::FileSystem> filesystem( const DiscIO::FileSystem* filesystem = m_volume->GetFileSystem(partition);
DiscIO::CreateFileSystem(m_volume.get(), partition));
std::unique_ptr<DiscIO::FileInfo> info = filesystem->FindFileInfo(path.toStdString()); std::unique_ptr<DiscIO::FileInfo> info = filesystem->FindFileInfo(path.toStdString());
u32 size = info->GetTotalChildren(); u32 size = info->GetTotalChildren();
@ -251,7 +245,7 @@ void FilesystemWidget::ExtractDirectory(const DiscIO::Partition& partition, cons
bool all = path.isEmpty(); bool all = path.isEmpty();
DiscIO::ExportDirectory( 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) { [all, dialog](const std::string& current) {
dialog->setLabelText( dialog->setLabelText(
(all ? QObject::tr("Extracting All Files...") : QObject::tr("Extracting Directory...")) (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, void FilesystemWidget::ExtractFile(const DiscIO::Partition& partition, const QString& path,
const QString& out) const QString& out)
{ {
std::unique_ptr<DiscIO::FileSystem> filesystem( const DiscIO::FileSystem* filesystem = m_volume->GetFileSystem(partition);
DiscIO::CreateFileSystem(m_volume.get(), partition));
bool success = DiscIO::ExportFile( bool success = DiscIO::ExportFile(
*m_volume, partition, filesystem->FindFileInfo(path.toStdString()).get(), out.toStdString()); *m_volume, partition, filesystem->FindFileInfo(path.toStdString()).get(), out.toStdString());

View File

@ -36,11 +36,8 @@ namespace
class WiiPartition final : public wxTreeItemData class WiiPartition final : public wxTreeItemData
{ {
public: public:
WiiPartition(std::unique_ptr<DiscIO::FileSystem> filesystem_) : filesystem{std::move(filesystem_)} WiiPartition(const DiscIO::Partition& partition_) : partition(partition_) {}
{ DiscIO::Partition partition;
}
std::unique_ptr<DiscIO::FileSystem> filesystem;
}; };
enum : int 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) WiiPartition* FindWiiPartition(wxTreeCtrl* tree_ctrl, const wxString& label)
{ {
wxTreeItemIdValue cookie; wxTreeItemIdValue cookie;
@ -154,30 +158,22 @@ bool FilesystemPanel::PopulateFileSystemTree()
{ {
for (size_t i = 0; i < partitions.size(); ++i) for (size_t i = 0; i < partitions.size(); ++i)
{ {
std::unique_ptr<DiscIO::FileSystem> file_system( wxTreeItemId partition_root = m_tree_ctrl->AppendItem(
DiscIO::CreateFileSystem(m_opened_iso.get(), partitions[i])); m_tree_ctrl->GetRootItem(), wxString::Format(_("Partition %zu"), i), ICON_DISC);
if (file_system)
{
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); m_tree_ctrl->SetItemData(partition_root, partition);
CreateDirectoryTree(m_tree_ctrl, partition_root, partition->filesystem->GetRoot()); CreateDirectoryTree(m_tree_ctrl, partition_root, m_opened_iso->GetFileSystem(partitions[i]));
if (partitions[i] == m_opened_iso->GetGamePartition()) if (partitions[i] == m_opened_iso->GetGamePartition())
m_tree_ctrl->Expand(partition_root); m_tree_ctrl->Expand(partition_root);
}
} }
} }
else else
{ {
m_filesystem = DiscIO::CreateFileSystem(m_opened_iso.get(), DiscIO::PARTITION_NONE); CreateDirectoryTree(m_tree_ctrl, m_tree_ctrl->GetRootItem(),
if (!m_filesystem) m_opened_iso->GetFileSystem(DiscIO::PARTITION_NONE));
return false;
CreateDirectoryTree(m_tree_ctrl, m_tree_ctrl->GetRootItem(), m_filesystem->GetRoot());
} }
return true; 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 selection_data = m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection());
const auto* const wii_partition = static_cast<const WiiPartition*>(selection_data); const auto* const wii_partition = static_cast<const WiiPartition*>(selection_data);
partition = wii_partition->filesystem->GetPartition(); partition = wii_partition->partition;
} }
else else
{ {
@ -293,11 +289,11 @@ void FilesystemPanel::OnExtractAll(wxCommandEvent& event)
{ {
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(item)); const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(item));
const std::optional<u32> partition_type = const std::optional<u32> partition_type =
*m_opened_iso->GetPartitionType(partition->filesystem->GetPartition()); *m_opened_iso->GetPartitionType(partition->partition);
if (partition_type) if (partition_type)
{ {
const std::string partition_name = DiscIO::DirectoryNameForPartitionType(*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); item = m_tree_ctrl->GetNextChild(root, cookie);
} }
@ -305,11 +301,11 @@ void FilesystemPanel::OnExtractAll(wxCommandEvent& event)
else if (m_has_partitions && !first_item_selected) else if (m_has_partitions && !first_item_selected)
{ {
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(selection)); 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 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(); const auto selection = m_tree_ctrl->GetSelection();
WiiPartition* partition = WiiPartition* partition =
static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection())); static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection()));
std::future<bool> is_valid = std::async(std::launch::async, [&] { std::future<bool> is_valid = std::async(
return m_opened_iso->CheckIntegrity(partition->filesystem->GetPartition()); std::launch::async, [&] { return m_opened_iso->CheckIntegrity(partition->partition); });
});
while (is_valid.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready) while (is_valid.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
dialog.Pulse(); dialog.Pulse();
@ -350,23 +345,26 @@ void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))
void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const
{ {
const std::pair<wxString, const DiscIO::FileSystem&> path = BuildFilePathFromSelection(); const std::pair<wxString, DiscIO::Partition> path = BuildFilePathFromSelection();
DiscIO::ExportFile(*m_opened_iso, path.second.GetPartition(), DiscIO::ExportFile(*m_opened_iso, path.second, WxStrToStr(path.first),
path.second.FindFileInfo(WxStrToStr(path.first)).get(),
WxStrToStr(output_file_path)); WxStrToStr(output_file_path));
} }
void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder) 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); ExtractDirectories(WxStrToStr(path.first), WxStrToStr(output_folder), path.second);
} }
void FilesystemPanel::ExtractDirectories(const std::string& full_path, void FilesystemPanel::ExtractDirectories(const std::string& full_path,
const std::string& output_folder, 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 size = file_info->GetTotalChildren();
u32 progress = 0; u32 progress = 0;
@ -376,7 +374,7 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH); wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
DiscIO::ExportDirectory( 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) { [&](const std::string& path) {
dialog.SetTitle(wxString::Format( dialog.SetTitle(wxString::Format(
"%s : %d%%", dialog_title.c_str(), "%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, void FilesystemPanel::ExtractPartition(const std::string& output_folder,
const DiscIO::FileSystem& filesystem) const DiscIO::Partition& partition)
{ {
ExtractDirectories("", output_folder + "/files", filesystem); ExtractDirectories("", output_folder + "/files", partition);
DiscIO::ExportSystemData(*m_opened_iso, filesystem.GetPartition(), output_folder); 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(); const wxTreeItemId root_node = m_tree_ctrl->GetRootItem();
wxTreeItemId node = m_tree_ctrl->GetSelection(); 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 size_t slash_index = file_path.find('/');
const wxString partition_label = file_path.substr(0, slash_index); 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/" // Remove "Partition x/"
file_path.erase(0, slash_index + 1); file_path.erase(0, slash_index + 1);
return {file_path, *partition->filesystem}; return {file_path, partition->partition};
} }
else else
{ {
return {file_path, *m_filesystem}; return {file_path, DiscIO::PARTITION_NONE};
} }
} }
std::pair<wxString, const DiscIO::FileSystem&> std::pair<wxString, DiscIO::Partition> FilesystemPanel::BuildDirectoryPathFromSelection() const
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}; return {result.first + DIR_SEP_CHR, result.second};
} }

View File

@ -15,7 +15,7 @@ class wxTreeEvent;
namespace DiscIO namespace DiscIO
{ {
class FileSystem; struct Partition;
class Volume; class Volume;
} }
@ -51,16 +51,15 @@ private:
void ExtractSingleFile(const wxString& output_file_path) const; void ExtractSingleFile(const wxString& output_file_path) const;
void ExtractSingleDirectory(const wxString& output_folder); void ExtractSingleDirectory(const wxString& output_folder);
void ExtractDirectories(const std::string& full_path, const std::string& output_folder, void ExtractDirectories(const std::string& full_path, const std::string& output_folder,
const DiscIO::FileSystem& filesystem); const DiscIO::Partition& partition);
void ExtractPartition(const std::string& output_folder, const DiscIO::FileSystem& filesystem); void ExtractPartition(const std::string& output_folder, const DiscIO::Partition& partition);
std::pair<wxString, const DiscIO::FileSystem&> BuildFilePathFromSelection() const; std::pair<wxString, DiscIO::Partition> BuildFilePathFromSelection() const;
std::pair<wxString, const DiscIO::FileSystem&> BuildDirectoryPathFromSelection() const; std::pair<wxString, DiscIO::Partition> BuildDirectoryPathFromSelection() const;
wxTreeCtrl* m_tree_ctrl; wxTreeCtrl* m_tree_ctrl;
const std::unique_ptr<DiscIO::Volume>& m_opened_iso; const std::unique_ptr<DiscIO::Volume>& m_opened_iso;
std::unique_ptr<DiscIO::FileSystem> m_filesystem;
bool m_has_partitions; bool m_has_partitions;
}; };