DiscIO: Use Common::Lazy for loading filesystems

This simplifies FileMonitor a lot and also lets us
clean up FilesystemPanel.
This commit is contained in:
JosJuice
2017-08-02 18:16:56 +02:00
parent 0d07821935
commit 38304da947
21 changed files with 182 additions and 172 deletions

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

@ -4,7 +4,6 @@
#include "DiscIO/Filesystem.h"
#include <memory>
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Volume.h"
namespace DiscIO
@ -18,20 +17,4 @@ FileSystem::FileSystem(const Volume* volume, const 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

@ -109,8 +109,7 @@ 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.
@ -126,7 +125,8 @@ protected:
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,11 @@ 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;
};
}
VolumeGC::~VolumeGC()
@ -43,6 +50,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");
@ -192,30 +204,16 @@ void VolumeGC::LoadBannerFile() const
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)
{

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;
@ -93,6 +97,8 @@ private:
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;
};