mirror of
https://gitlab.com/suyu-emu/suyu.git
synced 2024-03-15 23:15:44 +00:00
RomFS Extraction
This commit is contained in:
parent
0191a1e526
commit
906d785c73
|
@ -23,6 +23,8 @@ add_library(core STATIC
|
||||||
file_sys/partition_filesystem.h
|
file_sys/partition_filesystem.h
|
||||||
file_sys/program_metadata.cpp
|
file_sys/program_metadata.cpp
|
||||||
file_sys/program_metadata.h
|
file_sys/program_metadata.h
|
||||||
|
file_sys/romfs.cpp
|
||||||
|
file_sys/romfs.h
|
||||||
file_sys/romfs_factory.cpp
|
file_sys/romfs_factory.cpp
|
||||||
file_sys/romfs_factory.h
|
file_sys/romfs_factory.h
|
||||||
file_sys/savedata_factory.cpp
|
file_sys/savedata_factory.cpp
|
||||||
|
@ -35,6 +37,8 @@ add_library(core STATIC
|
||||||
file_sys/vfs_offset.h
|
file_sys/vfs_offset.h
|
||||||
file_sys/vfs_real.cpp
|
file_sys/vfs_real.cpp
|
||||||
file_sys/vfs_real.h
|
file_sys/vfs_real.h
|
||||||
|
file_sys/vfs_vector.cpp
|
||||||
|
file_sys/vfs_vector.h
|
||||||
frontend/emu_window.cpp
|
frontend/emu_window.cpp
|
||||||
frontend/emu_window.h
|
frontend/emu_window.h
|
||||||
frontend/framebuffer_layout.cpp
|
frontend/framebuffer_layout.cpp
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/vfs_offset.h"
|
#include "core/file_sys/vfs_offset.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
#include "romfs.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
|
@ -46,21 +47,9 @@ struct PFS0Superblock {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size.");
|
static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size.");
|
||||||
|
|
||||||
struct IVFCLevel {
|
|
||||||
u64_le offset;
|
|
||||||
u64_le size;
|
|
||||||
u32_le block_size;
|
|
||||||
u32_le reserved;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size.");
|
|
||||||
|
|
||||||
struct RomFSSuperblock {
|
struct RomFSSuperblock {
|
||||||
NCASectionHeaderBlock header_block;
|
NCASectionHeaderBlock header_block;
|
||||||
u32_le magic;
|
IVFCHeader ivfc;
|
||||||
u32_le magic_number;
|
|
||||||
INSERT_PADDING_BYTES(8);
|
|
||||||
std::array<IVFCLevel, 6> levels;
|
|
||||||
INSERT_PADDING_BYTES(64);
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(RomFSSuperblock) == 0xE8, "RomFSSuperblock has incorrect size.");
|
static_assert(sizeof(RomFSSuperblock) == 0xE8, "RomFSSuperblock has incorrect size.");
|
||||||
|
|
||||||
|
@ -92,8 +81,8 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
|
||||||
|
|
||||||
const size_t romfs_offset =
|
const size_t romfs_offset =
|
||||||
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER +
|
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER +
|
||||||
sb.levels[IVFC_MAX_LEVEL - 1].offset;
|
sb.ivfc.levels[IVFC_MAX_LEVEL - 1].offset;
|
||||||
const size_t romfs_size = sb.levels[IVFC_MAX_LEVEL - 1].size;
|
const size_t romfs_size = sb.ivfc.levels[IVFC_MAX_LEVEL - 1].size;
|
||||||
files.emplace_back(std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset));
|
files.emplace_back(std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset));
|
||||||
romfs = files.back();
|
romfs = files.back();
|
||||||
} else if (block.filesystem_type == NCASectionFilesystemType::PFS0) {
|
} else if (block.filesystem_type == NCASectionFilesystemType::PFS0) {
|
||||||
|
|
124
src/core/file_sys/romfs.cpp
Normal file
124
src/core/file_sys/romfs.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/swap.h"
|
||||||
|
#include "core/file_sys/romfs.h"
|
||||||
|
#include "core/file_sys/vfs.h"
|
||||||
|
#include "core/file_sys/vfs_offset.h"
|
||||||
|
#include "core/file_sys/vfs_vector.h"
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
|
||||||
|
constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
struct TableLocation {
|
||||||
|
u64_le offset;
|
||||||
|
u64_le size;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TableLocation) == 0x10, "TableLocation has incorrect size.");
|
||||||
|
|
||||||
|
struct RomFSHeader {
|
||||||
|
u64_le header_size;
|
||||||
|
TableLocation directory_hash;
|
||||||
|
TableLocation directory_meta;
|
||||||
|
TableLocation file_hash;
|
||||||
|
TableLocation file_meta;
|
||||||
|
u64_le data_offset;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
|
||||||
|
|
||||||
|
struct DirectoryEntry {
|
||||||
|
u32_le sibling;
|
||||||
|
u32_le child_dir;
|
||||||
|
u32_le child_file;
|
||||||
|
u32_le hash;
|
||||||
|
u32_le name_length;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(DirectoryEntry) == 0x14, "DirectoryEntry has incorrect size.");
|
||||||
|
|
||||||
|
struct FileEntry {
|
||||||
|
u32_le parent;
|
||||||
|
u32_le sibling;
|
||||||
|
u64_le offset;
|
||||||
|
u64_le size;
|
||||||
|
u32_le hash;
|
||||||
|
u32_le name_length;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
|
||||||
|
|
||||||
|
template <typename Entry>
|
||||||
|
static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t offset) {
|
||||||
|
Entry entry{};
|
||||||
|
if (file->ReadObject(&entry, offset) != sizeof(Entry))
|
||||||
|
return {};
|
||||||
|
std::string string(entry.name_length, '\0');
|
||||||
|
if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size())
|
||||||
|
return {};
|
||||||
|
return {entry, string};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 this_file_offset,
|
||||||
|
std::shared_ptr<VectorVfsDirectory> parent) {
|
||||||
|
while (true) {
|
||||||
|
auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset);
|
||||||
|
|
||||||
|
parent->AddFile(std::make_shared<OffsetVfsFile>(
|
||||||
|
file, entry.first.size, entry.first.offset + data_offset, entry.second, parent));
|
||||||
|
|
||||||
|
if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
|
||||||
|
break;
|
||||||
|
|
||||||
|
this_file_offset = entry.first.sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessDirectory(VirtualFile file, size_t dir_offset, size_t file_offset, size_t data_offset,
|
||||||
|
u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory> parent) {
|
||||||
|
while (true) {
|
||||||
|
auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset);
|
||||||
|
auto current = std::make_shared<VectorVfsDirectory>(
|
||||||
|
std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parent, entry.second);
|
||||||
|
|
||||||
|
if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
|
||||||
|
ProcessFile(file, file_offset, data_offset, entry.first.child_file, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
|
||||||
|
ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir,
|
||||||
|
current);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->AddDirectory(current);
|
||||||
|
if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
|
||||||
|
break;
|
||||||
|
this_dir_offset = entry.first.sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir ExtractRomFS(VirtualFile file) {
|
||||||
|
RomFSHeader header{};
|
||||||
|
if (file->ReadObject(&header) != sizeof(RomFSHeader))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (header.header_size != sizeof(RomFSHeader))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const u64 file_offset = header.file_meta.offset;
|
||||||
|
const u64 dir_offset = header.directory_meta.offset + 4;
|
||||||
|
|
||||||
|
const auto root =
|
||||||
|
std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, std::vector<VirtualDir>{},
|
||||||
|
file->GetContainingDirectory(), file->GetName());
|
||||||
|
|
||||||
|
ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root);
|
||||||
|
|
||||||
|
VirtualDir out = std::move(root);
|
||||||
|
|
||||||
|
while (out->GetSubdirectory("") != nullptr)
|
||||||
|
out = out->GetSubdirectory("");
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
} // namespace FileSys
|
35
src/core/file_sys/romfs.h
Normal file
35
src/core/file_sys/romfs.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/swap.h"
|
||||||
|
#include "core/file_sys/vfs.h"
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
|
||||||
|
struct IVFCLevel {
|
||||||
|
u64_le offset;
|
||||||
|
u64_le size;
|
||||||
|
u32_le block_size;
|
||||||
|
u32_le reserved;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size.");
|
||||||
|
|
||||||
|
struct IVFCHeader {
|
||||||
|
u32_le magic;
|
||||||
|
u32_le magic_number;
|
||||||
|
INSERT_PADDING_BYTES(8);
|
||||||
|
std::array<IVFCLevel, 6> levels;
|
||||||
|
INSERT_PADDING_BYTES(64);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size.");
|
||||||
|
|
||||||
|
// Converts a RomFS binary blob to VFS Filesystem
|
||||||
|
// Returns nullptr on failure
|
||||||
|
VirtualDir ExtractRomFS(VirtualFile file);
|
||||||
|
|
||||||
|
} // namespace FileSys
|
|
@ -46,6 +46,13 @@ size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) {
|
||||||
return Write(data.data(), data.size(), offset);
|
return Write(data.data(), data.size(), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string VfsFile::GetFullPath() const {
|
||||||
|
if (GetContainingDirectory() == nullptr)
|
||||||
|
return "/" + GetName();
|
||||||
|
|
||||||
|
return GetContainingDirectory()->GetFullPath() + "/" + GetName();
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
|
std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
|
||||||
auto vec = FileUtil::SplitPathComponents(path);
|
auto vec = FileUtil::SplitPathComponents(path);
|
||||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||||
|
@ -243,6 +250,13 @@ bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
|
||||||
return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
|
return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string VfsDirectory::GetFullPath() const {
|
||||||
|
if (IsRoot())
|
||||||
|
return GetName();
|
||||||
|
|
||||||
|
return GetParentDirectory()->GetFullPath() + "/" + GetName();
|
||||||
|
}
|
||||||
|
|
||||||
bool ReadOnlyVfsDirectory::IsWritable() const {
|
bool ReadOnlyVfsDirectory::IsWritable() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -270,4 +284,13 @@ bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
|
||||||
bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
|
bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VfsRawCopy(VirtualFile src, VirtualFile dest) {
|
||||||
|
if (src == nullptr || dest == nullptr)
|
||||||
|
return false;
|
||||||
|
if (!dest->Resize(src->GetSize()))
|
||||||
|
return false;
|
||||||
|
std::vector<u8> data = src->ReadAllBytes();
|
||||||
|
return dest->WriteBytes(data, 0) == data.size();
|
||||||
|
}
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -113,6 +113,9 @@ struct VfsFile : NonCopyable {
|
||||||
|
|
||||||
// Renames the file to name. Returns whether or not the operation was successsful.
|
// Renames the file to name. Returns whether or not the operation was successsful.
|
||||||
virtual bool Rename(std::string_view name) = 0;
|
virtual bool Rename(std::string_view name) = 0;
|
||||||
|
|
||||||
|
// Returns the full path of this file as a string, recursively
|
||||||
|
virtual std::string GetFullPath() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A class representing a directory in an abstract filesystem.
|
// A class representing a directory in an abstract filesystem.
|
||||||
|
@ -213,6 +216,17 @@ struct VfsDirectory : NonCopyable {
|
||||||
return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p));
|
return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InterpretAsDirectory(const std::function<VirtualDir(VirtualFile)>& function,
|
||||||
|
const std::string& file) {
|
||||||
|
auto file_p = GetFile(file);
|
||||||
|
if (file_p == nullptr)
|
||||||
|
return false;
|
||||||
|
return ReplaceFileWithSubdirectory(file_p, function(file_p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the full path of this directory as a string, recursively
|
||||||
|
virtual std::string GetFullPath() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Backend for InterpretAsDirectory.
|
// Backend for InterpretAsDirectory.
|
||||||
// Removes all references to file and adds a reference to dir in the directory's implementation.
|
// Removes all references to file and adds a reference to dir in the directory's implementation.
|
||||||
|
@ -230,4 +244,10 @@ struct ReadOnlyVfsDirectory : public VfsDirectory {
|
||||||
bool DeleteFile(std::string_view name) override;
|
bool DeleteFile(std::string_view name) override;
|
||||||
bool Rename(std::string_view name) override;
|
bool Rename(std::string_view name) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A method that copies the raw data between two different implementations of VirtualFile. If you
|
||||||
|
// are using the same implementation, it is probably better to use the Copy method in the parent
|
||||||
|
// directory of src/dest.
|
||||||
|
bool VfsRawCopy(VirtualFile src, VirtualFile dest);
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_,
|
OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_,
|
||||||
std::string name_)
|
std::string name_, VirtualDir parent_)
|
||||||
: file(std::move(file_)), offset(offset_), size(size_), name(std::move(name_)) {}
|
: file(file_), offset(offset_), size(size_), name(std::move(name_)),
|
||||||
|
parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
|
||||||
|
|
||||||
std::string OffsetVfsFile::GetName() const {
|
std::string OffsetVfsFile::GetName() const {
|
||||||
return name.empty() ? file->GetName() : name;
|
return name.empty() ? file->GetName() : name;
|
||||||
|
@ -35,7 +36,7 @@ bool OffsetVfsFile::Resize(size_t new_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const {
|
std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const {
|
||||||
return file->GetContainingDirectory();
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OffsetVfsFile::IsWritable() const {
|
bool OffsetVfsFile::IsWritable() const {
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace FileSys {
|
||||||
// the size of this wrapper.
|
// the size of this wrapper.
|
||||||
struct OffsetVfsFile : public VfsFile {
|
struct OffsetVfsFile : public VfsFile {
|
||||||
OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0,
|
OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0,
|
||||||
std::string new_name = "");
|
std::string new_name = "", VirtualDir new_parent = nullptr);
|
||||||
|
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
size_t GetSize() const override;
|
size_t GetSize() const override;
|
||||||
|
@ -44,6 +44,7 @@ private:
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
VirtualDir parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -195,6 +195,12 @@ bool RealVfsDirectory::Rename(std::string_view name) {
|
||||||
return FileUtil::Rename(path, new_name);
|
return FileUtil::Rename(path, new_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RealVfsDirectory::GetFullPath() const {
|
||||||
|
auto out = path;
|
||||||
|
std::replace(out.begin(), out.end(), '\\', '/');
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
|
bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
|
||||||
const auto iter = std::find(files.begin(), files.end(), file);
|
const auto iter = std::find(files.begin(), files.end(), file);
|
||||||
if (iter == files.end())
|
if (iter == files.end())
|
||||||
|
|
|
@ -41,7 +41,7 @@ private:
|
||||||
|
|
||||||
// An implementation of VfsDirectory that represents a directory on the user's computer.
|
// An implementation of VfsDirectory that represents a directory on the user's computer.
|
||||||
struct RealVfsDirectory : public VfsDirectory {
|
struct RealVfsDirectory : public VfsDirectory {
|
||||||
RealVfsDirectory(const std::string& path, Mode perms);
|
RealVfsDirectory(const std::string& path, Mode perms = Mode::Read);
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
||||||
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
||||||
|
@ -54,6 +54,7 @@ struct RealVfsDirectory : public VfsDirectory {
|
||||||
bool DeleteSubdirectory(std::string_view name) override;
|
bool DeleteSubdirectory(std::string_view name) override;
|
||||||
bool DeleteFile(std::string_view name) override;
|
bool DeleteFile(std::string_view name) override;
|
||||||
bool Rename(std::string_view name) override;
|
bool Rename(std::string_view name) override;
|
||||||
|
std::string GetFullPath() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
|
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
|
||||||
|
|
83
src/core/file_sys/vfs_vector.cpp
Normal file
83
src/core/file_sys/vfs_vector.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include "core/file_sys/vfs_vector.h"
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
|
||||||
|
std::vector<VirtualDir> dirs_, VirtualDir parent_,
|
||||||
|
std::string name_)
|
||||||
|
: files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)),
|
||||||
|
name(std::move(name_)) {}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<VfsDirectory>> VectorVfsDirectory::GetSubdirectories() const {
|
||||||
|
return dirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VectorVfsDirectory::IsWritable() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VectorVfsDirectory::IsReadable() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string VectorVfsDirectory::GetName() const {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
std::shared_ptr<VfsDirectory> VectorVfsDirectory::GetParentDirectory() const {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view name) {
|
||||||
|
auto iter = std::find_if(vec.begin(), vec.end(), [name](T e) { return e->GetName() == name; });
|
||||||
|
if (iter == vec.end())
|
||||||
|
return false;
|
||||||
|
auto old_size = vec.size();
|
||||||
|
vec.erase(iter);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VectorVfsDirectory::DeleteSubdirectory(std::string_view name) {
|
||||||
|
return FindAndRemoveVectorElement(dirs, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VectorVfsDirectory::DeleteFile(std::string_view name) {
|
||||||
|
return FindAndRemoveVectorElement(files, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VectorVfsDirectory::Rename(std::string_view name_) {
|
||||||
|
name = name_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VfsDirectory> VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VfsFile> VectorVfsDirectory::CreateFile(std::string_view name) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VectorVfsDirectory::AddFile(VirtualFile file) {
|
||||||
|
files.push_back(std::move(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VectorVfsDirectory::AddDirectory(VirtualDir dir) {
|
||||||
|
dirs.push_back(std::move(dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VectorVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
|
||||||
|
if (!DeleteFile(file->GetName()))
|
||||||
|
return false;
|
||||||
|
dirs.emplace_back(dir);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace FileSys
|
44
src/core/file_sys/vfs_vector.h
Normal file
44
src/core/file_sys/vfs_vector.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/file_sys/vfs.h"
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
|
||||||
|
// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
|
||||||
|
// Vector data is supplied upon construction.
|
||||||
|
struct VectorVfsDirectory : public VfsDirectory {
|
||||||
|
explicit VectorVfsDirectory(std::vector<VirtualFile> files = {},
|
||||||
|
std::vector<VirtualDir> dirs = {}, VirtualDir parent = nullptr,
|
||||||
|
std::string name = "");
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
||||||
|
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
||||||
|
bool IsWritable() const override;
|
||||||
|
bool IsReadable() const override;
|
||||||
|
std::string GetName() const override;
|
||||||
|
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
|
||||||
|
bool DeleteSubdirectory(std::string_view name) override;
|
||||||
|
bool DeleteFile(std::string_view name) override;
|
||||||
|
bool Rename(std::string_view name) override;
|
||||||
|
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
|
||||||
|
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
|
||||||
|
|
||||||
|
virtual void AddFile(VirtualFile file);
|
||||||
|
virtual void AddDirectory(VirtualDir dir);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<VirtualFile> files;
|
||||||
|
std::vector<VirtualDir> dirs;
|
||||||
|
|
||||||
|
VirtualDir parent;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace FileSys
|
Loading…
Reference in a new issue