diff options
author | bunnei <bunneidev@gmail.com> | 2018-01-20 04:18:01 +0100 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2018-01-21 21:39:23 +0100 |
commit | 1c06c918af30e4f431920c6197128524b2caee14 (patch) | |
tree | baf2150ffeef402b8ba59e71096b96326b69d556 | |
parent | archive_backend: Minor changes to match Switch IFileSystem. (diff) | |
download | yuzu-1c06c918af30e4f431920c6197128524b2caee14.tar yuzu-1c06c918af30e4f431920c6197128524b2caee14.tar.gz yuzu-1c06c918af30e4f431920c6197128524b2caee14.tar.bz2 yuzu-1c06c918af30e4f431920c6197128524b2caee14.tar.lz yuzu-1c06c918af30e4f431920c6197128524b2caee14.tar.xz yuzu-1c06c918af30e4f431920c6197128524b2caee14.tar.zst yuzu-1c06c918af30e4f431920c6197128524b2caee14.zip |
-rw-r--r-- | src/core/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/core/file_sys/disk_archive.cpp | 99 | ||||
-rw-r--r-- | src/core/file_sys/disk_archive.h | 68 | ||||
-rw-r--r-- | src/core/file_sys/savedata_archive.cpp | 330 | ||||
-rw-r--r-- | src/core/file_sys/savedata_archive.h | 43 | ||||
-rw-r--r-- | src/core/file_sys/title_metadata.cpp | 163 | ||||
-rw-r--r-- | src/core/file_sys/title_metadata.h | 126 |
7 files changed, 0 insertions, 835 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ec25ec9cf..b2dcc039a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -9,18 +9,12 @@ add_library(core STATIC file_sys/archive_backend.cpp file_sys/archive_backend.h file_sys/directory_backend.h - file_sys/disk_archive.cpp - file_sys/disk_archive.h file_sys/errors.h file_sys/file_backend.h file_sys/path_parser.cpp file_sys/path_parser.h file_sys/romfs_archive.cpp file_sys/romfs_archive.h - file_sys/savedata_archive.cpp - file_sys/savedata_archive.h - file_sys/title_metadata.cpp - file_sys/title_metadata.h frontend/emu_window.cpp frontend/emu_window.h frontend/framebuffer_layout.cpp diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp deleted file mode 100644 index 98d80aabc..000000000 --- a/src/core/file_sys/disk_archive.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <cstdio> -#include <memory> -#include "common/common_types.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "core/file_sys/disk_archive.h" -#include "core/file_sys/errors.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { - if (!mode.read_flag) - return ERROR_INVALID_OPEN_FLAGS; - - file->Seek(offset, SEEK_SET); - return MakeResult<size_t>(file->ReadBytes(buffer, length)); -} - -ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush, - const u8* buffer) const { - if (!mode.write_flag) - return ERROR_INVALID_OPEN_FLAGS; - - file->Seek(offset, SEEK_SET); - size_t written = file->WriteBytes(buffer, length); - if (flush) - file->Flush(); - return MakeResult<size_t>(written); -} - -u64 DiskFile::GetSize() const { - return file->GetSize(); -} - -bool DiskFile::SetSize(const u64 size) const { - file->Resize(size); - file->Flush(); - return true; -} - -bool DiskFile::Close() const { - return file->Close(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -DiskDirectory::DiskDirectory(const std::string& path) : directory() { - unsigned size = FileUtil::ScanDirectoryTree(path, directory); - directory.size = size; - directory.isDirectory = true; - children_iterator = directory.children.begin(); -} - -u32 DiskDirectory::Read(const u32 count, Entry* entries) { - u32 entries_read = 0; - - while (entries_read < count && children_iterator != directory.children.cend()) { - const FileUtil::FSTEntry& file = *children_iterator; - const std::string& filename = file.virtualName; - Entry& entry = entries[entries_read]; - - LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, - file.isDirectory); - - // TODO(Link Mauve): use a proper conversion to UTF-16. - for (size_t j = 0; j < FILENAME_LENGTH; ++j) { - entry.filename[j] = filename[j]; - if (!filename[j]) - break; - } - - FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); - - entry.is_directory = file.isDirectory; - entry.is_hidden = (filename[0] == '.'); - entry.is_read_only = 0; - entry.file_size = file.size; - - // We emulate a SD card where the archive bit has never been cleared, as it would be on - // most user SD cards. - // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a - // file bit. - entry.is_archive = !file.isDirectory; - - ++entries_read; - ++children_iterator; - } - return entries_read; -} - -} // namespace FileSys diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h deleted file mode 100644 index eb9166df6..000000000 --- a/src/core/file_sys/disk_archive.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <cstddef> -#include <memory> -#include <string> -#include <vector> -#include "common/common_types.h" -#include "common/file_util.h" -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -class DiskFile : public FileBackend { -public: - DiskFile(FileUtil::IOFile&& file_, const Mode& mode_) - : file(new FileUtil::IOFile(std::move(file_))) { - mode.hex = mode_.hex; - } - - ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override; - ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; - u64 GetSize() const override; - bool SetSize(u64 size) const override; - bool Close() const override; - - void Flush() const override { - file->Flush(); - } - -protected: - Mode mode; - std::unique_ptr<FileUtil::IOFile> file; -}; - -class DiskDirectory : public DirectoryBackend { -public: - DiskDirectory(const std::string& path); - - ~DiskDirectory() override { - Close(); - } - - u32 Read(const u32 count, Entry* entries) override; - - bool Close() const override { - return true; - } - -protected: - u32 total_entries_in_directory; - FileUtil::FSTEntry directory; - - // We need to remember the last entry we returned, so a subsequent call to Read will continue - // from the next one. This iterator will always point to the next unread entry. - std::vector<FileUtil::FSTEntry>::iterator children_iterator; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp deleted file mode 100644 index d12739ca7..000000000 --- a/src/core/file_sys/savedata_archive.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/file_util.h" -#include "core/file_sys/disk_archive.h" -#include "core/file_sys/errors.h" -#include "core/file_sys/path_parser.h" -#include "core/file_sys/savedata_archive.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& path, - const Mode& mode) const { - LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); - - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - if (mode.hex == 0) { - LOG_ERROR(Service_FS, "Empty open mode"); - return ERROR_UNSUPPORTED_OPEN_FLAGS; - } - - if (mode.create_flag && !mode.write_flag) { - LOG_ERROR(Service_FS, "Create flag set but write flag not set"); - return ERROR_UNSUPPORTED_OPEN_FLAGS; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::DirectoryFound: - LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::NotFound: - if (!mode.create_flag) { - LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", - full_path.c_str()); - return ERROR_FILE_NOT_FOUND; - } else { - // Create the file - FileUtil::CreateEmptyFile(full_path); - } - break; - case PathParser::FileFound: - break; // Expected 'success' case - } - - FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb"); - if (!file.IsOpen()) { - LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str()); - return ERROR_FILE_NOT_FOUND; - } - - auto disk_file = std::make_unique<DiskFile>(std::move(file), mode); - return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file)); -} - -ResultCode SaveDataArchive::DeleteFile(const Path& path) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::DirectoryFound: - case PathParser::NotFound: - LOG_ERROR(Service_FS, "File not found %s", full_path.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::FileFound: - break; // Expected 'success' case - } - - if (FileUtil::Delete(full_path)) { - return RESULT_SUCCESS; - } - - LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str()); - return ERROR_FILE_NOT_FOUND; -} - -ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const { - const PathParser path_parser_src(src_path); - - // TODO: Verify these return codes with HW - if (!path_parser_src.IsValid()) { - LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const PathParser path_parser_dest(dest_path); - - if (!path_parser_dest.IsValid()) { - LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto src_path_full = path_parser_src.BuildHostPath(mount_point); - const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); - - if (FileUtil::Rename(src_path_full, dest_path_full)) { - return RESULT_SUCCESS; - } - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -template <typename T> -static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point, - T deleter) { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - if (path_parser.IsRootDirectory()) - return ERROR_DIRECTORY_NOT_EMPTY; - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::PathNotFound: - case PathParser::NotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "Unexpected file or directory %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - break; // Expected 'success' case - } - - if (deleter(full_path)) { - return RESULT_SUCCESS; - } - - LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str()); - return ERROR_DIRECTORY_NOT_EMPTY; -} - -ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const { - return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir); -} - -ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const { - return DeleteDirectoryHelper( - path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); }); -} - -ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); - return ERROR_FILE_ALREADY_EXISTS; - case PathParser::NotFound: - break; // Expected 'success' case - } - - if (size == 0) { - FileUtil::CreateEmptyFile(full_path); - return RESULT_SUCCESS; - } - - FileUtil::IOFile file(full_path, "wb"); - // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) - // We do this by seeking to the right size, then writing a single null byte. - if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) { - return RESULT_SUCCESS; - } - - LOG_ERROR(Service_FS, "Too large file"); - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -ResultCode SaveDataArchive::CreateDirectory(const Path& path) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); - return ERROR_DIRECTORY_ALREADY_EXISTS; - case PathParser::NotFound: - break; // Expected 'success' case - } - - if (FileUtil::CreateDir(mount_point + path.AsString())) { - return RESULT_SUCCESS; - } - - LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str()); - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { - const PathParser path_parser_src(src_path); - - // TODO: Verify these return codes with HW - if (!path_parser_src.IsValid()) { - LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const PathParser path_parser_dest(dest_path); - - if (!path_parser_dest.IsValid()) { - LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto src_path_full = path_parser_src.BuildHostPath(mount_point); - const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); - - if (FileUtil::Rename(src_path_full, dest_path_full)) { - return RESULT_SUCCESS; - } - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory( - const Path& path) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - case PathParser::NotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - break; // Expected 'success' case - } - - auto directory = std::make_unique<DiskDirectory>(full_path); - return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory)); -} - -u64 SaveDataArchive::GetFreeSpaceSize() const { - // TODO: Stubbed to return 1GiB - return 1024 * 1024 * 1024; -} - -} // namespace FileSys diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h deleted file mode 100644 index 931dfb17b..000000000 --- a/src/core/file_sys/savedata_archive.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <string> -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -/// Archive backend for general save data archive type (SaveData and SystemSaveData) -class SaveDataArchive : public ArchiveBackend { -public: - explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {} - - std::string GetName() const override { - return "SaveDataArchive: " + mount_point; - } - - ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, - const Mode& mode) const override; - ResultCode DeleteFile(const Path& path) const override; - ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; - ResultCode DeleteDirectory(const Path& path) const override; - ResultCode DeleteDirectoryRecursively(const Path& path) const override; - ResultCode CreateFile(const Path& path, u64 size) const override; - ResultCode CreateDirectory(const Path& path) const override; - ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; - ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; - u64 GetFreeSpaceSize() const override; - -protected: - std::string mount_point; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/title_metadata.cpp b/src/core/file_sys/title_metadata.cpp deleted file mode 100644 index e29ba6064..000000000 --- a/src/core/file_sys/title_metadata.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <cinttypes> -#include "common/alignment.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "core/file_sys/title_metadata.h" -#include "core/loader/loader.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -static u32 GetSignatureSize(u32 signature_type) { - switch (signature_type) { - case Rsa4096Sha1: - case Rsa4096Sha256: - return 0x200; - - case Rsa2048Sha1: - case Rsa2048Sha256: - return 0x100; - - case EllipticSha1: - case EcdsaSha256: - return 0x3C; - } -} - -Loader::ResultStatus TitleMetadata::Load() { - FileUtil::IOFile file(filepath, "rb"); - if (!file.IsOpen()) - return Loader::ResultStatus::Error; - - if (!file.ReadBytes(&signature_type, sizeof(u32_be))) - return Loader::ResultStatus::Error; - - // Signature lengths are variable, and the body follows the signature - u32 signature_size = GetSignatureSize(signature_type); - - tmd_signature.resize(signature_size); - if (!file.ReadBytes(&tmd_signature[0], signature_size)) - return Loader::ResultStatus::Error; - - // The TMD body start position is rounded to the nearest 0x40 after the signature - size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40); - file.Seek(body_start, SEEK_SET); - - // Read our TMD body, then load the amount of ContentChunks specified - if (file.ReadBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body)) - return Loader::ResultStatus::Error; - - for (u16 i = 0; i < tmd_body.content_count; i++) { - ContentChunk chunk; - if (file.ReadBytes(&chunk, sizeof(ContentChunk)) == sizeof(ContentChunk)) { - tmd_chunks.push_back(chunk); - } else { - LOG_ERROR(Service_FS, "Malformed TMD %s, failed to load content chunk index %u!", - filepath.c_str(), i); - return Loader::ResultStatus::ErrorInvalidFormat; - } - } - - return Loader::ResultStatus::Success; -} - -Loader::ResultStatus TitleMetadata::Save() { - UNIMPLEMENTED(); - return Loader::ResultStatus::Success; -} - -u64 TitleMetadata::GetTitleID() const { - return tmd_body.title_id; -} - -u32 TitleMetadata::GetTitleType() const { - return tmd_body.title_type; -} - -u16 TitleMetadata::GetTitleVersion() const { - return tmd_body.title_version; -} - -u64 TitleMetadata::GetSystemVersion() const { - return tmd_body.system_version; -} - -size_t TitleMetadata::GetContentCount() const { - return tmd_chunks.size(); -} - -u32 TitleMetadata::GetBootContentID() const { - return tmd_chunks[TMDContentIndex::Main].id; -} - -u32 TitleMetadata::GetManualContentID() const { - return tmd_chunks[TMDContentIndex::Manual].id; -} - -u32 TitleMetadata::GetDLPContentID() const { - return tmd_chunks[TMDContentIndex::DLP].id; -} - -void TitleMetadata::SetTitleID(u64 title_id) { - tmd_body.title_id = title_id; -} - -void TitleMetadata::SetTitleType(u32 type) { - tmd_body.title_type = type; -} - -void TitleMetadata::SetTitleVersion(u16 version) { - tmd_body.title_version = version; -} - -void TitleMetadata::SetSystemVersion(u64 version) { - tmd_body.system_version = version; -} - -void TitleMetadata::AddContentChunk(const ContentChunk& chunk) { - tmd_chunks.push_back(chunk); -} - -void TitleMetadata::Print() const { - LOG_DEBUG(Service_FS, "%s - %u chunks", filepath.c_str(), - static_cast<u32>(tmd_body.content_count)); - - // Content info describes ranges of content chunks - LOG_DEBUG(Service_FS, "Content info:"); - for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) { - if (tmd_body.contentinfo[i].command_count == 0) - break; - - LOG_DEBUG(Service_FS, " Index %04X, Command Count %04X", - static_cast<u32>(tmd_body.contentinfo[i].index), - static_cast<u32>(tmd_body.contentinfo[i].command_count)); - } - - // For each content info, print their content chunk range - for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) { - u16 index = static_cast<u16>(tmd_body.contentinfo[i].index); - u16 count = static_cast<u16>(tmd_body.contentinfo[i].command_count); - - if (count == 0) - continue; - - LOG_DEBUG(Service_FS, "Content chunks for content info index %zu:", i); - for (u16 j = index; j < index + count; j++) { - // Don't attempt to print content we don't have - if (j > tmd_body.content_count) - break; - - const ContentChunk& chunk = tmd_chunks[j]; - LOG_DEBUG(Service_FS, " ID %08X, Index %04X, Type %04x, Size %016" PRIX64, - static_cast<u32>(chunk.id), static_cast<u32>(chunk.index), - static_cast<u32>(chunk.type), static_cast<u64>(chunk.size)); - } - } -} -} // namespace FileSys diff --git a/src/core/file_sys/title_metadata.h b/src/core/file_sys/title_metadata.h deleted file mode 100644 index a4c7d1089..000000000 --- a/src/core/file_sys/title_metadata.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <string> -#include <vector> -#include "common/common_types.h" -#include "common/swap.h" - -namespace Loader { -enum class ResultStatus; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -enum TMDSignatureType : u32 { - Rsa4096Sha1 = 0x10000, - Rsa2048Sha1 = 0x10001, - EllipticSha1 = 0x10002, - Rsa4096Sha256 = 0x10003, - Rsa2048Sha256 = 0x10004, - EcdsaSha256 = 0x10005 -}; - -enum TMDContentTypeFlag : u16 { - Encrypted = 1 << 1, - Disc = 1 << 2, - CFM = 1 << 3, - Optional = 1 << 14, - Shared = 1 << 15 -}; - -/** - * Helper which implements an interface to read and write Title Metadata (TMD) files. - * If a file path is provided and the file exists, it can be parsed and used, otherwise - * it must be created. The TMD file can then be interpreted, modified and/or saved. - */ -class TitleMetadata { -public: - struct ContentChunk { - u32_be id; - u16_be index; - u16_be type; - u64_be size; - std::array<u8, 0x20> hash; - }; - - static_assert(sizeof(ContentChunk) == 0x30, "TMD ContentChunk structure size is wrong"); - - struct ContentInfo { - u16_be index; - u16_be command_count; - std::array<u8, 0x20> hash; - }; - - static_assert(sizeof(ContentInfo) == 0x24, "TMD ContentInfo structure size is wrong"); - -#pragma pack(push, 1) - - struct Body { - std::array<u8, 0x40> issuer; - u8 version; - u8 ca_crl_version; - u8 signer_crl_version; - u8 reserved; - u64_be system_version; - u64_be title_id; - u32_be title_type; - u16_be group_id; - u32_be savedata_size; - u32_be srl_private_savedata_size; - std::array<u8, 4> reserved_2; - u8 srl_flag; - std::array<u8, 0x31> reserved_3; - u32_be access_rights; - u16_be title_version; - u16_be content_count; - u16_be boot_content; - std::array<u8, 2> reserved_4; - std::array<u8, 0x20> contentinfo_hash; - std::array<ContentInfo, 64> contentinfo; - }; - - static_assert(sizeof(Body) == 0x9C4, "TMD body structure size is wrong"); - -#pragma pack(pop) - - explicit TitleMetadata(std::string& path) : filepath(std::move(path)) {} - Loader::ResultStatus Load(); - Loader::ResultStatus Save(); - - u64 GetTitleID() const; - u32 GetTitleType() const; - u16 GetTitleVersion() const; - u64 GetSystemVersion() const; - size_t GetContentCount() const; - u32 GetBootContentID() const; - u32 GetManualContentID() const; - u32 GetDLPContentID() const; - - void SetTitleID(u64 title_id); - void SetTitleType(u32 type); - void SetTitleVersion(u16 version); - void SetSystemVersion(u64 version); - void AddContentChunk(const ContentChunk& chunk); - - void Print() const; - -private: - enum TMDContentIndex { Main = 0, Manual = 1, DLP = 2 }; - - Body tmd_body; - u32_be signature_type; - std::vector<u8> tmd_signature; - std::vector<ContentChunk> tmd_chunks; - - std::string filepath; -}; - -} // namespace FileSys |