summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-01-19 22:18:01 -0500
committerGravatar bunnei2018-01-21 15:39:23 -0500
commit1c06c918af30e4f431920c6197128524b2caee14 (patch)
treebaf2150ffeef402b8ba59e71096b96326b69d556 /src
parentarchive_backend: Minor changes to match Switch IFileSystem. (diff)
downloadyuzu-1c06c918af30e4f431920c6197128524b2caee14.tar.gz
yuzu-1c06c918af30e4f431920c6197128524b2caee14.tar.xz
yuzu-1c06c918af30e4f431920c6197128524b2caee14.zip
file_sys: Remove disk_archive, savedata_archive, and title_metadata.
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/file_sys/disk_archive.cpp99
-rw-r--r--src/core/file_sys/disk_archive.h68
-rw-r--r--src/core/file_sys/savedata_archive.cpp330
-rw-r--r--src/core/file_sys/savedata_archive.h43
-rw-r--r--src/core/file_sys/title_metadata.cpp163
-rw-r--r--src/core/file_sys/title_metadata.h126
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
9 file_sys/archive_backend.cpp 9 file_sys/archive_backend.cpp
10 file_sys/archive_backend.h 10 file_sys/archive_backend.h
11 file_sys/directory_backend.h 11 file_sys/directory_backend.h
12 file_sys/disk_archive.cpp
13 file_sys/disk_archive.h
14 file_sys/errors.h 12 file_sys/errors.h
15 file_sys/file_backend.h 13 file_sys/file_backend.h
16 file_sys/path_parser.cpp 14 file_sys/path_parser.cpp
17 file_sys/path_parser.h 15 file_sys/path_parser.h
18 file_sys/romfs_archive.cpp 16 file_sys/romfs_archive.cpp
19 file_sys/romfs_archive.h 17 file_sys/romfs_archive.h
20 file_sys/savedata_archive.cpp
21 file_sys/savedata_archive.h
22 file_sys/title_metadata.cpp
23 file_sys/title_metadata.h
24 frontend/emu_window.cpp 18 frontend/emu_window.cpp
25 frontend/emu_window.h 19 frontend/emu_window.h
26 frontend/framebuffer_layout.cpp 20 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <cstdio>
7#include <memory>
8#include "common/common_types.h"
9#include "common/file_util.h"
10#include "common/logging/log.h"
11#include "core/file_sys/disk_archive.h"
12#include "core/file_sys/errors.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
20 if (!mode.read_flag)
21 return ERROR_INVALID_OPEN_FLAGS;
22
23 file->Seek(offset, SEEK_SET);
24 return MakeResult<size_t>(file->ReadBytes(buffer, length));
25}
26
27ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush,
28 const u8* buffer) const {
29 if (!mode.write_flag)
30 return ERROR_INVALID_OPEN_FLAGS;
31
32 file->Seek(offset, SEEK_SET);
33 size_t written = file->WriteBytes(buffer, length);
34 if (flush)
35 file->Flush();
36 return MakeResult<size_t>(written);
37}
38
39u64 DiskFile::GetSize() const {
40 return file->GetSize();
41}
42
43bool DiskFile::SetSize(const u64 size) const {
44 file->Resize(size);
45 file->Flush();
46 return true;
47}
48
49bool DiskFile::Close() const {
50 return file->Close();
51}
52
53////////////////////////////////////////////////////////////////////////////////////////////////////
54
55DiskDirectory::DiskDirectory(const std::string& path) : directory() {
56 unsigned size = FileUtil::ScanDirectoryTree(path, directory);
57 directory.size = size;
58 directory.isDirectory = true;
59 children_iterator = directory.children.begin();
60}
61
62u32 DiskDirectory::Read(const u32 count, Entry* entries) {
63 u32 entries_read = 0;
64
65 while (entries_read < count && children_iterator != directory.children.cend()) {
66 const FileUtil::FSTEntry& file = *children_iterator;
67 const std::string& filename = file.virtualName;
68 Entry& entry = entries[entries_read];
69
70 LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size,
71 file.isDirectory);
72
73 // TODO(Link Mauve): use a proper conversion to UTF-16.
74 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
75 entry.filename[j] = filename[j];
76 if (!filename[j])
77 break;
78 }
79
80 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
81
82 entry.is_directory = file.isDirectory;
83 entry.is_hidden = (filename[0] == '.');
84 entry.is_read_only = 0;
85 entry.file_size = file.size;
86
87 // We emulate a SD card where the archive bit has never been cleared, as it would be on
88 // most user SD cards.
89 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
90 // file bit.
91 entry.is_archive = !file.isDirectory;
92
93 ++entries_read;
94 ++children_iterator;
95 }
96 return entries_read;
97}
98
99} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <memory>
9#include <string>
10#include <vector>
11#include "common/common_types.h"
12#include "common/file_util.h"
13#include "core/file_sys/archive_backend.h"
14#include "core/file_sys/directory_backend.h"
15#include "core/file_sys/file_backend.h"
16#include "core/hle/result.h"
17
18////////////////////////////////////////////////////////////////////////////////////////////////////
19// FileSys namespace
20
21namespace FileSys {
22
23class DiskFile : public FileBackend {
24public:
25 DiskFile(FileUtil::IOFile&& file_, const Mode& mode_)
26 : file(new FileUtil::IOFile(std::move(file_))) {
27 mode.hex = mode_.hex;
28 }
29
30 ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
31 ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
32 u64 GetSize() const override;
33 bool SetSize(u64 size) const override;
34 bool Close() const override;
35
36 void Flush() const override {
37 file->Flush();
38 }
39
40protected:
41 Mode mode;
42 std::unique_ptr<FileUtil::IOFile> file;
43};
44
45class DiskDirectory : public DirectoryBackend {
46public:
47 DiskDirectory(const std::string& path);
48
49 ~DiskDirectory() override {
50 Close();
51 }
52
53 u32 Read(const u32 count, Entry* entries) override;
54
55 bool Close() const override {
56 return true;
57 }
58
59protected:
60 u32 total_entries_in_directory;
61 FileUtil::FSTEntry directory;
62
63 // We need to remember the last entry we returned, so a subsequent call to Read will continue
64 // from the next one. This iterator will always point to the next unread entry.
65 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
66};
67
68} // 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 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/file_util.h"
6#include "core/file_sys/disk_archive.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/path_parser.h"
9#include "core/file_sys/savedata_archive.h"
10
11////////////////////////////////////////////////////////////////////////////////////////////////////
12// FileSys namespace
13
14namespace FileSys {
15
16ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& path,
17 const Mode& mode) const {
18 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
19
20 const PathParser path_parser(path);
21
22 if (!path_parser.IsValid()) {
23 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
24 return ERROR_INVALID_PATH;
25 }
26
27 if (mode.hex == 0) {
28 LOG_ERROR(Service_FS, "Empty open mode");
29 return ERROR_UNSUPPORTED_OPEN_FLAGS;
30 }
31
32 if (mode.create_flag && !mode.write_flag) {
33 LOG_ERROR(Service_FS, "Create flag set but write flag not set");
34 return ERROR_UNSUPPORTED_OPEN_FLAGS;
35 }
36
37 const auto full_path = path_parser.BuildHostPath(mount_point);
38
39 switch (path_parser.GetHostStatus(mount_point)) {
40 case PathParser::InvalidMountPoint:
41 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
42 return ERROR_FILE_NOT_FOUND;
43 case PathParser::PathNotFound:
44 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
45 return ERROR_PATH_NOT_FOUND;
46 case PathParser::FileInPath:
47 case PathParser::DirectoryFound:
48 LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str());
49 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
50 case PathParser::NotFound:
51 if (!mode.create_flag) {
52 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.",
53 full_path.c_str());
54 return ERROR_FILE_NOT_FOUND;
55 } else {
56 // Create the file
57 FileUtil::CreateEmptyFile(full_path);
58 }
59 break;
60 case PathParser::FileFound:
61 break; // Expected 'success' case
62 }
63
64 FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
65 if (!file.IsOpen()) {
66 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str());
67 return ERROR_FILE_NOT_FOUND;
68 }
69
70 auto disk_file = std::make_unique<DiskFile>(std::move(file), mode);
71 return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file));
72}
73
74ResultCode SaveDataArchive::DeleteFile(const Path& path) const {
75 const PathParser path_parser(path);
76
77 if (!path_parser.IsValid()) {
78 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
79 return ERROR_INVALID_PATH;
80 }
81
82 const auto full_path = path_parser.BuildHostPath(mount_point);
83
84 switch (path_parser.GetHostStatus(mount_point)) {
85 case PathParser::InvalidMountPoint:
86 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
87 return ERROR_FILE_NOT_FOUND;
88 case PathParser::PathNotFound:
89 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
90 return ERROR_PATH_NOT_FOUND;
91 case PathParser::FileInPath:
92 case PathParser::DirectoryFound:
93 case PathParser::NotFound:
94 LOG_ERROR(Service_FS, "File not found %s", full_path.c_str());
95 return ERROR_FILE_NOT_FOUND;
96 case PathParser::FileFound:
97 break; // Expected 'success' case
98 }
99
100 if (FileUtil::Delete(full_path)) {
101 return RESULT_SUCCESS;
102 }
103
104 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str());
105 return ERROR_FILE_NOT_FOUND;
106}
107
108ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
109 const PathParser path_parser_src(src_path);
110
111 // TODO: Verify these return codes with HW
112 if (!path_parser_src.IsValid()) {
113 LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str());
114 return ERROR_INVALID_PATH;
115 }
116
117 const PathParser path_parser_dest(dest_path);
118
119 if (!path_parser_dest.IsValid()) {
120 LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str());
121 return ERROR_INVALID_PATH;
122 }
123
124 const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
125 const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
126
127 if (FileUtil::Rename(src_path_full, dest_path_full)) {
128 return RESULT_SUCCESS;
129 }
130
131 // TODO(bunnei): Use correct error code
132 return ResultCode(-1);
133}
134
135template <typename T>
136static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point,
137 T deleter) {
138 const PathParser path_parser(path);
139
140 if (!path_parser.IsValid()) {
141 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
142 return ERROR_INVALID_PATH;
143 }
144
145 if (path_parser.IsRootDirectory())
146 return ERROR_DIRECTORY_NOT_EMPTY;
147
148 const auto full_path = path_parser.BuildHostPath(mount_point);
149
150 switch (path_parser.GetHostStatus(mount_point)) {
151 case PathParser::InvalidMountPoint:
152 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
153 return ERROR_PATH_NOT_FOUND;
154 case PathParser::PathNotFound:
155 case PathParser::NotFound:
156 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
157 return ERROR_PATH_NOT_FOUND;
158 case PathParser::FileInPath:
159 case PathParser::FileFound:
160 LOG_ERROR(Service_FS, "Unexpected file or directory %s", full_path.c_str());
161 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
162 case PathParser::DirectoryFound:
163 break; // Expected 'success' case
164 }
165
166 if (deleter(full_path)) {
167 return RESULT_SUCCESS;
168 }
169
170 LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str());
171 return ERROR_DIRECTORY_NOT_EMPTY;
172}
173
174ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const {
175 return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
176}
177
178ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const {
179 return DeleteDirectoryHelper(
180 path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
181}
182
183ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const {
184 const PathParser path_parser(path);
185
186 if (!path_parser.IsValid()) {
187 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
188 return ERROR_INVALID_PATH;
189 }
190
191 const auto full_path = path_parser.BuildHostPath(mount_point);
192
193 switch (path_parser.GetHostStatus(mount_point)) {
194 case PathParser::InvalidMountPoint:
195 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
196 return ERROR_FILE_NOT_FOUND;
197 case PathParser::PathNotFound:
198 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
199 return ERROR_PATH_NOT_FOUND;
200 case PathParser::FileInPath:
201 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
202 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
203 case PathParser::DirectoryFound:
204 case PathParser::FileFound:
205 LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
206 return ERROR_FILE_ALREADY_EXISTS;
207 case PathParser::NotFound:
208 break; // Expected 'success' case
209 }
210
211 if (size == 0) {
212 FileUtil::CreateEmptyFile(full_path);
213 return RESULT_SUCCESS;
214 }
215
216 FileUtil::IOFile file(full_path, "wb");
217 // Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
218 // We do this by seeking to the right size, then writing a single null byte.
219 if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
220 return RESULT_SUCCESS;
221 }
222
223 LOG_ERROR(Service_FS, "Too large file");
224
225 // TODO(bunnei): Use correct error code
226 return ResultCode(-1);
227}
228
229ResultCode SaveDataArchive::CreateDirectory(const Path& path) const {
230 const PathParser path_parser(path);
231
232 if (!path_parser.IsValid()) {
233 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
234 return ERROR_INVALID_PATH;
235 }
236
237 const auto full_path = path_parser.BuildHostPath(mount_point);
238
239 switch (path_parser.GetHostStatus(mount_point)) {
240 case PathParser::InvalidMountPoint:
241 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
242 return ERROR_FILE_NOT_FOUND;
243 case PathParser::PathNotFound:
244 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
245 return ERROR_PATH_NOT_FOUND;
246 case PathParser::FileInPath:
247 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
248 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
249 case PathParser::DirectoryFound:
250 case PathParser::FileFound:
251 LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
252 return ERROR_DIRECTORY_ALREADY_EXISTS;
253 case PathParser::NotFound:
254 break; // Expected 'success' case
255 }
256
257 if (FileUtil::CreateDir(mount_point + path.AsString())) {
258 return RESULT_SUCCESS;
259 }
260
261 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str());
262
263 // TODO(bunnei): Use correct error code
264 return ResultCode(-1);
265}
266
267ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
268 const PathParser path_parser_src(src_path);
269
270 // TODO: Verify these return codes with HW
271 if (!path_parser_src.IsValid()) {
272 LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str());
273 return ERROR_INVALID_PATH;
274 }
275
276 const PathParser path_parser_dest(dest_path);
277
278 if (!path_parser_dest.IsValid()) {
279 LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str());
280 return ERROR_INVALID_PATH;
281 }
282
283 const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
284 const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
285
286 if (FileUtil::Rename(src_path_full, dest_path_full)) {
287 return RESULT_SUCCESS;
288 }
289
290 // TODO(bunnei): Use correct error code
291 return ResultCode(-1);
292}
293
294ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
295 const Path& path) const {
296 const PathParser path_parser(path);
297
298 if (!path_parser.IsValid()) {
299 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
300 return ERROR_INVALID_PATH;
301 }
302
303 const auto full_path = path_parser.BuildHostPath(mount_point);
304
305 switch (path_parser.GetHostStatus(mount_point)) {
306 case PathParser::InvalidMountPoint:
307 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
308 return ERROR_FILE_NOT_FOUND;
309 case PathParser::PathNotFound:
310 case PathParser::NotFound:
311 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
312 return ERROR_PATH_NOT_FOUND;
313 case PathParser::FileInPath:
314 case PathParser::FileFound:
315 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
316 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
317 case PathParser::DirectoryFound:
318 break; // Expected 'success' case
319 }
320
321 auto directory = std::make_unique<DiskDirectory>(full_path);
322 return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
323}
324
325u64 SaveDataArchive::GetFreeSpaceSize() const {
326 // TODO: Stubbed to return 1GiB
327 return 1024 * 1024 * 1024;
328}
329
330} // 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 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8#include "core/file_sys/archive_backend.h"
9#include "core/file_sys/directory_backend.h"
10#include "core/file_sys/file_backend.h"
11#include "core/hle/result.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18/// Archive backend for general save data archive type (SaveData and SystemSaveData)
19class SaveDataArchive : public ArchiveBackend {
20public:
21 explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
22
23 std::string GetName() const override {
24 return "SaveDataArchive: " + mount_point;
25 }
26
27 ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
28 const Mode& mode) const override;
29 ResultCode DeleteFile(const Path& path) const override;
30 ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
31 ResultCode DeleteDirectory(const Path& path) const override;
32 ResultCode DeleteDirectoryRecursively(const Path& path) const override;
33 ResultCode CreateFile(const Path& path, u64 size) const override;
34 ResultCode CreateDirectory(const Path& path) const override;
35 ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
36 ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
37 u64 GetFreeSpaceSize() const override;
38
39protected:
40 std::string mount_point;
41};
42
43} // 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 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cinttypes>
6#include "common/alignment.h"
7#include "common/file_util.h"
8#include "common/logging/log.h"
9#include "core/file_sys/title_metadata.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17static u32 GetSignatureSize(u32 signature_type) {
18 switch (signature_type) {
19 case Rsa4096Sha1:
20 case Rsa4096Sha256:
21 return 0x200;
22
23 case Rsa2048Sha1:
24 case Rsa2048Sha256:
25 return 0x100;
26
27 case EllipticSha1:
28 case EcdsaSha256:
29 return 0x3C;
30 }
31}
32
33Loader::ResultStatus TitleMetadata::Load() {
34 FileUtil::IOFile file(filepath, "rb");
35 if (!file.IsOpen())
36 return Loader::ResultStatus::Error;
37
38 if (!file.ReadBytes(&signature_type, sizeof(u32_be)))
39 return Loader::ResultStatus::Error;
40
41 // Signature lengths are variable, and the body follows the signature
42 u32 signature_size = GetSignatureSize(signature_type);
43
44 tmd_signature.resize(signature_size);
45 if (!file.ReadBytes(&tmd_signature[0], signature_size))
46 return Loader::ResultStatus::Error;
47
48 // The TMD body start position is rounded to the nearest 0x40 after the signature
49 size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40);
50 file.Seek(body_start, SEEK_SET);
51
52 // Read our TMD body, then load the amount of ContentChunks specified
53 if (file.ReadBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body))
54 return Loader::ResultStatus::Error;
55
56 for (u16 i = 0; i < tmd_body.content_count; i++) {
57 ContentChunk chunk;
58 if (file.ReadBytes(&chunk, sizeof(ContentChunk)) == sizeof(ContentChunk)) {
59 tmd_chunks.push_back(chunk);
60 } else {
61 LOG_ERROR(Service_FS, "Malformed TMD %s, failed to load content chunk index %u!",
62 filepath.c_str(), i);
63 return Loader::ResultStatus::ErrorInvalidFormat;
64 }
65 }
66
67 return Loader::ResultStatus::Success;
68}
69
70Loader::ResultStatus TitleMetadata::Save() {
71 UNIMPLEMENTED();
72 return Loader::ResultStatus::Success;
73}
74
75u64 TitleMetadata::GetTitleID() const {
76 return tmd_body.title_id;
77}
78
79u32 TitleMetadata::GetTitleType() const {
80 return tmd_body.title_type;
81}
82
83u16 TitleMetadata::GetTitleVersion() const {
84 return tmd_body.title_version;
85}
86
87u64 TitleMetadata::GetSystemVersion() const {
88 return tmd_body.system_version;
89}
90
91size_t TitleMetadata::GetContentCount() const {
92 return tmd_chunks.size();
93}
94
95u32 TitleMetadata::GetBootContentID() const {
96 return tmd_chunks[TMDContentIndex::Main].id;
97}
98
99u32 TitleMetadata::GetManualContentID() const {
100 return tmd_chunks[TMDContentIndex::Manual].id;
101}
102
103u32 TitleMetadata::GetDLPContentID() const {
104 return tmd_chunks[TMDContentIndex::DLP].id;
105}
106
107void TitleMetadata::SetTitleID(u64 title_id) {
108 tmd_body.title_id = title_id;
109}
110
111void TitleMetadata::SetTitleType(u32 type) {
112 tmd_body.title_type = type;
113}
114
115void TitleMetadata::SetTitleVersion(u16 version) {
116 tmd_body.title_version = version;
117}
118
119void TitleMetadata::SetSystemVersion(u64 version) {
120 tmd_body.system_version = version;
121}
122
123void TitleMetadata::AddContentChunk(const ContentChunk& chunk) {
124 tmd_chunks.push_back(chunk);
125}
126
127void TitleMetadata::Print() const {
128 LOG_DEBUG(Service_FS, "%s - %u chunks", filepath.c_str(),
129 static_cast<u32>(tmd_body.content_count));
130
131 // Content info describes ranges of content chunks
132 LOG_DEBUG(Service_FS, "Content info:");
133 for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) {
134 if (tmd_body.contentinfo[i].command_count == 0)
135 break;
136
137 LOG_DEBUG(Service_FS, " Index %04X, Command Count %04X",
138 static_cast<u32>(tmd_body.contentinfo[i].index),
139 static_cast<u32>(tmd_body.contentinfo[i].command_count));
140 }
141
142 // For each content info, print their content chunk range
143 for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) {
144 u16 index = static_cast<u16>(tmd_body.contentinfo[i].index);
145 u16 count = static_cast<u16>(tmd_body.contentinfo[i].command_count);
146
147 if (count == 0)
148 continue;
149
150 LOG_DEBUG(Service_FS, "Content chunks for content info index %zu:", i);
151 for (u16 j = index; j < index + count; j++) {
152 // Don't attempt to print content we don't have
153 if (j > tmd_body.content_count)
154 break;
155
156 const ContentChunk& chunk = tmd_chunks[j];
157 LOG_DEBUG(Service_FS, " ID %08X, Index %04X, Type %04x, Size %016" PRIX64,
158 static_cast<u32>(chunk.id), static_cast<u32>(chunk.index),
159 static_cast<u32>(chunk.type), static_cast<u64>(chunk.size));
160 }
161 }
162}
163} // 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 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <string>
9#include <vector>
10#include "common/common_types.h"
11#include "common/swap.h"
12
13namespace Loader {
14enum class ResultStatus;
15}
16
17////////////////////////////////////////////////////////////////////////////////////////////////////
18// FileSys namespace
19
20namespace FileSys {
21
22enum TMDSignatureType : u32 {
23 Rsa4096Sha1 = 0x10000,
24 Rsa2048Sha1 = 0x10001,
25 EllipticSha1 = 0x10002,
26 Rsa4096Sha256 = 0x10003,
27 Rsa2048Sha256 = 0x10004,
28 EcdsaSha256 = 0x10005
29};
30
31enum TMDContentTypeFlag : u16 {
32 Encrypted = 1 << 1,
33 Disc = 1 << 2,
34 CFM = 1 << 3,
35 Optional = 1 << 14,
36 Shared = 1 << 15
37};
38
39/**
40 * Helper which implements an interface to read and write Title Metadata (TMD) files.
41 * If a file path is provided and the file exists, it can be parsed and used, otherwise
42 * it must be created. The TMD file can then be interpreted, modified and/or saved.
43 */
44class TitleMetadata {
45public:
46 struct ContentChunk {
47 u32_be id;
48 u16_be index;
49 u16_be type;
50 u64_be size;
51 std::array<u8, 0x20> hash;
52 };
53
54 static_assert(sizeof(ContentChunk) == 0x30, "TMD ContentChunk structure size is wrong");
55
56 struct ContentInfo {
57 u16_be index;
58 u16_be command_count;
59 std::array<u8, 0x20> hash;
60 };
61
62 static_assert(sizeof(ContentInfo) == 0x24, "TMD ContentInfo structure size is wrong");
63
64#pragma pack(push, 1)
65
66 struct Body {
67 std::array<u8, 0x40> issuer;
68 u8 version;
69 u8 ca_crl_version;
70 u8 signer_crl_version;
71 u8 reserved;
72 u64_be system_version;
73 u64_be title_id;
74 u32_be title_type;
75 u16_be group_id;
76 u32_be savedata_size;
77 u32_be srl_private_savedata_size;
78 std::array<u8, 4> reserved_2;
79 u8 srl_flag;
80 std::array<u8, 0x31> reserved_3;
81 u32_be access_rights;
82 u16_be title_version;
83 u16_be content_count;
84 u16_be boot_content;
85 std::array<u8, 2> reserved_4;
86 std::array<u8, 0x20> contentinfo_hash;
87 std::array<ContentInfo, 64> contentinfo;
88 };
89
90 static_assert(sizeof(Body) == 0x9C4, "TMD body structure size is wrong");
91
92#pragma pack(pop)
93
94 explicit TitleMetadata(std::string& path) : filepath(std::move(path)) {}
95 Loader::ResultStatus Load();
96 Loader::ResultStatus Save();
97
98 u64 GetTitleID() const;
99 u32 GetTitleType() const;
100 u16 GetTitleVersion() const;
101 u64 GetSystemVersion() const;
102 size_t GetContentCount() const;
103 u32 GetBootContentID() const;
104 u32 GetManualContentID() const;
105 u32 GetDLPContentID() const;
106
107 void SetTitleID(u64 title_id);
108 void SetTitleType(u32 type);
109 void SetTitleVersion(u16 version);
110 void SetSystemVersion(u64 version);
111 void AddContentChunk(const ContentChunk& chunk);
112
113 void Print() const;
114
115private:
116 enum TMDContentIndex { Main = 0, Manual = 1, DLP = 2 };
117
118 Body tmd_body;
119 u32_be signature_type;
120 std::vector<u8> tmd_signature;
121 std::vector<ContentChunk> tmd_chunks;
122
123 std::string filepath;
124};
125
126} // namespace FileSys