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(const std::variant<T, std::function<T()>>& value) : m_value(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(); }
T& operator*() { return *ComputeValue(); }

View File

@ -116,7 +116,6 @@ void Stop()
{
StopDVDThread();
s_disc.reset();
FileMonitor::SetFileSystem(nullptr);
}
static void StopDVDThread()
@ -160,14 +159,9 @@ void DoState(PointerWrap& p)
if (had_disc != HasDisc())
{
if (had_disc)
{
PanicAlertT("An inserted disc was expected but not found.");
}
else
{
s_disc.reset();
FileMonitor::SetFileSystem(nullptr);
}
}
// 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();
s_disc = std::move(disc);
FileMonitor::SetFileSystem(s_disc.get());
}
bool HasDisc()
@ -356,7 +349,7 @@ static void DVDThread()
ReadRequest 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);
if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))

View File

@ -21,10 +21,7 @@
namespace FileMonitor
{
static const DiscIO::Volume* s_volume;
static bool s_new_volume = false;
static std::unique_ptr<DiscIO::FileSystem> s_filesystem;
static DiscIO::Partition s_partition;
static DiscIO::Partition s_previous_partition;
static std::string s_previous_file;
// Filtered files
@ -53,42 +50,19 @@ static bool IsSoundFile(const std::string& filename)
return extensions.find(extension) != extensions.end();
}
void SetFileSystem(const DiscIO::Volume* volume)
{
// 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)
void Log(const DiscIO::Volume& volume, const DiscIO::Partition& partition, u64 offset)
{
// Do nothing if the log isn't selected
if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING))
return;
// If the volume or partition changed, load the filesystem of the new 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();
}
const DiscIO::FileSystem* file_system = volume.GetFileSystem(partition);
// Do nothing if there is no valid file system
if (!s_filesystem)
if (!file_system)
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
if (!file_info)
@ -97,7 +71,7 @@ void Log(u64 offset, const DiscIO::Partition& partition)
const std::string path = file_info->GetPath();
// Do nothing if we found the same file again
if (s_previous_file == path)
if (s_previous_partition == partition && s_previous_file == path)
return;
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());
// Update the last accessed file
s_previous_partition = partition;
s_previous_file = path;
}

View File

@ -14,9 +14,5 @@ class Volume;
namespace FileMonitor
{
// Can be called with nullptr to set the file system to nothing. When not called
// 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);
void Log(const DiscIO::Volume& volume, const DiscIO::Partition& partition, u64 offset);
}

View File

@ -552,7 +552,7 @@ private:
UpdateCallback m_update_callback;
std::unique_ptr<DiscIO::Volume> m_volume;
std::unique_ptr<DiscIO::FileSystem> m_disc_fs;
DiscIO::Partition m_partition;
};
UpdateResult DiscSystemUpdater::DoDiscUpdate()
@ -578,16 +578,21 @@ UpdateResult DiscSystemUpdater::DoDiscUpdate()
return UpdateResult::MissingUpdatePartition;
}
m_disc_fs = DiscIO::CreateFileSystem(m_volume.get(), *update_partition);
if (!m_disc_fs || !m_disc_fs->IsValid())
return UpdateResult::DiscReadFailed;
m_partition = *update_partition;
return UpdateFromManifest("__update.inf");
}
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 ||
(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)
{
const u32 offset = sizeof(ManifestHeader) + sizeof(Entry) * i;
if (entry.size() != DiscIO::ReadFile(*m_volume, m_disc_fs->GetPartition(),
update_manifest.get(), entry.data(), entry.size(), offset))
if (entry.size() != DiscIO::ReadFile(*m_volume, m_partition, update_manifest.get(),
entry.data(), entry.size(), offset))
{
ERROR_LOG(CORE, "Failed to read update information from update manifest");
return UpdateResult::DiscReadFailed;
@ -654,14 +659,13 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs,
return UpdateResult::AlreadyUpToDate;
// Import the WAD.
const std::unique_ptr<DiscIO::FileInfo> wad_file = m_disc_fs->FindFileInfo(path);
if (!wad_file)
auto blob = DiscIO::VolumeFileBlobReader::Create(*m_volume, m_partition, path);
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;
}
const DiscIO::WiiWAD wad{DiscIO::VolumeFileBlobReader::Create(*m_volume, *m_disc_fs, path)};
const DiscIO::WiiWAD wad{std::move(blob)};
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;
}
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,
const std::string& export_filename)
{
@ -98,6 +109,16 @@ bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo
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,
bool recursive, const std::string& filesystem_path,
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,
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,
const std::string& export_filename);
bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
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).
// 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
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)
{
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)
: FileSystem(volume, partition), m_valid(false), m_root(nullptr, 0, 0, 0)
: m_valid(false), m_root(nullptr, 0, 0, 0)
{
u8 offset_shift;
// 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
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
else
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_size = GetFSTSize(*m_volume, m_partition);
const std::optional<u64> fst_offset = GetFSTOffset(*volume, partition);
const std::optional<u64> fst_size = GetFSTSize(*volume, partition);
if (!fst_offset || !fst_size)
return;
if (*fst_size < FST_ENTRY_SIZE)
@ -220,7 +220,7 @@ FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partitio
// Read the whole FST
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");
return;

View File

@ -3,35 +3,11 @@
// Refer to the license.txt file included.
#include "DiscIO/Filesystem.h"
#include <memory>
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Volume.h"
namespace DiscIO
{
FileInfo::~FileInfo() = default;
FileSystem::FileSystem(const Volume* volume, const Partition& partition)
: m_volume(volume), m_partition(partition)
{
}
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

View File

@ -106,11 +106,9 @@ protected:
class FileSystem
{
public:
FileSystem(const Volume* volume, const Partition& partition);
virtual ~FileSystem();
// If IsValid is false, GetRoot must not be called. CreateFileSystem
// takes care of this automatically, so other code is recommended to use it.
// If IsValid is false, GetRoot must not be called.
virtual bool IsValid() const = 0;
// The object returned by GetRoot and all objects created from it
// 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;
// Returns nullptr if not found
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
std::unique_ptr<FileSystem> CreateFileSystem(const Volume* volume, const Partition& partition);
// Calling Volume::GetFileSystem instead of manually constructing a filesystem is recommended,
// 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

View File

@ -21,6 +21,7 @@
namespace DiscIO
{
enum class BlobType;
class FileSystem;
struct Partition final
{
@ -67,6 +68,8 @@ public:
return INVALID_TICKET;
}
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()); }
virtual std::string GetGameID(const Partition& partition) const = 0;
std::string GetMakerID() const { return GetMakerID(GetGamePartition()); }

View File

@ -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

View File

@ -13,14 +13,14 @@
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;
@ -28,11 +28,11 @@ public:
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

View File

@ -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

View File

@ -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 @@ public:
~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 @@ private:
// (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;
Common::Lazy<ConvertedGCBanner> m_converted_banner;
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;
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;
};

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);
}
const FileSystem* VolumeWAD::GetFileSystem(const Partition& partition) const
{
// TODO: Implement this?
return nullptr;
}
Region VolumeWAD::GetRegion() const
{
if (!m_tmd.IsValid())

View File

@ -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 @@ public:
~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;

View File

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

View File

@ -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 @@ public:
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 @@ private:
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;
};

View File

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

View File

@ -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,11 +289,11 @@ 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);
}
@ -305,11 +301,11 @@ void FilesystemPanel::OnExtractAll(wxCommandEvent& event)
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};
}

View File

@ -15,7 +15,7 @@ class wxTreeEvent;
namespace DiscIO
{
class FileSystem;
struct Partition;
class Volume;
}
@ -51,16 +51,15 @@ private:
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;
};