From c03795300a2d9fa4539fb840dca5b2579984bc7f Mon Sep 17 00:00:00 2001 From: shinyquagsire23 Date: Mon, 16 Apr 2018 04:29:15 -0600 Subject: [PATCH 1/3] file_sys: Add HFS/PFS helper component --- src/core/CMakeLists.txt | 2 + src/core/file_sys/partition_filesystem.cpp | 124 +++++++++++++++++++++ src/core/file_sys/partition_filesystem.h | 87 +++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 src/core/file_sys/partition_filesystem.cpp create mode 100644 src/core/file_sys/partition_filesystem.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9877b83fe5..c1a645460c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -12,6 +12,8 @@ add_library(core STATIC file_sys/errors.h file_sys/filesystem.cpp file_sys/filesystem.h + file_sys/partition_filesystem.cpp + file_sys/partition_filesystem.h file_sys/path_parser.cpp file_sys/path_parser.h file_sys/program_metadata.cpp diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp new file mode 100644 index 0000000000..f344e7970d --- /dev/null +++ b/src/core/file_sys/partition_filesystem.cpp @@ -0,0 +1,124 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/file_util.h" +#include "common/logging/log.h" +#include "core/file_sys/partition_filesystem.h" +#include "core/loader/loader.h" + +namespace FileSys { + +Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, size_t offset) { + FileUtil::IOFile file(file_path, "rb"); + if (!file.IsOpen()) + return Loader::ResultStatus::Error; + + // At least be as large as the header + if (file.GetSize() < sizeof(Header)) + return Loader::ResultStatus::Error; + + // For cartridges, HFSs can get very large, so we need to calculate the size up to + // the actual content itself instead of just blindly reading in the entire file. + Header pfs_header; + if (!file.ReadBytes(&pfs_header, sizeof(Header))) + return Loader::ResultStatus::Error; + + bool is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0); + size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); + size_t metadata_size = + sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size; + + // Actually read in now... + file.Seek(offset, SEEK_SET); + std::vector file_data(metadata_size); + + if (!file.ReadBytes(file_data.data(), metadata_size)) + return Loader::ResultStatus::Error; + + Loader::ResultStatus result = Load(file_data); + if (result != Loader::ResultStatus::Success) + LOG_ERROR(Service_FS, "Failed to load PFS from file %s!", file_path.c_str()); + + return result; +} + +Loader::ResultStatus PartitionFilesystem::Load(const std::vector file_data, size_t offset) { + size_t total_size = static_cast(file_data.size() - offset); + if (total_size < sizeof(Header)) + return Loader::ResultStatus::Error; + + memcpy(&pfs_header, &file_data[offset], sizeof(Header)); + is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0); + + size_t entries_offset = offset + sizeof(Header); + size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); + size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size); + for (u16 i = 0; i < pfs_header.num_entries; i++) { + FileEntry entry; + + memcpy(&entry.fs_entry, &file_data[entries_offset + (i * entry_size)], sizeof(FSEntry)); + entry.name = std::string(reinterpret_cast( + &file_data[strtab_offset + entry.fs_entry.strtab_offset])); + pfs_entries.push_back(entry); + } + + content_offset = strtab_offset + pfs_header.strtab_size; + + return Loader::ResultStatus::Success; +} + +u32 PartitionFilesystem::GetNumEntries(void) const { + return pfs_header.num_entries; +} + +u64 PartitionFilesystem::GetEntryOffset(int index) const { + if (index > GetNumEntries()) + return 0; + + return content_offset + pfs_entries[index].fs_entry.offset; +} + +u64 PartitionFilesystem::GetEntrySize(int index) const { + if (index > GetNumEntries()) + return 0; + + return pfs_entries[index].fs_entry.size; +} + +std::string PartitionFilesystem::GetEntryName(int index) const { + if (index > GetNumEntries()) + return ""; + + return pfs_entries[index].name; +} + +u64 PartitionFilesystem::GetFileOffset(const std::string& name) const { + for (u32 i = 0; i < pfs_header.num_entries; i++) { + if (pfs_entries[i].name == name) + return content_offset + pfs_entries[i].fs_entry.offset; + } + + return 0; +} + +u64 PartitionFilesystem::GetFileSize(const std::string& name) const { + for (u32 i = 0; i < pfs_header.num_entries; i++) { + if (pfs_entries[i].name == name) + return pfs_entries[i].fs_entry.size; + } + + return 0; +} + +void PartitionFilesystem::Print() const { + LOG_DEBUG(Service_FS, "Magic: %.4s", pfs_header.magic.data()); + LOG_DEBUG(Service_FS, "Files: %u", pfs_header.num_entries); + for (u32 i = 0; i < pfs_header.num_entries; i++) { + LOG_DEBUG(Service_FS, " > File %u: %s (0x%" PRIX64 " bytes, at 0x%" PRIX64 ")", + i, pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size, + GetFileOffset(pfs_entries[i].name)); + } +} +} // namespace FileSys diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h new file mode 100644 index 0000000000..4cc534f50c --- /dev/null +++ b/src/core/file_sys/partition_filesystem.h @@ -0,0 +1,87 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" + +namespace Loader { +enum class ResultStatus; +} + +namespace FileSys { + +/** + * Helper which implements an interface to parse PFS/HFS filesystems. + * Data can either be loaded from a file path or data with an offset into it. + */ +class PartitionFilesystem { +public: + Loader::ResultStatus Load(const std::string& file_path, size_t offset = 0); + Loader::ResultStatus Load(const std::vector file_data, size_t offset = 0); + + u32 GetNumEntries(void) const; + u64 GetEntryOffset(int index) const; + u64 GetEntrySize(int index) const; + std::string GetEntryName(int index) const; + u64 GetFileOffset(const std::string& name) const; + u64 GetFileSize(const std::string& name) const; + + void Print() const; + +private: + struct Header { + std::array magic; + u32_le num_entries; + u32_le strtab_size; + INSERT_PADDING_BYTES(0x4); + }; + + static_assert(sizeof(Header) == 0x10, "PFS/HFS header structure size is wrong"); + +#pragma pack(push, 1) + struct FSEntry { + u64_le offset; + u64_le size; + u32_le strtab_offset; + }; + + static_assert(sizeof(FSEntry) == 0x14, "FS entry structure size is wrong"); + + struct PFSEntry { + FSEntry fs_entry; + INSERT_PADDING_BYTES(0x4); + }; + + static_assert(sizeof(PFSEntry) == 0x18, "PFS entry structure size is wrong"); + + struct HFSEntry { + FSEntry fs_entry; + u32_le hash_region_size; + INSERT_PADDING_BYTES(0x8); + std::array hash; + }; + + static_assert(sizeof(HFSEntry) == 0x40, "HFS entry structure size is wrong"); + +#pragma pack(pop) + + struct FileEntry { + FSEntry fs_entry; + std::string name; + }; + + Header pfs_header; + bool is_hfs; + size_t content_offset; + + std::vector pfs_entries; +}; + +} // namespace FileSys From 83aa38b2390ac4af1757d03d3549d73e26dbfa10 Mon Sep 17 00:00:00 2001 From: shinyquagsire23 Date: Mon, 16 Apr 2018 06:51:59 -0600 Subject: [PATCH 2/3] file_sys: tweaks --- src/core/file_sys/partition_filesystem.cpp | 9 +++++---- src/core/file_sys/partition_filesystem.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index f344e7970d..12ba5f3158 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "common/file_util.h" #include "common/logging/log.h" #include "core/file_sys/partition_filesystem.h" @@ -44,8 +45,8 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, siz return result; } -Loader::ResultStatus PartitionFilesystem::Load(const std::vector file_data, size_t offset) { - size_t total_size = static_cast(file_data.size() - offset); +Loader::ResultStatus PartitionFilesystem::Load(const std::vector& file_data, size_t offset) { + size_t total_size = file_data.size() - offset; if (total_size < sizeof(Header)) return Loader::ResultStatus::Error; @@ -61,7 +62,7 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::vector file_data, memcpy(&entry.fs_entry, &file_data[entries_offset + (i * entry_size)], sizeof(FSEntry)); entry.name = std::string(reinterpret_cast( &file_data[strtab_offset + entry.fs_entry.strtab_offset])); - pfs_entries.push_back(entry); + pfs_entries.push_back(std::move(entry)); } content_offset = strtab_offset + pfs_header.strtab_size; @@ -69,7 +70,7 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::vector file_data, return Loader::ResultStatus::Success; } -u32 PartitionFilesystem::GetNumEntries(void) const { +u32 PartitionFilesystem::GetNumEntries() const { return pfs_header.num_entries; } diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h index 4cc534f50c..573c90057f 100644 --- a/src/core/file_sys/partition_filesystem.h +++ b/src/core/file_sys/partition_filesystem.h @@ -24,9 +24,9 @@ namespace FileSys { class PartitionFilesystem { public: Loader::ResultStatus Load(const std::string& file_path, size_t offset = 0); - Loader::ResultStatus Load(const std::vector file_data, size_t offset = 0); + Loader::ResultStatus Load(const std::vector& file_data, size_t offset = 0); - u32 GetNumEntries(void) const; + u32 GetNumEntries() const; u64 GetEntryOffset(int index) const; u64 GetEntrySize(int index) const; std::string GetEntryName(int index) const; From de580ccdd50f349b82f2aa81f7b63cd1f0bafb00 Mon Sep 17 00:00:00 2001 From: shinyquagsire23 Date: Tue, 17 Apr 2018 09:47:11 -0600 Subject: [PATCH 3/3] file_sys: Use NGLOG --- src/core/file_sys/partition_filesystem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 12ba5f3158..4a58a92916 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -114,12 +114,12 @@ u64 PartitionFilesystem::GetFileSize(const std::string& name) const { } void PartitionFilesystem::Print() const { - LOG_DEBUG(Service_FS, "Magic: %.4s", pfs_header.magic.data()); - LOG_DEBUG(Service_FS, "Files: %u", pfs_header.num_entries); + NGLOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic.data()); + NGLOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); for (u32 i = 0; i < pfs_header.num_entries; i++) { - LOG_DEBUG(Service_FS, " > File %u: %s (0x%" PRIX64 " bytes, at 0x%" PRIX64 ")", - i, pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size, - GetFileOffset(pfs_entries[i].name)); + NGLOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, + pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size, + GetFileOffset(pfs_entries[i].name)); } } } // namespace FileSys