summaryrefslogtreecommitdiff
path: root/src/frontend_common/content_manager.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend_common/content_manager.h')
-rw-r--r--src/frontend_common/content_manager.h168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h
new file mode 100644
index 000000000..8e55f4ca0
--- /dev/null
+++ b/src/frontend_common/content_manager.h
@@ -0,0 +1,168 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <boost/algorithm/string.hpp>
7#include "common/common_types.h"
8#include "common/literals.h"
9#include "core/core.h"
10#include "core/file_sys/common_funcs.h"
11#include "core/file_sys/content_archive.h"
12#include "core/file_sys/mode.h"
13#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/registered_cache.h"
15#include "core/file_sys/submission_package.h"
16#include "core/hle/service/filesystem/filesystem.h"
17#include "core/loader/loader.h"
18
19namespace ContentManager {
20
21enum class InstallResult {
22 Success,
23 Overwrite,
24 Failure,
25 BaseInstallAttempted,
26};
27
28inline bool RemoveDLC(const Service::FileSystem::FileSystemController& fs_controller,
29 const u64 title_id) {
30 return fs_controller.GetUserNANDContents()->RemoveExistingEntry(title_id) ||
31 fs_controller.GetSDMCContents()->RemoveExistingEntry(title_id);
32}
33
34inline size_t RemoveAllDLC(Core::System* system, const u64 program_id) {
35 size_t count{};
36 const auto& fs_controller = system->GetFileSystemController();
37 const auto dlc_entries = system->GetContentProvider().ListEntriesFilter(
38 FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
39 std::vector<u64> program_dlc_entries;
40
41 for (const auto& entry : dlc_entries) {
42 if (FileSys::GetBaseTitleID(entry.title_id) == program_id) {
43 program_dlc_entries.push_back(entry.title_id);
44 }
45 }
46
47 for (const auto& entry : program_dlc_entries) {
48 if (RemoveDLC(fs_controller, entry)) {
49 ++count;
50 }
51 }
52 return count;
53}
54
55inline bool RemoveUpdate(const Service::FileSystem::FileSystemController& fs_controller,
56 const u64 program_id) {
57 const auto update_id = program_id | 0x800;
58 return fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
59 fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id);
60}
61
62inline bool RemoveBaseContent(const Service::FileSystem::FileSystemController& fs_controller,
63 const u64 program_id) {
64 return fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) ||
65 fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id);
66}
67
68inline InstallResult InstallNSP(
69 Core::System* system, FileSys::VfsFilesystem* vfs, const std::string& filename,
70 const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) {
71 const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
72 std::size_t block_size) {
73 if (src == nullptr || dest == nullptr) {
74 return false;
75 }
76 if (!dest->Resize(src->GetSize())) {
77 return false;
78 }
79
80 using namespace Common::Literals;
81 std::vector<u8> buffer(1_MiB);
82
83 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
84 if (callback(src->GetSize(), i)) {
85 dest->Resize(0);
86 return false;
87 }
88 const auto read = src->Read(buffer.data(), buffer.size(), i);
89 dest->Write(buffer.data(), read, i);
90 }
91 return true;
92 };
93
94 std::shared_ptr<FileSys::NSP> nsp;
95 FileSys::VirtualFile file = vfs->OpenFile(filename, FileSys::Mode::Read);
96 if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) {
97 nsp = std::make_shared<FileSys::NSP>(file);
98 if (nsp->IsExtractedType()) {
99 return InstallResult::Failure;
100 }
101 } else {
102 return InstallResult::Failure;
103 }
104
105 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
106 return InstallResult::Failure;
107 }
108 const auto res =
109 system->GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, copy);
110 switch (res) {
111 case FileSys::InstallResult::Success:
112 return InstallResult::Success;
113 case FileSys::InstallResult::OverwriteExisting:
114 return InstallResult::Overwrite;
115 case FileSys::InstallResult::ErrorBaseInstall:
116 return InstallResult::BaseInstallAttempted;
117 default:
118 return InstallResult::Failure;
119 }
120}
121
122inline InstallResult InstallNCA(
123 FileSys::VfsFilesystem* vfs, const std::string& filename,
124 FileSys::RegisteredCache* registered_cache, const FileSys::TitleType title_type,
125 const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) {
126 const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
127 std::size_t block_size) {
128 if (src == nullptr || dest == nullptr) {
129 return false;
130 }
131 if (!dest->Resize(src->GetSize())) {
132 return false;
133 }
134
135 using namespace Common::Literals;
136 std::vector<u8> buffer(1_MiB);
137
138 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
139 if (callback(src->GetSize(), i)) {
140 dest->Resize(0);
141 return false;
142 }
143 const auto read = src->Read(buffer.data(), buffer.size(), i);
144 dest->Write(buffer.data(), read, i);
145 }
146 return true;
147 };
148
149 const auto nca = std::make_shared<FileSys::NCA>(vfs->OpenFile(filename, FileSys::Mode::Read));
150 const auto id = nca->GetStatus();
151
152 // Game updates necessary are missing base RomFS
153 if (id != Loader::ResultStatus::Success &&
154 id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
155 return InstallResult::Failure;
156 }
157
158 const auto res = registered_cache->InstallEntry(*nca, title_type, true, copy);
159 if (res == FileSys::InstallResult::Success) {
160 return InstallResult::Success;
161 } else if (res == FileSys::InstallResult::OverwriteExisting) {
162 return InstallResult::Overwrite;
163 } else {
164 return InstallResult::Failure;
165 }
166}
167
168} // namespace ContentManager