summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt12
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp548
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.h64
-rw-r--r--src/core/hle/service/bcat/bcat_module.cpp7
4 files changed, 0 insertions, 631 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a59c5a552..aa3b26628 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -651,13 +651,6 @@ add_library(core STATIC
651 tools/freezer.h 651 tools/freezer.h
652) 652)
653 653
654if (YUZU_ENABLE_BOXCAT)
655 target_sources(core PRIVATE
656 hle/service/bcat/backend/boxcat.cpp
657 hle/service/bcat/backend/boxcat.h
658 )
659endif()
660
661if (MSVC) 654if (MSVC)
662 target_compile_options(core PRIVATE 655 target_compile_options(core PRIVATE
663 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data 656 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
@@ -690,11 +683,6 @@ create_target_directory_groups(core)
690target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 683target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
691target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus) 684target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus)
692 685
693if (YUZU_ENABLE_BOXCAT)
694 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
695 target_link_libraries(core PRIVATE httplib nlohmann_json::nlohmann_json)
696endif()
697
698if (ENABLE_WEB_SERVICE) 686if (ENABLE_WEB_SERVICE)
699 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) 687 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
700 target_link_libraries(core PRIVATE web_service) 688 target_link_libraries(core PRIVATE web_service)
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
deleted file mode 100644
index 7ca7f2aac..000000000
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ /dev/null
@@ -1,548 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <fmt/ostream.h>
6
7#ifdef __GNUC__
8#pragma GCC diagnostic push
9#pragma GCC diagnostic ignored "-Wshadow"
10#ifndef __clang__
11#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
12#endif
13#endif
14#include <httplib.h>
15#include <mbedtls/sha256.h>
16#include <nlohmann/json.hpp>
17#ifdef __GNUC__
18#pragma GCC diagnostic pop
19#endif
20
21#include "common/fs/file.h"
22#include "common/fs/fs.h"
23#include "common/fs/path_util.h"
24#include "common/hex_util.h"
25#include "common/logging/log.h"
26#include "common/settings.h"
27#include "core/core.h"
28#include "core/file_sys/vfs.h"
29#include "core/file_sys/vfs_libzip.h"
30#include "core/file_sys/vfs_vector.h"
31#include "core/frontend/applets/error.h"
32#include "core/hle/service/am/applets/applets.h"
33#include "core/hle/service/bcat/backend/boxcat.h"
34
35namespace Service::BCAT {
36namespace {
37
38// Prevents conflicts with windows macro called CreateFile
39FileSys::VirtualFile VfsCreateFileWrap(FileSys::VirtualDir dir, std::string_view name) {
40 return dir->CreateFile(name);
41}
42
43// Prevents conflicts with windows macro called DeleteFile
44bool VfsDeleteFileWrap(FileSys::VirtualDir dir, std::string_view name) {
45 return dir->DeleteFile(name);
46}
47
48constexpr ResultCode ERROR_GENERAL_BCAT_FAILURE{ErrorModule::BCAT, 1};
49
50constexpr char BOXCAT_HOSTNAME[] = "api.yuzu-emu.org";
51
52// Formatted using fmt with arg[0] = hex title id
53constexpr char BOXCAT_PATHNAME_DATA[] = "/game-assets/{:016X}/boxcat";
54constexpr char BOXCAT_PATHNAME_LAUNCHPARAM[] = "/game-assets/{:016X}/launchparam";
55
56constexpr char BOXCAT_PATHNAME_EVENTS[] = "/game-assets/boxcat/events";
57
58constexpr char BOXCAT_API_VERSION[] = "1";
59constexpr char BOXCAT_CLIENT_TYPE[] = "yuzu";
60
61// HTTP status codes for Boxcat
62enum class ResponseStatus {
63 Ok = 200, ///< Operation completed successfully.
64 BadClientVersion = 301, ///< The Boxcat-Client-Version doesn't match the server.
65 NoUpdate = 304, ///< The digest provided would match the new data, no need to update.
66 NoMatchTitleId = 404, ///< The title ID provided doesn't have a boxcat implementation.
67 NoMatchBuildId = 406, ///< The build ID provided is blacklisted (potentially because of format
68 ///< issues or whatnot) and has no data.
69};
70
71enum class DownloadResult {
72 Success = 0,
73 NoResponse,
74 GeneralWebError,
75 NoMatchTitleId,
76 NoMatchBuildId,
77 InvalidContentType,
78 GeneralFSError,
79 BadClientVersion,
80};
81
82constexpr std::array<const char*, 8> DOWNLOAD_RESULT_LOG_MESSAGES{
83 "Success",
84 "There was no response from the server.",
85 "There was a general web error code returned from the server.",
86 "The title ID of the current game doesn't have a boxcat implementation. If you believe an "
87 "implementation should be added, contact yuzu support.",
88 "The build ID of the current version of the game is marked as incompatible with the current "
89 "BCAT distribution. Try upgrading or downgrading your game version or contacting yuzu support.",
90 "The content type of the web response was invalid.",
91 "There was a general filesystem error while saving the zip file.",
92 "The server is either too new or too old to serve the request. Try using the latest version of "
93 "an official release of yuzu.",
94};
95
96std::ostream& operator<<(std::ostream& os, DownloadResult result) {
97 return os << DOWNLOAD_RESULT_LOG_MESSAGES.at(static_cast<std::size_t>(result));
98}
99
100constexpr u32 PORT = 443;
101constexpr u32 TIMEOUT_SECONDS = 30;
102[[maybe_unused]] constexpr u64 VFS_COPY_BLOCK_SIZE = 1ULL << 24; // 4MB
103
104std::filesystem::path GetBINFilePath(u64 title_id) {
105 return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" /
106 fmt::format("{:016X}/launchparam.bin", title_id);
107}
108
109std::filesystem::path GetZIPFilePath(u64 title_id) {
110 return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" /
111 fmt::format("{:016X}/data.zip", title_id);
112}
113
114// If the error is something the user should know about (build ID mismatch, bad client version),
115// display an error.
116void HandleDownloadDisplayResult(const AM::Applets::AppletManager& applet_manager,
117 DownloadResult res) {
118 if (res == DownloadResult::Success || res == DownloadResult::NoResponse ||
119 res == DownloadResult::GeneralWebError || res == DownloadResult::GeneralFSError ||
120 res == DownloadResult::NoMatchTitleId || res == DownloadResult::InvalidContentType) {
121 return;
122 }
123
124 const auto& frontend{applet_manager.GetAppletFrontendSet()};
125 frontend.error->ShowCustomErrorText(
126 ResultUnknown, "There was an error while attempting to use Boxcat.",
127 DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {});
128}
129
130bool VfsRawCopyProgress(FileSys::VirtualFile src, FileSys::VirtualFile dest,
131 std::string_view dir_name, ProgressServiceBackend& progress,
132 std::size_t block_size = 0x1000) {
133 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
134 return false;
135 if (!dest->Resize(src->GetSize()))
136 return false;
137
138 progress.StartDownloadingFile(dir_name, src->GetName(), src->GetSize());
139
140 std::vector<u8> temp(std::min(block_size, src->GetSize()));
141 for (std::size_t i = 0; i < src->GetSize(); i += block_size) {
142 const auto read = std::min(block_size, src->GetSize() - i);
143
144 if (src->Read(temp.data(), read, i) != read) {
145 return false;
146 }
147
148 if (dest->Write(temp.data(), read, i) != read) {
149 return false;
150 }
151
152 progress.UpdateFileProgress(i);
153 }
154
155 progress.FinishDownloadingFile();
156
157 return true;
158}
159
160bool VfsRawCopyDProgressSingle(FileSys::VirtualDir src, FileSys::VirtualDir dest,
161 ProgressServiceBackend& progress, std::size_t block_size = 0x1000) {
162 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
163 return false;
164
165 for (const auto& file : src->GetFiles()) {
166 const auto out_file = VfsCreateFileWrap(dest, file->GetName());
167 if (!VfsRawCopyProgress(file, out_file, src->GetName(), progress, block_size)) {
168 return false;
169 }
170 }
171 progress.CommitDirectory(src->GetName());
172
173 return true;
174}
175
176bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest,
177 ProgressServiceBackend& progress, std::size_t block_size = 0x1000) {
178 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
179 return false;
180
181 for (const auto& dir : src->GetSubdirectories()) {
182 const auto out = dest->CreateSubdirectory(dir->GetName());
183 if (!VfsRawCopyDProgressSingle(dir, out, progress, block_size)) {
184 return false;
185 }
186 }
187
188 return true;
189}
190
191} // Anonymous namespace
192
193class Boxcat::Client {
194public:
195 Client(std::filesystem::path path_, u64 title_id_, u64 build_id_)
196 : path(std::move(path_)), title_id(title_id_), build_id(build_id_) {}
197
198 DownloadResult DownloadDataZip() {
199 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS,
200 "application/zip");
201 }
202
203 DownloadResult DownloadLaunchParam() {
204 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_LAUNCHPARAM, title_id),
205 TIMEOUT_SECONDS / 3, "application/octet-stream");
206 }
207
208private:
209 DownloadResult DownloadInternal(const std::string& resolved_path, u32 timeout_seconds,
210 const std::string& content_type_name) {
211 if (client == nullptr) {
212 client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT);
213 client->set_connection_timeout(timeout_seconds);
214 client->set_read_timeout(timeout_seconds);
215 client->set_write_timeout(timeout_seconds);
216 }
217
218 httplib::Headers headers{
219 {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
220 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
221 {std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)},
222 };
223
224 if (Common::FS::Exists(path)) {
225 Common::FS::IOFile file{path, Common::FS::FileAccessMode::Read,
226 Common::FS::FileType::BinaryFile};
227 if (file.IsOpen()) {
228 std::vector<u8> bytes(file.GetSize());
229 void(file.Read(bytes));
230 const auto digest = DigestFile(bytes);
231 headers.insert({std::string("If-None-Match"), Common::HexToString(digest, false)});
232 }
233 }
234
235 const auto response = client->Get(resolved_path.c_str(), headers);
236 if (response == nullptr)
237 return DownloadResult::NoResponse;
238
239 if (response->status == static_cast<int>(ResponseStatus::NoUpdate))
240 return DownloadResult::Success;
241 if (response->status == static_cast<int>(ResponseStatus::BadClientVersion))
242 return DownloadResult::BadClientVersion;
243 if (response->status == static_cast<int>(ResponseStatus::NoMatchTitleId))
244 return DownloadResult::NoMatchTitleId;
245 if (response->status == static_cast<int>(ResponseStatus::NoMatchBuildId))
246 return DownloadResult::NoMatchBuildId;
247 if (response->status != static_cast<int>(ResponseStatus::Ok))
248 return DownloadResult::GeneralWebError;
249
250 const auto content_type = response->headers.find("content-type");
251 if (content_type == response->headers.end() ||
252 content_type->second.find(content_type_name) == std::string::npos) {
253 return DownloadResult::InvalidContentType;
254 }
255
256 if (!Common::FS::CreateDirs(path)) {
257 return DownloadResult::GeneralFSError;
258 }
259
260 Common::FS::IOFile file{path, Common::FS::FileAccessMode::Append,
261 Common::FS::FileType::BinaryFile};
262 if (!file.IsOpen()) {
263 return DownloadResult::GeneralFSError;
264 }
265
266 if (!file.SetSize(response->body.size())) {
267 return DownloadResult::GeneralFSError;
268 }
269
270 if (file.Write(response->body) != response->body.size()) {
271 return DownloadResult::GeneralFSError;
272 }
273
274 return DownloadResult::Success;
275 }
276
277 using Digest = std::array<u8, 0x20>;
278 static Digest DigestFile(std::vector<u8> bytes) {
279 Digest out{};
280 mbedtls_sha256_ret(bytes.data(), bytes.size(), out.data(), 0);
281 return out;
282 }
283
284 std::unique_ptr<httplib::SSLClient> client;
285 std::filesystem::path path;
286 u64 title_id;
287 u64 build_id;
288};
289
290Boxcat::Boxcat(AM::Applets::AppletManager& applet_manager_, DirectoryGetter getter)
291 : Backend(std::move(getter)), applet_manager{applet_manager_} {}
292
293Boxcat::~Boxcat() = default;
294
295void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGetter dir_getter,
296 TitleIDVersion title, ProgressServiceBackend& progress,
297 std::optional<std::string> dir_name = {}) {
298 progress.SetNeedHLELock(true);
299
300 if (Settings::values.bcat_boxcat_local) {
301 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download.");
302 const auto dir = dir_getter(title.title_id);
303 if (dir)
304 progress.SetTotalSize(dir->GetSize());
305 progress.FinishDownload(ResultSuccess);
306 return;
307 }
308
309 const auto zip_path = GetZIPFilePath(title.title_id);
310 Boxcat::Client client{zip_path, title.title_id, title.build_id};
311
312 progress.StartConnecting();
313
314 const auto res = client.DownloadDataZip();
315 if (res != DownloadResult::Success) {
316 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
317
318 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
319 Common::FS::RemoveFile(zip_path);
320 }
321
322 HandleDownloadDisplayResult(applet_manager, res);
323 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
324 return;
325 }
326
327 progress.StartProcessingDataList();
328
329 Common::FS::IOFile zip{zip_path, Common::FS::FileAccessMode::Read,
330 Common::FS::FileType::BinaryFile};
331 const auto size = zip.GetSize();
332 std::vector<u8> bytes(size);
333 if (!zip.IsOpen() || size == 0 || zip.Read(bytes) != bytes.size()) {
334 LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!",
335 Common::FS::PathToUTF8String(zip_path));
336 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
337 return;
338 }
339
340 const auto extracted = FileSys::ExtractZIP(std::make_shared<FileSys::VectorVfsFile>(bytes));
341 if (extracted == nullptr) {
342 LOG_ERROR(Service_BCAT, "Boxcat failed to extract ZIP file!");
343 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
344 return;
345 }
346
347 if (dir_name == std::nullopt) {
348 progress.SetTotalSize(extracted->GetSize());
349
350 const auto target_dir = dir_getter(title.title_id);
351 if (target_dir == nullptr || !VfsRawCopyDProgress(extracted, target_dir, progress)) {
352 LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!");
353 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
354 return;
355 }
356 } else {
357 const auto target_dir = dir_getter(title.title_id);
358 if (target_dir == nullptr) {
359 LOG_ERROR(Service_BCAT, "Boxcat failed to get directory for title ID!");
360 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
361 return;
362 }
363
364 const auto target_sub = target_dir->GetSubdirectory(*dir_name);
365 const auto source_sub = extracted->GetSubdirectory(*dir_name);
366
367 progress.SetTotalSize(source_sub->GetSize());
368
369 std::vector<std::string> filenames;
370 {
371 const auto files = target_sub->GetFiles();
372 std::transform(files.begin(), files.end(), std::back_inserter(filenames),
373 [](const auto& vfile) { return vfile->GetName(); });
374 }
375
376 for (const auto& filename : filenames) {
377 VfsDeleteFileWrap(target_sub, filename);
378 }
379
380 if (target_sub == nullptr || source_sub == nullptr ||
381 !VfsRawCopyDProgressSingle(source_sub, target_sub, progress)) {
382 LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!");
383 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
384 return;
385 }
386 }
387
388 progress.FinishDownload(ResultSuccess);
389}
390
391bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) {
392 is_syncing.exchange(true);
393
394 std::thread([this, title, &progress] {
395 SynchronizeInternal(applet_manager, dir_getter, title, progress);
396 }).detach();
397
398 return true;
399}
400
401bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name,
402 ProgressServiceBackend& progress) {
403 is_syncing.exchange(true);
404
405 std::thread([this, title, name, &progress] {
406 SynchronizeInternal(applet_manager, dir_getter, title, progress, name);
407 }).detach();
408
409 return true;
410}
411
412bool Boxcat::Clear(u64 title_id) {
413 if (Settings::values.bcat_boxcat_local) {
414 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping clear.");
415 return true;
416 }
417
418 const auto dir = dir_getter(title_id);
419
420 std::vector<std::string> dirnames;
421
422 for (const auto& subdir : dir->GetSubdirectories())
423 dirnames.push_back(subdir->GetName());
424
425 for (const auto& subdir : dirnames) {
426 if (!dir->DeleteSubdirectoryRecursive(subdir))
427 return false;
428 }
429
430 return true;
431}
432
433void Boxcat::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
434 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
435 Common::HexToString(passphrase));
436}
437
438std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) {
439 const auto bin_file_path = GetBINFilePath(title.title_id);
440
441 if (Settings::values.bcat_boxcat_local) {
442 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download.");
443 } else {
444 Client launch_client{bin_file_path, title.title_id, title.build_id};
445
446 const auto res = launch_client.DownloadLaunchParam();
447 if (res != DownloadResult::Success) {
448 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
449
450 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
451 Common::FS::RemoveFile(bin_file_path);
452 }
453
454 HandleDownloadDisplayResult(applet_manager, res);
455 return std::nullopt;
456 }
457 }
458
459 Common::FS::IOFile bin{bin_file_path, Common::FS::FileAccessMode::Read,
460 Common::FS::FileType::BinaryFile};
461 const auto size = bin.GetSize();
462 std::vector<u8> bytes(size);
463 if (!bin.IsOpen() || size == 0 || bin.Read(bytes) != bytes.size()) {
464 LOG_ERROR(Service_BCAT, "Boxcat failed to read launch parameter binary at path '{}'!",
465 Common::FS::PathToUTF8String(bin_file_path));
466 return std::nullopt;
467 }
468
469 return bytes;
470}
471
472Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
473 std::map<std::string, EventStatus>& games) {
474 httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)};
475 client.set_connection_timeout(static_cast<int>(TIMEOUT_SECONDS));
476 client.set_read_timeout(static_cast<int>(TIMEOUT_SECONDS));
477 client.set_write_timeout(static_cast<int>(TIMEOUT_SECONDS));
478
479 httplib::Headers headers{
480 {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
481 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
482 };
483
484 if (!client.is_valid()) {
485 LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
486 return StatusResult::Offline;
487 }
488
489 if (!client.is_socket_open()) {
490 LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
491 return StatusResult::Offline;
492 }
493
494 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
495 if (response == nullptr)
496 return StatusResult::Offline;
497
498 if (response->status == static_cast<int>(ResponseStatus::BadClientVersion))
499 return StatusResult::BadClientVersion;
500
501 try {
502 nlohmann::json json = nlohmann::json::parse(response->body);
503
504 if (!json["online"].get<bool>())
505 return StatusResult::Offline;
506
507 if (json["global"].is_null())
508 global = std::nullopt;
509 else
510 global = json["global"].get<std::string>();
511
512 if (json["games"].is_array()) {
513 for (const auto& object : json["games"]) {
514 if (object.is_object() && object.find("name") != object.end()) {
515 EventStatus detail{};
516 if (object["header"].is_string()) {
517 detail.header = object["header"].get<std::string>();
518 } else {
519 detail.header = std::nullopt;
520 }
521
522 if (object["footer"].is_string()) {
523 detail.footer = object["footer"].get<std::string>();
524 } else {
525 detail.footer = std::nullopt;
526 }
527
528 if (object["events"].is_array()) {
529 for (const auto& event : object["events"]) {
530 if (!event.is_string())
531 continue;
532 detail.events.push_back(event.get<std::string>());
533 }
534 }
535
536 games.insert_or_assign(object["name"], std::move(detail));
537 }
538 }
539 }
540
541 return StatusResult::Success;
542 } catch (const nlohmann::json::parse_error& error) {
543 LOG_ERROR(Service_BCAT, "{}", error.what());
544 return StatusResult::ParseError;
545 }
546}
547
548} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/backend/boxcat.h b/src/core/hle/service/bcat/backend/boxcat.h
deleted file mode 100644
index d65b42e58..000000000
--- a/src/core/hle/service/bcat/backend/boxcat.h
+++ /dev/null
@@ -1,64 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <map>
9#include <optional>
10#include "core/hle/service/bcat/backend/backend.h"
11
12namespace Service::AM::Applets {
13class AppletManager;
14}
15
16namespace Service::BCAT {
17
18struct EventStatus {
19 std::optional<std::string> header;
20 std::optional<std::string> footer;
21 std::vector<std::string> events;
22};
23
24/// Boxcat is yuzu's custom backend implementation of Nintendo's BCAT service. It is free to use and
25/// doesn't require a switch or nintendo account. The content is controlled by the yuzu team.
26class Boxcat final : public Backend {
27 friend void SynchronizeInternal(AM::Applets::AppletManager& applet_manager,
28 DirectoryGetter dir_getter, TitleIDVersion title,
29 ProgressServiceBackend& progress,
30 std::optional<std::string> dir_name);
31
32public:
33 explicit Boxcat(AM::Applets::AppletManager& applet_manager_, DirectoryGetter getter);
34 ~Boxcat() override;
35
36 bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override;
37 bool SynchronizeDirectory(TitleIDVersion title, std::string name,
38 ProgressServiceBackend& progress) override;
39
40 bool Clear(u64 title_id) override;
41
42 void SetPassphrase(u64 title_id, const Passphrase& passphrase) override;
43
44 std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override;
45
46 enum class StatusResult {
47 Success,
48 Offline,
49 ParseError,
50 BadClientVersion,
51 };
52
53 static StatusResult GetStatus(std::optional<std::string>& global,
54 std::map<std::string, EventStatus>& games);
55
56private:
57 std::atomic_bool is_syncing{false};
58
59 class Client;
60 std::unique_ptr<Client> client;
61 AM::Applets::AppletManager& applet_manager;
62};
63
64} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp
index 72294eb2e..701f634f8 100644
--- a/src/core/hle/service/bcat/bcat_module.cpp
+++ b/src/core/hle/service/bcat/bcat_module.cpp
@@ -4,7 +4,6 @@
4 4
5#include <cctype> 5#include <cctype>
6#include <mbedtls/md5.h> 6#include <mbedtls/md5.h>
7#include "backend/boxcat.h"
8#include "common/hex_util.h" 7#include "common/hex_util.h"
9#include "common/logging/log.h" 8#include "common/logging/log.h"
10#include "common/settings.h" 9#include "common/settings.h"
@@ -578,12 +577,6 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
578 577
579std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system, 578std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
580 DirectoryGetter getter) { 579 DirectoryGetter getter) {
581#ifdef YUZU_ENABLE_BOXCAT
582 if (Settings::values.bcat_backend.GetValue() == "boxcat") {
583 return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
584 }
585#endif
586
587 return std::make_unique<NullBackend>(std::move(getter)); 580 return std::make_unique<NullBackend>(std::move(getter));
588} 581}
589 582