mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +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 New Issue
	
	Block a user