summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt29
-rw-r--r--src/core/file_sys/errors.h1
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp30
-rw-r--r--src/core/hle/service/bcat/backend/backend.h54
-rw-r--r--src/core/hle/service/bcat/bcat.cpp42
-rw-r--r--src/core/hle/service/bcat/bcat.h9
-rw-r--r--src/core/hle/service/bcat/bcat_module.cpp606
-rw-r--r--src/core/hle/service/bcat/bcat_module.h46
-rw-r--r--src/core/hle/service/bcat/bcat_result.h15
-rw-r--r--src/core/hle/service/bcat/bcat_service.cpp132
-rw-r--r--src/core/hle/service/bcat/bcat_service.h45
-rw-r--r--src/core/hle/service/bcat/bcat_types.h66
-rw-r--r--src/core/hle/service/bcat/bcat_util.h39
-rw-r--r--src/core/hle/service/bcat/delivery_cache_directory_service.cpp80
-rw-r--r--src/core/hle/service/bcat/delivery_cache_directory_service.h33
-rw-r--r--src/core/hle/service/bcat/delivery_cache_file_service.cpp82
-rw-r--r--src/core/hle/service/bcat/delivery_cache_file_service.h33
-rw-r--r--src/core/hle/service/bcat/delivery_cache_progress_service.cpp41
-rw-r--r--src/core/hle/service/bcat/delivery_cache_progress_service.h35
-rw-r--r--src/core/hle/service/bcat/delivery_cache_storage_service.cpp57
-rw-r--r--src/core/hle/service/bcat/delivery_cache_storage_service.h36
-rw-r--r--src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp34
-rw-r--r--src/core/hle/service/bcat/news/newly_arrived_event_holder.h33
-rw-r--r--src/core/hle/service/bcat/news/news_data_service.cpp25
-rw-r--r--src/core/hle/service/bcat/news/news_data_service.h20
-rw-r--r--src/core/hle/service/bcat/news/news_database_service.cpp35
-rw-r--r--src/core/hle/service/bcat/news/news_database_service.h24
-rw-r--r--src/core/hle/service/bcat/news/news_service.cpp46
-rw-r--r--src/core/hle/service/bcat/news/news_service.h24
-rw-r--r--src/core/hle/service/bcat/news/overwrite_event_holder.cpp33
-rw-r--r--src/core/hle/service/bcat/news/overwrite_event_holder.h33
-rw-r--r--src/core/hle/service/bcat/news/service_creator.cpp64
-rw-r--r--src/core/hle/service/bcat/news/service_creator.h35
-rw-r--r--src/core/hle/service/bcat/service_creator.cpp62
-rw-r--r--src/core/hle/service/bcat/service_creator.h40
-rw-r--r--src/core/hle/service/service.cpp2
36 files changed, 1285 insertions, 736 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 1b44148f4..2d5490968 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -512,10 +512,35 @@ add_library(core STATIC
512 hle/service/audio/hwopus.h 512 hle/service/audio/hwopus.h
513 hle/service/bcat/backend/backend.cpp 513 hle/service/bcat/backend/backend.cpp
514 hle/service/bcat/backend/backend.h 514 hle/service/bcat/backend/backend.h
515 hle/service/bcat/news/newly_arrived_event_holder.cpp
516 hle/service/bcat/news/newly_arrived_event_holder.h
517 hle/service/bcat/news/news_data_service.cpp
518 hle/service/bcat/news/news_data_service.h
519 hle/service/bcat/news/news_database_service.cpp
520 hle/service/bcat/news/news_database_service.h
521 hle/service/bcat/news/news_service.cpp
522 hle/service/bcat/news/news_service.h
523 hle/service/bcat/news/overwrite_event_holder.cpp
524 hle/service/bcat/news/overwrite_event_holder.h
525 hle/service/bcat/news/service_creator.cpp
526 hle/service/bcat/news/service_creator.h
515 hle/service/bcat/bcat.cpp 527 hle/service/bcat/bcat.cpp
516 hle/service/bcat/bcat.h 528 hle/service/bcat/bcat.h
517 hle/service/bcat/bcat_module.cpp 529 hle/service/bcat/bcat_result.h
518 hle/service/bcat/bcat_module.h 530 hle/service/bcat/bcat_service.cpp
531 hle/service/bcat/bcat_service.h
532 hle/service/bcat/bcat_types.h
533 hle/service/bcat/bcat_util.h
534 hle/service/bcat/delivery_cache_directory_service.cpp
535 hle/service/bcat/delivery_cache_directory_service.h
536 hle/service/bcat/delivery_cache_file_service.cpp
537 hle/service/bcat/delivery_cache_file_service.h
538 hle/service/bcat/delivery_cache_progress_service.cpp
539 hle/service/bcat/delivery_cache_progress_service.h
540 hle/service/bcat/delivery_cache_storage_service.cpp
541 hle/service/bcat/delivery_cache_storage_service.h
542 hle/service/bcat/service_creator.cpp
543 hle/service/bcat/service_creator.h
519 hle/service/bpc/bpc.cpp 544 hle/service/bpc/bpc.cpp
520 hle/service/bpc/bpc.h 545 hle/service/bpc/bpc.h
521 hle/service/btdrv/btdrv.cpp 546 hle/service/btdrv/btdrv.cpp
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index d4e0eb6f4..b22767bf5 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -91,6 +91,7 @@ constexpr Result ResultWriteNotPermitted{ErrorModule::FS, 6203};
91constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 6325}; 91constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 6325};
92constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387}; 92constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387};
93constexpr Result ResultUnsupportedOperateRangeForCompressedStorage{ErrorModule::FS, 6388}; 93constexpr Result ResultUnsupportedOperateRangeForCompressedStorage{ErrorModule::FS, 6388};
94constexpr Result ResultPermissionDenied{ErrorModule::FS, 6400};
94constexpr Result ResultBufferAllocationFailed{ErrorModule::FS, 6705}; 95constexpr Result ResultBufferAllocationFailed{ErrorModule::FS, 6705};
95 96
96} // namespace FileSys 97} // namespace FileSys
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index 847f76987..1993493a9 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -33,18 +33,18 @@ void ProgressServiceBackend::SetTotalSize(u64 size) {
33} 33}
34 34
35void ProgressServiceBackend::StartConnecting() { 35void ProgressServiceBackend::StartConnecting() {
36 impl.status = DeliveryCacheProgressImpl::Status::Connecting; 36 impl.status = DeliveryCacheProgressStatus::Connecting;
37 SignalUpdate(); 37 SignalUpdate();
38} 38}
39 39
40void ProgressServiceBackend::StartProcessingDataList() { 40void ProgressServiceBackend::StartProcessingDataList() {
41 impl.status = DeliveryCacheProgressImpl::Status::ProcessingDataList; 41 impl.status = DeliveryCacheProgressStatus::ProcessingDataList;
42 SignalUpdate(); 42 SignalUpdate();
43} 43}
44 44
45void ProgressServiceBackend::StartDownloadingFile(std::string_view dir_name, 45void ProgressServiceBackend::StartDownloadingFile(std::string_view dir_name,
46 std::string_view file_name, u64 file_size) { 46 std::string_view file_name, u64 file_size) {
47 impl.status = DeliveryCacheProgressImpl::Status::Downloading; 47 impl.status = DeliveryCacheProgressStatus::Downloading;
48 impl.current_downloaded_bytes = 0; 48 impl.current_downloaded_bytes = 0;
49 impl.current_total_bytes = file_size; 49 impl.current_total_bytes = file_size;
50 std::memcpy(impl.current_directory.data(), dir_name.data(), 50 std::memcpy(impl.current_directory.data(), dir_name.data(),
@@ -65,7 +65,7 @@ void ProgressServiceBackend::FinishDownloadingFile() {
65} 65}
66 66
67void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) { 67void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) {
68 impl.status = DeliveryCacheProgressImpl::Status::Committing; 68 impl.status = DeliveryCacheProgressStatus::Committing;
69 impl.current_file.fill(0); 69 impl.current_file.fill(0);
70 impl.current_downloaded_bytes = 0; 70 impl.current_downloaded_bytes = 0;
71 impl.current_total_bytes = 0; 71 impl.current_total_bytes = 0;
@@ -76,7 +76,7 @@ void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) {
76 76
77void ProgressServiceBackend::FinishDownload(Result result) { 77void ProgressServiceBackend::FinishDownload(Result result) {
78 impl.total_downloaded_bytes = impl.total_bytes; 78 impl.total_downloaded_bytes = impl.total_bytes;
79 impl.status = DeliveryCacheProgressImpl::Status::Done; 79 impl.status = DeliveryCacheProgressStatus::Done;
80 impl.result = result; 80 impl.result = result;
81 SignalUpdate(); 81 SignalUpdate();
82} 82}
@@ -85,15 +85,15 @@ void ProgressServiceBackend::SignalUpdate() {
85 update_event->Signal(); 85 update_event->Signal();
86} 86}
87 87
88Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {} 88BcatBackend::BcatBackend(DirectoryGetter getter) : dir_getter(std::move(getter)) {}
89 89
90Backend::~Backend() = default; 90BcatBackend::~BcatBackend() = default;
91 91
92NullBackend::NullBackend(DirectoryGetter getter) : Backend(std::move(getter)) {} 92NullBcatBackend::NullBcatBackend(DirectoryGetter getter) : BcatBackend(std::move(getter)) {}
93 93
94NullBackend::~NullBackend() = default; 94NullBcatBackend::~NullBcatBackend() = default;
95 95
96bool NullBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { 96bool NullBcatBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) {
97 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, 97 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id,
98 title.build_id); 98 title.build_id);
99 99
@@ -101,8 +101,8 @@ bool NullBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& prog
101 return true; 101 return true;
102} 102}
103 103
104bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name, 104bool NullBcatBackend::SynchronizeDirectory(TitleIDVersion title, std::string name,
105 ProgressServiceBackend& progress) { 105 ProgressServiceBackend& progress) {
106 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}, name={}", title.title_id, 106 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}, name={}", title.title_id,
107 title.build_id, name); 107 title.build_id, name);
108 108
@@ -110,18 +110,18 @@ bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name,
110 return true; 110 return true;
111} 111}
112 112
113bool NullBackend::Clear(u64 title_id) { 113bool NullBcatBackend::Clear(u64 title_id) {
114 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); 114 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
115 115
116 return true; 116 return true;
117} 117}
118 118
119void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) { 119void NullBcatBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
120 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, 120 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
121 Common::HexToString(passphrase)); 121 Common::HexToString(passphrase));
122} 122}
123 123
124std::optional<std::vector<u8>> NullBackend::GetLaunchParameter(TitleIDVersion title) { 124std::optional<std::vector<u8>> NullBcatBackend::GetLaunchParameter(TitleIDVersion title) {
125 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, 125 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id,
126 title.build_id); 126 title.build_id);
127 return std::nullopt; 127 return std::nullopt;
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h
index aa36d29d5..3680f6c9c 100644
--- a/src/core/hle/service/bcat/backend/backend.h
+++ b/src/core/hle/service/bcat/backend/backend.h
@@ -10,6 +10,7 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/vfs/vfs_types.h" 11#include "core/file_sys/vfs/vfs_types.h"
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13#include "core/hle/service/bcat/bcat_types.h"
13#include "core/hle/service/kernel_helpers.h" 14#include "core/hle/service/kernel_helpers.h"
14 15
15namespace Core { 16namespace Core {
@@ -24,44 +25,6 @@ class KReadableEvent;
24 25
25namespace Service::BCAT { 26namespace Service::BCAT {
26 27
27struct DeliveryCacheProgressImpl;
28
29using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>;
30using Passphrase = std::array<u8, 0x20>;
31
32struct TitleIDVersion {
33 u64 title_id;
34 u64 build_id;
35};
36
37using DirectoryName = std::array<char, 0x20>;
38using FileName = std::array<char, 0x20>;
39
40struct DeliveryCacheProgressImpl {
41 enum class Status : s32 {
42 None = 0x0,
43 Queued = 0x1,
44 Connecting = 0x2,
45 ProcessingDataList = 0x3,
46 Downloading = 0x4,
47 Committing = 0x5,
48 Done = 0x9,
49 };
50
51 Status status;
52 Result result = ResultSuccess;
53 DirectoryName current_directory;
54 FileName current_file;
55 s64 current_downloaded_bytes; ///< Bytes downloaded on current file.
56 s64 current_total_bytes; ///< Bytes total on current file.
57 s64 total_downloaded_bytes; ///< Bytes downloaded on overall download.
58 s64 total_bytes; ///< Bytes total on overall download.
59 INSERT_PADDING_BYTES(
60 0x198); ///< Appears to be unused in official code, possibly reserved for future use.
61};
62static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200,
63 "DeliveryCacheProgressImpl has incorrect size.");
64
65// A class to manage the signalling to the game about BCAT download progress. 28// A class to manage the signalling to the game about BCAT download progress.
66// Some of this class is implemented in module.cpp to avoid exposing the implementation structure. 29// Some of this class is implemented in module.cpp to avoid exposing the implementation structure.
67class ProgressServiceBackend { 30class ProgressServiceBackend {
@@ -107,10 +70,10 @@ private:
107}; 70};
108 71
109// A class representing an abstract backend for BCAT functionality. 72// A class representing an abstract backend for BCAT functionality.
110class Backend { 73class BcatBackend {
111public: 74public:
112 explicit Backend(DirectoryGetter getter); 75 explicit BcatBackend(DirectoryGetter getter);
113 virtual ~Backend(); 76 virtual ~BcatBackend();
114 77
115 // Called when the backend is needed to synchronize the data for the game with title ID and 78 // Called when the backend is needed to synchronize the data for the game with title ID and
116 // version in title. A ProgressServiceBackend object is provided to alert the application of 79 // version in title. A ProgressServiceBackend object is provided to alert the application of
@@ -135,10 +98,10 @@ protected:
135}; 98};
136 99
137// A backend of BCAT that provides no operation. 100// A backend of BCAT that provides no operation.
138class NullBackend : public Backend { 101class NullBcatBackend : public BcatBackend {
139public: 102public:
140 explicit NullBackend(DirectoryGetter getter); 103 explicit NullBcatBackend(DirectoryGetter getter);
141 ~NullBackend() override; 104 ~NullBcatBackend() override;
142 105
143 bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; 106 bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override;
144 bool SynchronizeDirectory(TitleIDVersion title, std::string name, 107 bool SynchronizeDirectory(TitleIDVersion title, std::string name,
@@ -151,6 +114,7 @@ public:
151 std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; 114 std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override;
152}; 115};
153 116
154std::unique_ptr<Backend> CreateBackendFromSettings(Core::System& system, DirectoryGetter getter); 117std::unique_ptr<BcatBackend> CreateBackendFromSettings(Core::System& system,
118 DirectoryGetter getter);
155 119
156} // namespace Service::BCAT 120} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp
index d0ac17324..ea8b15998 100644
--- a/src/core/hle/service/bcat/bcat.cpp
+++ b/src/core/hle/service/bcat/bcat.cpp
@@ -1,24 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/bcat/backend/backend.h"
4#include "core/hle/service/bcat/bcat.h" 5#include "core/hle/service/bcat/bcat.h"
6#include "core/hle/service/bcat/news/service_creator.h"
7#include "core/hle/service/bcat/service_creator.h"
8#include "core/hle/service/server_manager.h"
5 9
6namespace Service::BCAT { 10namespace Service::BCAT {
7 11
8BCAT::BCAT(Core::System& system_, std::shared_ptr<Module> module_, 12void LoopProcess(Core::System& system) {
9 FileSystem::FileSystemController& fsc_, const char* name_) 13 auto server_manager = std::make_unique<ServerManager>(system);
10 : Interface(system_, std::move(module_), fsc_, name_) { 14
11 // clang-format off 15 server_manager->RegisterNamedService("bcat:a",
12 static const FunctionInfo functions[] = { 16 std::make_shared<IServiceCreator>(system, "bcat:a"));
13 {0, &BCAT::CreateBcatService, "CreateBcatService"}, 17 server_manager->RegisterNamedService("bcat:m",
14 {1, &BCAT::CreateDeliveryCacheStorageService, "CreateDeliveryCacheStorageService"}, 18 std::make_shared<IServiceCreator>(system, "bcat:m"));
15 {2, &BCAT::CreateDeliveryCacheStorageServiceWithApplicationId, "CreateDeliveryCacheStorageServiceWithApplicationId"}, 19 server_manager->RegisterNamedService("bcat:u",
16 {3, nullptr, "CreateDeliveryCacheProgressService"}, 20 std::make_shared<IServiceCreator>(system, "bcat:u"));
17 {4, nullptr, "CreateDeliveryCacheProgressServiceWithApplicationId"}, 21 server_manager->RegisterNamedService("bcat:s",
18 }; 22 std::make_shared<IServiceCreator>(system, "bcat:s"));
19 // clang-format on 23
20 RegisterHandlers(functions); 24 server_manager->RegisterNamedService(
25 "news:a", std::make_shared<News::IServiceCreator>(system, 0xffffffff, "news:a"));
26 server_manager->RegisterNamedService(
27 "news:p", std::make_shared<News::IServiceCreator>(system, 0x1, "news:p"));
28 server_manager->RegisterNamedService(
29 "news:c", std::make_shared<News::IServiceCreator>(system, 0x2, "news:c"));
30 server_manager->RegisterNamedService(
31 "news:v", std::make_shared<News::IServiceCreator>(system, 0x4, "news:v"));
32 server_manager->RegisterNamedService(
33 "news:m", std::make_shared<News::IServiceCreator>(system, 0xd, "news:m"));
34
35 ServerManager::RunServer(std::move(server_manager));
21} 36}
22 37
23BCAT::~BCAT() = default;
24} // namespace Service::BCAT 38} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h
index db9d3c8c5..2aaffc693 100644
--- a/src/core/hle/service/bcat/bcat.h
+++ b/src/core/hle/service/bcat/bcat.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/bcat/bcat_module.h" 6#include "core/hle/service/service.h"
7 7
8namespace Core { 8namespace Core {
9class System; 9class System;
@@ -11,11 +11,6 @@ class System;
11 11
12namespace Service::BCAT { 12namespace Service::BCAT {
13 13
14class BCAT final : public Module::Interface { 14void LoopProcess(Core::System& system);
15public:
16 explicit BCAT(Core::System& system_, std::shared_ptr<Module> module_,
17 FileSystem::FileSystemController& fsc_, const char* name_);
18 ~BCAT() override;
19};
20 15
21} // namespace Service::BCAT 16} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp
deleted file mode 100644
index 76d7bb139..000000000
--- a/src/core/hle/service/bcat/bcat_module.cpp
+++ /dev/null
@@ -1,606 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cctype>
5#include <mbedtls/md5.h>
6#include "common/hex_util.h"
7#include "common/logging/log.h"
8#include "common/settings.h"
9#include "common/string_util.h"
10#include "core/core.h"
11#include "core/file_sys/vfs/vfs.h"
12#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/service/bcat/backend/backend.h"
14#include "core/hle/service/bcat/bcat.h"
15#include "core/hle/service/bcat/bcat_module.h"
16#include "core/hle/service/filesystem/filesystem.h"
17#include "core/hle/service/ipc_helpers.h"
18#include "core/hle/service/server_manager.h"
19
20namespace Service::BCAT {
21
22constexpr Result ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1};
23constexpr Result ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2};
24constexpr Result ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6};
25constexpr Result ERROR_NO_OPEN_ENTITY{ErrorModule::BCAT, 7};
26
27// The command to clear the delivery cache just calls fs IFileSystem DeleteFile on all of the files
28// and if any of them have a non-zero result it just forwards that result. This is the FS error code
29// for permission denied, which is the closest approximation of this scenario.
30constexpr Result ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400};
31
32using BCATDigest = std::array<u8, 0x10>;
33
34namespace {
35
36u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
37 u64 out{};
38 std::memcpy(&out, id.data(), sizeof(u64));
39 return out;
40}
41
42// The digest is only used to determine if a file is unique compared to others of the same name.
43// Since the algorithm isn't ever checked in game, MD5 is safe.
44BCATDigest DigestFile(const FileSys::VirtualFile& file) {
45 BCATDigest out{};
46 const auto bytes = file->ReadAllBytes();
47 mbedtls_md5_ret(bytes.data(), bytes.size(), out.data());
48 return out;
49}
50
51// For a name to be valid it must be non-empty, must have a null terminating character as the final
52// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if
53// file.
54bool VerifyNameValidInternal(HLERequestContext& ctx, std::array<char, 0x20> name, char match_char) {
55 const auto null_chars = std::count(name.begin(), name.end(), 0);
56 const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) {
57 return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0';
58 });
59 if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') {
60 LOG_ERROR(Service_BCAT, "Name passed was invalid!");
61 IPC::ResponseBuilder rb{ctx, 2};
62 rb.Push(ERROR_INVALID_ARGUMENT);
63 return false;
64 }
65
66 return true;
67}
68
69bool VerifyNameValidDir(HLERequestContext& ctx, DirectoryName name) {
70 return VerifyNameValidInternal(ctx, name, '-');
71}
72
73bool VerifyNameValidFile(HLERequestContext& ctx, FileName name) {
74 return VerifyNameValidInternal(ctx, name, '.');
75}
76
77} // Anonymous namespace
78
79struct DeliveryCacheDirectoryEntry {
80 FileName name;
81 u64 size;
82 BCATDigest digest;
83};
84
85class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
86public:
87 explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_,
88 const DeliveryCacheProgressImpl& impl_)
89 : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} {
90 // clang-format off
91 static const FunctionInfo functions[] = {
92 {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"},
93 {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"},
94 };
95 // clang-format on
96
97 RegisterHandlers(functions);
98 }
99
100private:
101 void GetEvent(HLERequestContext& ctx) {
102 LOG_DEBUG(Service_BCAT, "called");
103
104 IPC::ResponseBuilder rb{ctx, 2, 1};
105 rb.Push(ResultSuccess);
106 rb.PushCopyObjects(event);
107 }
108
109 void GetImpl(HLERequestContext& ctx) {
110 LOG_DEBUG(Service_BCAT, "called");
111
112 ctx.WriteBuffer(impl);
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(ResultSuccess);
116 }
117
118 Kernel::KReadableEvent& event;
119 const DeliveryCacheProgressImpl& impl;
120};
121
122class IBcatService final : public ServiceFramework<IBcatService> {
123public:
124 explicit IBcatService(Core::System& system_, Backend& backend_)
125 : ServiceFramework{system_, "IBcatService"}, backend{backend_},
126 progress{{
127 ProgressServiceBackend{system_, "Normal"},
128 ProgressServiceBackend{system_, "Directory"},
129 }} {
130 // clang-format off
131 static const FunctionInfo functions[] = {
132 {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"},
133 {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"},
134 {10200, nullptr, "CancelSyncDeliveryCacheRequest"},
135 {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"},
136 {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"},
137 {20300, nullptr, "GetDeliveryCacheStorageUpdateNotifier"},
138 {20301, nullptr, "RequestSuspendDeliveryTask"},
139 {20400, nullptr, "RegisterSystemApplicationDeliveryTask"},
140 {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
141 {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"},
142 {30100, &IBcatService::SetPassphrase, "SetPassphrase"},
143 {30101, nullptr, "Unknown30101"},
144 {30102, nullptr, "Unknown30102"},
145 {30200, nullptr, "RegisterBackgroundDeliveryTask"},
146 {30201, nullptr, "UnregisterBackgroundDeliveryTask"},
147 {30202, nullptr, "BlockDeliveryTask"},
148 {30203, nullptr, "UnblockDeliveryTask"},
149 {30210, nullptr, "SetDeliveryTaskTimer"},
150 {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"},
151 {90100, nullptr, "EnumerateBackgroundDeliveryTask"},
152 {90101, nullptr, "Unknown90101"},
153 {90200, nullptr, "GetDeliveryList"},
154 {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"},
155 {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
156 {90300, nullptr, "GetPushNotificationLog"},
157 {90301, nullptr, "Unknown90301"},
158 };
159 // clang-format on
160 RegisterHandlers(functions);
161 }
162
163private:
164 enum class SyncType {
165 Normal,
166 Directory,
167 Count,
168 };
169
170 std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) {
171 auto& progress_backend{GetProgressBackend(type)};
172 return std::make_shared<IDeliveryCacheProgressService>(system, progress_backend.GetEvent(),
173 progress_backend.GetImpl());
174 }
175
176 void RequestSyncDeliveryCache(HLERequestContext& ctx) {
177 LOG_DEBUG(Service_BCAT, "called");
178
179 backend.Synchronize({system.GetApplicationProcessProgramID(),
180 GetCurrentBuildID(system.GetApplicationProcessBuildID())},
181 GetProgressBackend(SyncType::Normal));
182
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(ResultSuccess);
185 rb.PushIpcInterface(CreateProgressService(SyncType::Normal));
186 }
187
188 void RequestSyncDeliveryCacheWithDirectoryName(HLERequestContext& ctx) {
189 IPC::RequestParser rp{ctx};
190 const auto name_raw = rp.PopRaw<DirectoryName>();
191 const auto name =
192 Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size());
193
194 LOG_DEBUG(Service_BCAT, "called, name={}", name);
195
196 backend.SynchronizeDirectory({system.GetApplicationProcessProgramID(),
197 GetCurrentBuildID(system.GetApplicationProcessBuildID())},
198 name, GetProgressBackend(SyncType::Directory));
199
200 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
201 rb.Push(ResultSuccess);
202 rb.PushIpcInterface(CreateProgressService(SyncType::Directory));
203 }
204
205 void SetPassphrase(HLERequestContext& ctx) {
206 IPC::RequestParser rp{ctx};
207 const auto title_id = rp.PopRaw<u64>();
208
209 const auto passphrase_raw = ctx.ReadBuffer();
210
211 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
212 Common::HexToString(passphrase_raw));
213
214 if (title_id == 0) {
215 LOG_ERROR(Service_BCAT, "Invalid title ID!");
216 IPC::ResponseBuilder rb{ctx, 2};
217 rb.Push(ERROR_INVALID_ARGUMENT);
218 }
219
220 if (passphrase_raw.size() > 0x40) {
221 LOG_ERROR(Service_BCAT, "Passphrase too large!");
222 IPC::ResponseBuilder rb{ctx, 2};
223 rb.Push(ERROR_INVALID_ARGUMENT);
224 return;
225 }
226
227 Passphrase passphrase{};
228 std::memcpy(passphrase.data(), passphrase_raw.data(),
229 std::min(passphrase.size(), passphrase_raw.size()));
230
231 backend.SetPassphrase(title_id, passphrase);
232
233 IPC::ResponseBuilder rb{ctx, 2};
234 rb.Push(ResultSuccess);
235 }
236
237 void ClearDeliveryCacheStorage(HLERequestContext& ctx) {
238 IPC::RequestParser rp{ctx};
239 const auto title_id = rp.PopRaw<u64>();
240
241 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
242
243 if (title_id == 0) {
244 LOG_ERROR(Service_BCAT, "Invalid title ID!");
245 IPC::ResponseBuilder rb{ctx, 2};
246 rb.Push(ERROR_INVALID_ARGUMENT);
247 return;
248 }
249
250 if (!backend.Clear(title_id)) {
251 LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!");
252 IPC::ResponseBuilder rb{ctx, 2};
253 rb.Push(ERROR_FAILED_CLEAR_CACHE);
254 return;
255 }
256
257 IPC::ResponseBuilder rb{ctx, 2};
258 rb.Push(ResultSuccess);
259 }
260
261 ProgressServiceBackend& GetProgressBackend(SyncType type) {
262 return progress.at(static_cast<size_t>(type));
263 }
264
265 const ProgressServiceBackend& GetProgressBackend(SyncType type) const {
266 return progress.at(static_cast<size_t>(type));
267 }
268
269 Backend& backend;
270 std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
271};
272
273void Module::Interface::CreateBcatService(HLERequestContext& ctx) {
274 LOG_DEBUG(Service_BCAT, "called");
275
276 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
277 rb.Push(ResultSuccess);
278 rb.PushIpcInterface<IBcatService>(system, *backend);
279}
280
281class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
282public:
283 explicit IDeliveryCacheFileService(Core::System& system_, FileSys::VirtualDir root_)
284 : ServiceFramework{system_, "IDeliveryCacheFileService"}, root(std::move(root_)) {
285 // clang-format off
286 static const FunctionInfo functions[] = {
287 {0, &IDeliveryCacheFileService::Open, "Open"},
288 {1, &IDeliveryCacheFileService::Read, "Read"},
289 {2, &IDeliveryCacheFileService::GetSize, "GetSize"},
290 {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"},
291 };
292 // clang-format on
293
294 RegisterHandlers(functions);
295 }
296
297private:
298 void Open(HLERequestContext& ctx) {
299 IPC::RequestParser rp{ctx};
300 const auto dir_name_raw = rp.PopRaw<DirectoryName>();
301 const auto file_name_raw = rp.PopRaw<FileName>();
302
303 const auto dir_name =
304 Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size());
305 const auto file_name =
306 Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size());
307
308 LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name);
309
310 if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw))
311 return;
312
313 if (current_file != nullptr) {
314 LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!");
315 IPC::ResponseBuilder rb{ctx, 2};
316 rb.Push(ERROR_ENTITY_ALREADY_OPEN);
317 return;
318 }
319
320 const auto dir = root->GetSubdirectory(dir_name);
321
322 if (dir == nullptr) {
323 LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name);
324 IPC::ResponseBuilder rb{ctx, 2};
325 rb.Push(ERROR_FAILED_OPEN_ENTITY);
326 return;
327 }
328
329 current_file = dir->GetFile(file_name);
330
331 if (current_file == nullptr) {
332 LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name);
333 IPC::ResponseBuilder rb{ctx, 2};
334 rb.Push(ERROR_FAILED_OPEN_ENTITY);
335 return;
336 }
337
338 IPC::ResponseBuilder rb{ctx, 2};
339 rb.Push(ResultSuccess);
340 }
341
342 void Read(HLERequestContext& ctx) {
343 IPC::RequestParser rp{ctx};
344 const auto offset{rp.PopRaw<u64>()};
345
346 auto size = ctx.GetWriteBufferSize();
347
348 LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size);
349
350 if (current_file == nullptr) {
351 LOG_ERROR(Service_BCAT, "There is no file currently open!");
352 IPC::ResponseBuilder rb{ctx, 2};
353 rb.Push(ERROR_NO_OPEN_ENTITY);
354 }
355
356 size = std::min<u64>(current_file->GetSize() - offset, size);
357 const auto buffer = current_file->ReadBytes(size, offset);
358 ctx.WriteBuffer(buffer);
359
360 IPC::ResponseBuilder rb{ctx, 4};
361 rb.Push(ResultSuccess);
362 rb.Push<u64>(buffer.size());
363 }
364
365 void GetSize(HLERequestContext& ctx) {
366 LOG_DEBUG(Service_BCAT, "called");
367
368 if (current_file == nullptr) {
369 LOG_ERROR(Service_BCAT, "There is no file currently open!");
370 IPC::ResponseBuilder rb{ctx, 2};
371 rb.Push(ERROR_NO_OPEN_ENTITY);
372 }
373
374 IPC::ResponseBuilder rb{ctx, 4};
375 rb.Push(ResultSuccess);
376 rb.Push<u64>(current_file->GetSize());
377 }
378
379 void GetDigest(HLERequestContext& ctx) {
380 LOG_DEBUG(Service_BCAT, "called");
381
382 if (current_file == nullptr) {
383 LOG_ERROR(Service_BCAT, "There is no file currently open!");
384 IPC::ResponseBuilder rb{ctx, 2};
385 rb.Push(ERROR_NO_OPEN_ENTITY);
386 }
387
388 IPC::ResponseBuilder rb{ctx, 6};
389 rb.Push(ResultSuccess);
390 rb.PushRaw(DigestFile(current_file));
391 }
392
393 FileSys::VirtualDir root;
394 FileSys::VirtualFile current_file;
395};
396
397class IDeliveryCacheDirectoryService final
398 : public ServiceFramework<IDeliveryCacheDirectoryService> {
399public:
400 explicit IDeliveryCacheDirectoryService(Core::System& system_, FileSys::VirtualDir root_)
401 : ServiceFramework{system_, "IDeliveryCacheDirectoryService"}, root(std::move(root_)) {
402 // clang-format off
403 static const FunctionInfo functions[] = {
404 {0, &IDeliveryCacheDirectoryService::Open, "Open"},
405 {1, &IDeliveryCacheDirectoryService::Read, "Read"},
406 {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"},
407 };
408 // clang-format on
409
410 RegisterHandlers(functions);
411 }
412
413private:
414 void Open(HLERequestContext& ctx) {
415 IPC::RequestParser rp{ctx};
416 const auto name_raw = rp.PopRaw<DirectoryName>();
417 const auto name =
418 Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size());
419
420 LOG_DEBUG(Service_BCAT, "called, name={}", name);
421
422 if (!VerifyNameValidDir(ctx, name_raw))
423 return;
424
425 if (current_dir != nullptr) {
426 LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!");
427 IPC::ResponseBuilder rb{ctx, 2};
428 rb.Push(ERROR_ENTITY_ALREADY_OPEN);
429 return;
430 }
431
432 current_dir = root->GetSubdirectory(name);
433
434 if (current_dir == nullptr) {
435 LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name);
436 IPC::ResponseBuilder rb{ctx, 2};
437 rb.Push(ERROR_FAILED_OPEN_ENTITY);
438 return;
439 }
440
441 IPC::ResponseBuilder rb{ctx, 2};
442 rb.Push(ResultSuccess);
443 }
444
445 void Read(HLERequestContext& ctx) {
446 auto write_size = ctx.GetWriteBufferNumElements<DeliveryCacheDirectoryEntry>();
447
448 LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size);
449
450 if (current_dir == nullptr) {
451 LOG_ERROR(Service_BCAT, "There is no open directory!");
452 IPC::ResponseBuilder rb{ctx, 2};
453 rb.Push(ERROR_NO_OPEN_ENTITY);
454 return;
455 }
456
457 const auto files = current_dir->GetFiles();
458 write_size = std::min<u64>(write_size, files.size());
459 std::vector<DeliveryCacheDirectoryEntry> entries(write_size);
460 std::transform(
461 files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) {
462 FileName name{};
463 std::memcpy(name.data(), file->GetName().data(),
464 std::min(file->GetName().size(), name.size()));
465 return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)};
466 });
467
468 ctx.WriteBuffer(entries);
469
470 IPC::ResponseBuilder rb{ctx, 3};
471 rb.Push(ResultSuccess);
472 rb.Push(static_cast<u32>(write_size * sizeof(DeliveryCacheDirectoryEntry)));
473 }
474
475 void GetCount(HLERequestContext& ctx) {
476 LOG_DEBUG(Service_BCAT, "called");
477
478 if (current_dir == nullptr) {
479 LOG_ERROR(Service_BCAT, "There is no open directory!");
480 IPC::ResponseBuilder rb{ctx, 2};
481 rb.Push(ERROR_NO_OPEN_ENTITY);
482 return;
483 }
484
485 const auto files = current_dir->GetFiles();
486
487 IPC::ResponseBuilder rb{ctx, 3};
488 rb.Push(ResultSuccess);
489 rb.Push(static_cast<u32>(files.size()));
490 }
491
492 FileSys::VirtualDir root;
493 FileSys::VirtualDir current_dir;
494};
495
496class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> {
497public:
498 explicit IDeliveryCacheStorageService(Core::System& system_, FileSys::VirtualDir root_)
499 : ServiceFramework{system_, "IDeliveryCacheStorageService"}, root(std::move(root_)) {
500 // clang-format off
501 static const FunctionInfo functions[] = {
502 {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"},
503 {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"},
504 {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"},
505 };
506 // clang-format on
507
508 RegisterHandlers(functions);
509
510 for (const auto& subdir : root->GetSubdirectories()) {
511 DirectoryName name{};
512 std::memcpy(name.data(), subdir->GetName().data(),
513 std::min(sizeof(DirectoryName) - 1, subdir->GetName().size()));
514 entries.push_back(name);
515 }
516 }
517
518private:
519 void CreateFileService(HLERequestContext& ctx) {
520 LOG_DEBUG(Service_BCAT, "called");
521
522 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
523 rb.Push(ResultSuccess);
524 rb.PushIpcInterface<IDeliveryCacheFileService>(system, root);
525 }
526
527 void CreateDirectoryService(HLERequestContext& ctx) {
528 LOG_DEBUG(Service_BCAT, "called");
529
530 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
531 rb.Push(ResultSuccess);
532 rb.PushIpcInterface<IDeliveryCacheDirectoryService>(system, root);
533 }
534
535 void EnumerateDeliveryCacheDirectory(HLERequestContext& ctx) {
536 auto size = ctx.GetWriteBufferNumElements<DirectoryName>();
537
538 LOG_DEBUG(Service_BCAT, "called, size={:016X}", size);
539
540 size = std::min<u64>(size, entries.size() - next_read_index);
541 ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName));
542 next_read_index += size;
543
544 IPC::ResponseBuilder rb{ctx, 3};
545 rb.Push(ResultSuccess);
546 rb.Push(static_cast<u32>(size));
547 }
548
549 FileSys::VirtualDir root;
550 std::vector<DirectoryName> entries;
551 u64 next_read_index = 0;
552};
553
554void Module::Interface::CreateDeliveryCacheStorageService(HLERequestContext& ctx) {
555 LOG_DEBUG(Service_BCAT, "called");
556
557 const auto title_id = system.GetApplicationProcessProgramID();
558 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
559 rb.Push(ResultSuccess);
560 rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
561}
562
563void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(HLERequestContext& ctx) {
564 IPC::RequestParser rp{ctx};
565 const auto title_id = rp.PopRaw<u64>();
566
567 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
568
569 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
570 rb.Push(ResultSuccess);
571 rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
572}
573
574std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
575 DirectoryGetter getter) {
576 return std::make_unique<NullBackend>(std::move(getter));
577}
578
579Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
580 FileSystem::FileSystemController& fsc_, const char* name)
581 : ServiceFramework{system_, name}, fsc{fsc_}, module{std::move(module_)},
582 backend{CreateBackendFromSettings(system_,
583 [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })} {}
584
585Module::Interface::~Interface() = default;
586
587void LoopProcess(Core::System& system) {
588 auto server_manager = std::make_unique<ServerManager>(system);
589 auto module = std::make_shared<Module>();
590
591 server_manager->RegisterNamedService(
592 "bcat:a",
593 std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:a"));
594 server_manager->RegisterNamedService(
595 "bcat:m",
596 std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:m"));
597 server_manager->RegisterNamedService(
598 "bcat:u",
599 std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:u"));
600 server_manager->RegisterNamedService(
601 "bcat:s",
602 std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:s"));
603 ServerManager::RunServer(std::move(server_manager));
604}
605
606} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_module.h b/src/core/hle/service/bcat/bcat_module.h
deleted file mode 100644
index 87576288b..000000000
--- a/src/core/hle/service/bcat/bcat_module.h
+++ /dev/null
@@ -1,46 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core {
9class System;
10}
11
12namespace Service {
13
14namespace FileSystem {
15class FileSystemController;
16} // namespace FileSystem
17
18namespace BCAT {
19
20class Backend;
21
22class Module final {
23public:
24 class Interface : public ServiceFramework<Interface> {
25 public:
26 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
27 FileSystem::FileSystemController& fsc_, const char* name);
28 ~Interface() override;
29
30 void CreateBcatService(HLERequestContext& ctx);
31 void CreateDeliveryCacheStorageService(HLERequestContext& ctx);
32 void CreateDeliveryCacheStorageServiceWithApplicationId(HLERequestContext& ctx);
33
34 protected:
35 FileSystem::FileSystemController& fsc;
36
37 std::shared_ptr<Module> module;
38 std::unique_ptr<Backend> backend;
39 };
40};
41
42void LoopProcess(Core::System& system);
43
44} // namespace BCAT
45
46} // namespace Service
diff --git a/src/core/hle/service/bcat/bcat_result.h b/src/core/hle/service/bcat/bcat_result.h
new file mode 100644
index 000000000..edf8a6564
--- /dev/null
+++ b/src/core/hle/service/bcat/bcat_result.h
@@ -0,0 +1,15 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::BCAT {
9
10constexpr Result ResultInvalidArgument{ErrorModule::BCAT, 1};
11constexpr Result ResultFailedOpenEntity{ErrorModule::BCAT, 2};
12constexpr Result ResultEntityAlreadyOpen{ErrorModule::BCAT, 6};
13constexpr Result ResultNoOpenEntry{ErrorModule::BCAT, 7};
14
15} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_service.cpp b/src/core/hle/service/bcat/bcat_service.cpp
new file mode 100644
index 000000000..63b1072d2
--- /dev/null
+++ b/src/core/hle/service/bcat/bcat_service.cpp
@@ -0,0 +1,132 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/hex_util.h"
5#include "common/string_util.h"
6#include "core/core.h"
7#include "core/file_sys/errors.h"
8#include "core/hle/service/bcat/backend/backend.h"
9#include "core/hle/service/bcat/bcat_result.h"
10#include "core/hle/service/bcat/bcat_service.h"
11#include "core/hle/service/bcat/bcat_util.h"
12#include "core/hle/service/bcat/delivery_cache_progress_service.h"
13#include "core/hle/service/bcat/delivery_cache_storage_service.h"
14#include "core/hle/service/cmif_serialization.h"
15
16namespace Service::BCAT {
17
18static u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
19 u64 out{};
20 std::memcpy(&out, id.data(), sizeof(u64));
21 return out;
22}
23
24IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
25 : ServiceFramework{system_, "IBcatService"}, backend{backend_},
26 progress{{
27 ProgressServiceBackend{system_, "Normal"},
28 ProgressServiceBackend{system_, "Directory"},
29 }} {
30 // clang-format off
31 static const FunctionInfo functions[] = {
32 {10100, D<&IBcatService::RequestSyncDeliveryCache>, "RequestSyncDeliveryCache"},
33 {10101, D<&IBcatService::RequestSyncDeliveryCacheWithDirectoryName>, "RequestSyncDeliveryCacheWithDirectoryName"},
34 {10200, nullptr, "CancelSyncDeliveryCacheRequest"},
35 {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"},
36 {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"},
37 {20300, nullptr, "GetDeliveryCacheStorageUpdateNotifier"},
38 {20301, nullptr, "RequestSuspendDeliveryTask"},
39 {20400, nullptr, "RegisterSystemApplicationDeliveryTask"},
40 {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
41 {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"},
42 {30100, D<&IBcatService::SetPassphrase>, "SetPassphrase"},
43 {30101, nullptr, "Unknown30101"},
44 {30102, nullptr, "Unknown30102"},
45 {30200, nullptr, "RegisterBackgroundDeliveryTask"},
46 {30201, nullptr, "UnregisterBackgroundDeliveryTask"},
47 {30202, nullptr, "BlockDeliveryTask"},
48 {30203, nullptr, "UnblockDeliveryTask"},
49 {30210, nullptr, "SetDeliveryTaskTimer"},
50 {30300, D<&IBcatService::RegisterSystemApplicationDeliveryTasks>, "RegisterSystemApplicationDeliveryTasks"},
51 {90100, nullptr, "EnumerateBackgroundDeliveryTask"},
52 {90101, nullptr, "Unknown90101"},
53 {90200, nullptr, "GetDeliveryList"},
54 {90201, D<&IBcatService::ClearDeliveryCacheStorage>, "ClearDeliveryCacheStorage"},
55 {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
56 {90300, nullptr, "GetPushNotificationLog"},
57 {90301, nullptr, "Unknown90301"},
58 };
59 // clang-format on
60 RegisterHandlers(functions);
61}
62
63IBcatService::~IBcatService() = default;
64
65Result IBcatService::RequestSyncDeliveryCache(
66 OutInterface<IDeliveryCacheProgressService> out_interface) {
67 LOG_DEBUG(Service_BCAT, "called");
68
69 auto& progress_backend{GetProgressBackend(SyncType::Normal)};
70 backend.Synchronize({system.GetApplicationProcessProgramID(),
71 GetCurrentBuildID(system.GetApplicationProcessBuildID())},
72 GetProgressBackend(SyncType::Normal));
73
74 *out_interface = std::make_shared<IDeliveryCacheProgressService>(
75 system, progress_backend.GetEvent(), progress_backend.GetImpl());
76 R_SUCCEED();
77}
78
79Result IBcatService::RequestSyncDeliveryCacheWithDirectoryName(
80 const DirectoryName& name_raw, OutInterface<IDeliveryCacheProgressService> out_interface) {
81 const auto name = Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size());
82
83 LOG_DEBUG(Service_BCAT, "called, name={}", name);
84
85 auto& progress_backend{GetProgressBackend(SyncType::Directory)};
86 backend.SynchronizeDirectory({system.GetApplicationProcessProgramID(),
87 GetCurrentBuildID(system.GetApplicationProcessBuildID())},
88 name, progress_backend);
89
90 *out_interface = std::make_shared<IDeliveryCacheProgressService>(
91 system, progress_backend.GetEvent(), progress_backend.GetImpl());
92 R_SUCCEED();
93}
94
95Result IBcatService::SetPassphrase(u64 application_id,
96 InBuffer<BufferAttr_HipcPointer> passphrase_buffer) {
97 LOG_DEBUG(Service_BCAT, "called, application_id={:016X}, passphrase={}", application_id,
98 Common::HexToString(passphrase_buffer));
99
100 R_UNLESS(application_id != 0, ResultInvalidArgument);
101 R_UNLESS(passphrase_buffer.size() <= 0x40, ResultInvalidArgument);
102
103 Passphrase passphrase{};
104 std::memcpy(passphrase.data(), passphrase_buffer.data(),
105 std::min(passphrase.size(), passphrase_buffer.size()));
106
107 backend.SetPassphrase(application_id, passphrase);
108 R_SUCCEED();
109}
110
111Result IBcatService::RegisterSystemApplicationDeliveryTasks() {
112 LOG_WARNING(Service_BCAT, "(STUBBED) called");
113 R_SUCCEED();
114}
115
116Result IBcatService::ClearDeliveryCacheStorage(u64 application_id) {
117 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", application_id);
118
119 R_UNLESS(application_id != 0, ResultInvalidArgument);
120 R_UNLESS(backend.Clear(application_id), FileSys::ResultPermissionDenied);
121 R_SUCCEED();
122}
123
124ProgressServiceBackend& IBcatService::GetProgressBackend(SyncType type) {
125 return progress.at(static_cast<size_t>(type));
126}
127
128const ProgressServiceBackend& IBcatService::GetProgressBackend(SyncType type) const {
129 return progress.at(static_cast<size_t>(type));
130}
131
132} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_service.h b/src/core/hle/service/bcat/bcat_service.h
new file mode 100644
index 000000000..dda5a2d5f
--- /dev/null
+++ b/src/core/hle/service/bcat/bcat_service.h
@@ -0,0 +1,45 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/bcat/backend/backend.h"
7#include "core/hle/service/bcat/bcat_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::BCAT {
16class BcatBackend;
17class IDeliveryCacheStorageService;
18class IDeliveryCacheProgressService;
19
20class IBcatService final : public ServiceFramework<IBcatService> {
21public:
22 explicit IBcatService(Core::System& system_, BcatBackend& backend_);
23 ~IBcatService() override;
24
25private:
26 Result RequestSyncDeliveryCache(OutInterface<IDeliveryCacheProgressService> out_interface);
27
28 Result RequestSyncDeliveryCacheWithDirectoryName(
29 const DirectoryName& name, OutInterface<IDeliveryCacheProgressService> out_interface);
30
31 Result SetPassphrase(u64 application_id, InBuffer<BufferAttr_HipcPointer> passphrase_buffer);
32
33 Result RegisterSystemApplicationDeliveryTasks();
34
35 Result ClearDeliveryCacheStorage(u64 application_id);
36
37private:
38 ProgressServiceBackend& GetProgressBackend(SyncType type);
39 const ProgressServiceBackend& GetProgressBackend(SyncType type) const;
40
41 BcatBackend& backend;
42 std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
43};
44
45} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_types.h b/src/core/hle/service/bcat/bcat_types.h
new file mode 100644
index 000000000..b35dab7c5
--- /dev/null
+++ b/src/core/hle/service/bcat/bcat_types.h
@@ -0,0 +1,66 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <functional>
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11#include "core/file_sys/vfs/vfs_types.h"
12#include "core/hle/result.h"
13
14namespace Service::BCAT {
15
16using DirectoryName = std::array<char, 0x20>;
17using FileName = std::array<char, 0x20>;
18using BcatDigest = std::array<u8, 0x10>;
19using Passphrase = std::array<u8, 0x20>;
20using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>;
21
22enum class SyncType {
23 Normal,
24 Directory,
25 Count,
26};
27
28enum class DeliveryCacheProgressStatus : s32 {
29 None = 0x0,
30 Queued = 0x1,
31 Connecting = 0x2,
32 ProcessingDataList = 0x3,
33 Downloading = 0x4,
34 Committing = 0x5,
35 Done = 0x9,
36};
37
38struct DeliveryCacheDirectoryEntry {
39 FileName name;
40 u64 size;
41 BcatDigest digest;
42};
43
44struct TitleIDVersion {
45 u64 title_id;
46 u64 build_id;
47};
48
49struct DeliveryCacheProgressImpl {
50 DeliveryCacheProgressStatus status;
51 Result result;
52 DirectoryName current_directory;
53 FileName current_file;
54 s64 current_downloaded_bytes; ///< Bytes downloaded on current file.
55 s64 current_total_bytes; ///< Bytes total on current file.
56 s64 total_downloaded_bytes; ///< Bytes downloaded on overall download.
57 s64 total_bytes; ///< Bytes total on overall download.
58 INSERT_PADDING_BYTES_NOINIT(
59 0x198); ///< Appears to be unused in official code, possibly reserved for future use.
60};
61static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200,
62 "DeliveryCacheProgressImpl has incorrect size.");
63static_assert(std::is_trivial_v<DeliveryCacheProgressImpl>,
64 "DeliveryCacheProgressImpl type must be trivially copyable.");
65
66} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_util.h b/src/core/hle/service/bcat/bcat_util.h
new file mode 100644
index 000000000..6bf2657ee
--- /dev/null
+++ b/src/core/hle/service/bcat/bcat_util.h
@@ -0,0 +1,39 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <cctype>
8#include <mbedtls/md5.h>
9
10#include "core/hle/service/bcat/bcat_result.h"
11#include "core/hle/service/bcat/bcat_types.h"
12
13namespace Service::BCAT {
14
15// For a name to be valid it must be non-empty, must have a null terminating character as the final
16// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if
17// file.
18constexpr Result VerifyNameValidInternal(std::array<char, 0x20> name, char match_char) {
19 const auto null_chars = std::count(name.begin(), name.end(), 0);
20 const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) {
21 return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0';
22 });
23 if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') {
24 LOG_ERROR(Service_BCAT, "Name passed was invalid!");
25 return ResultInvalidArgument;
26 }
27
28 return ResultSuccess;
29}
30
31constexpr Result VerifyNameValidDir(DirectoryName name) {
32 return VerifyNameValidInternal(name, '-');
33}
34
35constexpr Result VerifyNameValidFile(FileName name) {
36 return VerifyNameValidInternal(name, '.');
37}
38
39} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_directory_service.cpp b/src/core/hle/service/bcat/delivery_cache_directory_service.cpp
new file mode 100644
index 000000000..01f08a2fc
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_directory_service.cpp
@@ -0,0 +1,80 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/string_util.h"
5#include "core/file_sys/vfs/vfs_types.h"
6#include "core/hle/service/bcat/bcat_result.h"
7#include "core/hle/service/bcat/bcat_util.h"
8#include "core/hle/service/bcat/delivery_cache_directory_service.h"
9#include "core/hle/service/cmif_serialization.h"
10
11namespace Service::BCAT {
12
13// The digest is only used to determine if a file is unique compared to others of the same name.
14// Since the algorithm isn't ever checked in game, MD5 is safe.
15static BcatDigest DigestFile(const FileSys::VirtualFile& file) {
16 BcatDigest out{};
17 const auto bytes = file->ReadAllBytes();
18 mbedtls_md5_ret(bytes.data(), bytes.size(), out.data());
19 return out;
20}
21
22IDeliveryCacheDirectoryService::IDeliveryCacheDirectoryService(Core::System& system_,
23 FileSys::VirtualDir root_)
24 : ServiceFramework{system_, "IDeliveryCacheDirectoryService"}, root(std::move(root_)) {
25 // clang-format off
26 static const FunctionInfo functions[] = {
27 {0, D<&IDeliveryCacheDirectoryService::Open>, "Open"},
28 {1, D<&IDeliveryCacheDirectoryService::Read>, "Read"},
29 {2, D<&IDeliveryCacheDirectoryService::GetCount>, "GetCount"},
30 };
31 // clang-format on
32
33 RegisterHandlers(functions);
34}
35
36IDeliveryCacheDirectoryService::~IDeliveryCacheDirectoryService() = default;
37
38Result IDeliveryCacheDirectoryService::Open(const DirectoryName& dir_name_raw) {
39 const auto dir_name =
40 Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size());
41
42 LOG_DEBUG(Service_BCAT, "called, dir_name={}", dir_name);
43
44 R_TRY(VerifyNameValidDir(dir_name_raw));
45 R_UNLESS(current_dir == nullptr, ResultEntityAlreadyOpen);
46
47 const auto dir = root->GetSubdirectory(dir_name);
48 R_UNLESS(dir != nullptr, ResultFailedOpenEntity);
49
50 R_SUCCEED();
51}
52
53Result IDeliveryCacheDirectoryService::Read(
54 Out<s32> out_count, OutArray<DeliveryCacheDirectoryEntry, BufferAttr_HipcMapAlias> out_buffer) {
55 LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", out_buffer.size());
56
57 R_UNLESS(current_dir != nullptr, ResultNoOpenEntry);
58
59 const auto files = current_dir->GetFiles();
60 *out_count = static_cast<s32>(std::min(files.size(), out_buffer.size()));
61 std::transform(files.begin(), files.begin() + *out_count, out_buffer.begin(),
62 [](const auto& file) {
63 FileName name{};
64 std::memcpy(name.data(), file->GetName().data(),
65 std::min(file->GetName().size(), name.size()));
66 return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)};
67 });
68 R_SUCCEED();
69}
70
71Result IDeliveryCacheDirectoryService::GetCount(Out<s32> out_count) {
72 LOG_DEBUG(Service_BCAT, "called");
73
74 R_UNLESS(current_dir != nullptr, ResultNoOpenEntry);
75
76 *out_count = static_cast<s32>(current_dir->GetFiles().size());
77 R_SUCCEED();
78}
79
80} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_directory_service.h b/src/core/hle/service/bcat/delivery_cache_directory_service.h
new file mode 100644
index 000000000..b902c6495
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_directory_service.h
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/bcat/bcat_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::BCAT {
16
17class IDeliveryCacheDirectoryService final
18 : public ServiceFramework<IDeliveryCacheDirectoryService> {
19public:
20 explicit IDeliveryCacheDirectoryService(Core::System& system_, FileSys::VirtualDir root_);
21 ~IDeliveryCacheDirectoryService() override;
22
23private:
24 Result Open(const DirectoryName& dir_name_raw);
25 Result Read(Out<s32> out_count,
26 OutArray<DeliveryCacheDirectoryEntry, BufferAttr_HipcMapAlias> out_buffer);
27 Result GetCount(Out<s32> out_count);
28
29 FileSys::VirtualDir root;
30 FileSys::VirtualDir current_dir;
31};
32
33} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_file_service.cpp b/src/core/hle/service/bcat/delivery_cache_file_service.cpp
new file mode 100644
index 000000000..b75fac4bf
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_file_service.cpp
@@ -0,0 +1,82 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/bcat/bcat_result.h"
6#include "core/hle/service/bcat/bcat_util.h"
7#include "core/hle/service/bcat/delivery_cache_file_service.h"
8#include "core/hle/service/cmif_serialization.h"
9
10namespace Service::BCAT {
11
12IDeliveryCacheFileService::IDeliveryCacheFileService(Core::System& system_,
13 FileSys::VirtualDir root_)
14 : ServiceFramework{system_, "IDeliveryCacheFileService"}, root(std::move(root_)) {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IDeliveryCacheFileService::Open>, "Open"},
18 {1, D<&IDeliveryCacheFileService::Read>, "Read"},
19 {2, D<&IDeliveryCacheFileService::GetSize>, "GetSize"},
20 {3, D<&IDeliveryCacheFileService::GetDigest>, "GetDigest"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25}
26
27IDeliveryCacheFileService::~IDeliveryCacheFileService() = default;
28
29Result IDeliveryCacheFileService::Open(const DirectoryName& dir_name_raw,
30 const FileName& file_name_raw) {
31 const auto dir_name =
32 Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size());
33 const auto file_name =
34 Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size());
35
36 LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name);
37
38 R_TRY(VerifyNameValidDir(dir_name_raw));
39 R_TRY(VerifyNameValidDir(file_name_raw));
40 R_UNLESS(current_file == nullptr, ResultEntityAlreadyOpen);
41
42 const auto dir = root->GetSubdirectory(dir_name);
43 R_UNLESS(dir != nullptr, ResultFailedOpenEntity);
44
45 current_file = dir->GetFile(file_name);
46 R_UNLESS(current_file != nullptr, ResultFailedOpenEntity);
47
48 R_SUCCEED();
49}
50
51Result IDeliveryCacheFileService::Read(Out<u64> out_buffer_size, u64 offset,
52 OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
53 LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, out_buffer.size());
54
55 R_UNLESS(current_file != nullptr, ResultNoOpenEntry);
56
57 *out_buffer_size = std::min<u64>(current_file->GetSize() - offset, out_buffer.size());
58 const auto buffer = current_file->ReadBytes(*out_buffer_size, offset);
59 memcpy(out_buffer.data(), buffer.data(), buffer.size());
60
61 R_SUCCEED();
62}
63
64Result IDeliveryCacheFileService::GetSize(Out<u64> out_size) {
65 LOG_DEBUG(Service_BCAT, "called");
66
67 R_UNLESS(current_file != nullptr, ResultNoOpenEntry);
68
69 *out_size = current_file->GetSize();
70 R_SUCCEED();
71}
72
73Result IDeliveryCacheFileService::GetDigest(Out<BcatDigest> out_digest) {
74 LOG_DEBUG(Service_BCAT, "called");
75
76 R_UNLESS(current_file != nullptr, ResultNoOpenEntry);
77
78 //*out_digest = DigestFile(current_file);
79 R_SUCCEED();
80}
81
82} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_file_service.h b/src/core/hle/service/bcat/delivery_cache_file_service.h
new file mode 100644
index 000000000..e1012e687
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_file_service.h
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/bcat/bcat_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::BCAT {
16
17class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
18public:
19 explicit IDeliveryCacheFileService(Core::System& system_, FileSys::VirtualDir root_);
20 ~IDeliveryCacheFileService() override;
21
22private:
23 Result Open(const DirectoryName& dir_name_raw, const FileName& file_name_raw);
24 Result Read(Out<u64> out_buffer_size, u64 offset,
25 OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
26 Result GetSize(Out<u64> out_size);
27 Result GetDigest(Out<BcatDigest> out_digest);
28
29 FileSys::VirtualDir root;
30 FileSys::VirtualFile current_file;
31};
32
33} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_progress_service.cpp b/src/core/hle/service/bcat/delivery_cache_progress_service.cpp
new file mode 100644
index 000000000..79e7e0d95
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_progress_service.cpp
@@ -0,0 +1,41 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/bcat_types.h"
5#include "core/hle/service/bcat/delivery_cache_progress_service.h"
6#include "core/hle/service/cmif_serialization.h"
7
8namespace Service::BCAT {
9
10IDeliveryCacheProgressService::IDeliveryCacheProgressService(Core::System& system_,
11 Kernel::KReadableEvent& event_,
12 const DeliveryCacheProgressImpl& impl_)
13 : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IDeliveryCacheProgressService::GetEvent>, "Get"},
17 {1, D<&IDeliveryCacheProgressService::GetImpl>, "Get"},
18 };
19 // clang-format on
20
21 RegisterHandlers(functions);
22}
23
24IDeliveryCacheProgressService::~IDeliveryCacheProgressService() = default;
25
26Result IDeliveryCacheProgressService::GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
27 LOG_DEBUG(Service_BCAT, "called");
28
29 *out_event = &event;
30 R_SUCCEED();
31}
32
33Result IDeliveryCacheProgressService::GetImpl(
34 OutLargeData<DeliveryCacheProgressImpl, BufferAttr_HipcPointer> out_impl) {
35 LOG_DEBUG(Service_BCAT, "called");
36
37 *out_impl = impl;
38 R_SUCCEED();
39}
40
41} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_progress_service.h b/src/core/hle/service/bcat/delivery_cache_progress_service.h
new file mode 100644
index 000000000..f81a13980
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_progress_service.h
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Kernel {
14class KEvent;
15class KReadableEvent;
16} // namespace Kernel
17
18namespace Service::BCAT {
19struct DeliveryCacheProgressImpl;
20
21class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
22public:
23 explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_,
24 const DeliveryCacheProgressImpl& impl_);
25 ~IDeliveryCacheProgressService() override;
26
27private:
28 Result GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
29 Result GetImpl(OutLargeData<DeliveryCacheProgressImpl, BufferAttr_HipcPointer> out_impl);
30
31 Kernel::KReadableEvent& event;
32 const DeliveryCacheProgressImpl& impl;
33};
34
35} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_storage_service.cpp b/src/core/hle/service/bcat/delivery_cache_storage_service.cpp
new file mode 100644
index 000000000..4c79d71f4
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_storage_service.cpp
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/bcat_result.h"
5#include "core/hle/service/bcat/delivery_cache_directory_service.h"
6#include "core/hle/service/bcat/delivery_cache_file_service.h"
7#include "core/hle/service/bcat/delivery_cache_storage_service.h"
8#include "core/hle/service/cmif_serialization.h"
9
10namespace Service::BCAT {
11
12IDeliveryCacheStorageService::IDeliveryCacheStorageService(Core::System& system_,
13 FileSys::VirtualDir root_)
14 : ServiceFramework{system_, "IDeliveryCacheStorageService"}, root(std::move(root_)) {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IDeliveryCacheStorageService::CreateFileService>, "CreateFileService"},
18 {1, D<&IDeliveryCacheStorageService::CreateDirectoryService>, "CreateDirectoryService"},
19 {10, D<&IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory>, "EnumerateDeliveryCacheDirectory"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26IDeliveryCacheStorageService::~IDeliveryCacheStorageService() = default;
27
28Result IDeliveryCacheStorageService::CreateFileService(
29 OutInterface<IDeliveryCacheFileService> out_interface) {
30 LOG_DEBUG(Service_BCAT, "called");
31
32 *out_interface = std::make_shared<IDeliveryCacheFileService>(system, root);
33 R_SUCCEED();
34}
35
36Result IDeliveryCacheStorageService::CreateDirectoryService(
37 OutInterface<IDeliveryCacheDirectoryService> out_interface) {
38 LOG_DEBUG(Service_BCAT, "called");
39
40 *out_interface = std::make_shared<IDeliveryCacheDirectoryService>(system, root);
41 R_SUCCEED();
42}
43
44Result IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory(
45 Out<s32> out_directory_count,
46 OutArray<DirectoryName, BufferAttr_HipcMapAlias> out_directories) {
47 LOG_DEBUG(Service_BCAT, "called, size={:016X}", out_directories.size());
48
49 *out_directory_count =
50 static_cast<s32>(std::min(out_directories.size(), entries.size() - next_read_index));
51 memcpy(out_directories.data(), entries.data() + next_read_index,
52 *out_directory_count * sizeof(DirectoryName));
53 next_read_index += *out_directory_count;
54 R_SUCCEED();
55}
56
57} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/delivery_cache_storage_service.h b/src/core/hle/service/bcat/delivery_cache_storage_service.h
new file mode 100644
index 000000000..3b8dfb1a3
--- /dev/null
+++ b/src/core/hle/service/bcat/delivery_cache_storage_service.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/bcat/bcat_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::BCAT {
16class IDeliveryCacheFileService;
17class IDeliveryCacheDirectoryService;
18
19class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> {
20public:
21 explicit IDeliveryCacheStorageService(Core::System& system_, FileSys::VirtualDir root_);
22 ~IDeliveryCacheStorageService() override;
23
24private:
25 Result CreateFileService(OutInterface<IDeliveryCacheFileService> out_interface);
26 Result CreateDirectoryService(OutInterface<IDeliveryCacheDirectoryService> out_interface);
27 Result EnumerateDeliveryCacheDirectory(
28 Out<s32> out_directory_count,
29 OutArray<DirectoryName, BufferAttr_HipcMapAlias> out_directories);
30
31 FileSys::VirtualDir root;
32 std::vector<DirectoryName> entries;
33 std::size_t next_read_index = 0;
34};
35
36} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp b/src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp
new file mode 100644
index 000000000..5be167fce
--- /dev/null
+++ b/src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp
@@ -0,0 +1,34 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/news/newly_arrived_event_holder.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::News {
8
9INewlyArrivedEventHolder::INewlyArrivedEventHolder(Core::System& system_)
10 : ServiceFramework{system_, "INewlyArrivedEventHolder"}, service_context{
11 system_,
12 "INewlyArrivedEventHolder"} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, C<&INewlyArrivedEventHolder::Get>, "Get"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20 arrived_event = service_context.CreateEvent("INewlyArrivedEventHolder::ArrivedEvent");
21}
22
23INewlyArrivedEventHolder::~INewlyArrivedEventHolder() {
24 service_context.CloseEvent(arrived_event);
25}
26
27Result INewlyArrivedEventHolder::Get(OutCopyHandle<Kernel::KReadableEvent> out_event) {
28 LOG_INFO(Service_BCAT, "called");
29
30 *out_event = &arrived_event->GetReadableEvent();
31 R_SUCCEED();
32}
33
34} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/newly_arrived_event_holder.h b/src/core/hle/service/bcat/news/newly_arrived_event_holder.h
new file mode 100644
index 000000000..6cc9ae099
--- /dev/null
+++ b/src/core/hle/service/bcat/news/newly_arrived_event_holder.h
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Core {
11class System;
12}
13
14namespace Kernel {
15class KEvent;
16class KReadableEvent;
17} // namespace Kernel
18
19namespace Service::News {
20
21class INewlyArrivedEventHolder final : public ServiceFramework<INewlyArrivedEventHolder> {
22public:
23 explicit INewlyArrivedEventHolder(Core::System& system_);
24 ~INewlyArrivedEventHolder() override;
25
26private:
27 Result Get(OutCopyHandle<Kernel::KReadableEvent> out_event);
28
29 Kernel::KEvent* arrived_event;
30 KernelHelpers::ServiceContext service_context;
31};
32
33} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_data_service.cpp b/src/core/hle/service/bcat/news/news_data_service.cpp
new file mode 100644
index 000000000..08103c9c3
--- /dev/null
+++ b/src/core/hle/service/bcat/news/news_data_service.cpp
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/news/news_data_service.h"
5
6namespace Service::News {
7
8INewsDataService::INewsDataService(Core::System& system_)
9 : ServiceFramework{system_, "INewsDataService"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "Open"},
13 {1, nullptr, "OpenWithNewsRecordV1"},
14 {2, nullptr, "Read"},
15 {3, nullptr, "GetSize"},
16 {1001, nullptr, "OpenWithNewsRecord"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21}
22
23INewsDataService::~INewsDataService() = default;
24
25} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_data_service.h b/src/core/hle/service/bcat/news/news_data_service.h
new file mode 100644
index 000000000..12082ada4
--- /dev/null
+++ b/src/core/hle/service/bcat/news/news_data_service.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core {
9class System;
10}
11
12namespace Service::News {
13
14class INewsDataService final : public ServiceFramework<INewsDataService> {
15public:
16 explicit INewsDataService(Core::System& system_);
17 ~INewsDataService() override;
18};
19
20} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_database_service.cpp b/src/core/hle/service/bcat/news/news_database_service.cpp
new file mode 100644
index 000000000..18109f9b0
--- /dev/null
+++ b/src/core/hle/service/bcat/news/news_database_service.cpp
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/news/news_database_service.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::News {
8
9INewsDatabaseService::INewsDatabaseService(Core::System& system_)
10 : ServiceFramework{system_, "INewsDatabaseService"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "GetListV1"},
14 {1, C<&INewsDatabaseService::Count>, "Count"},
15 {2, nullptr, "CountWithKey"},
16 {3, nullptr, "UpdateIntegerValue"},
17 {4, nullptr, "UpdateIntegerValueWithAddition"},
18 {5, nullptr, "UpdateStringValue"},
19 {1000, nullptr, "GetList"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26INewsDatabaseService::~INewsDatabaseService() = default;
27
28Result INewsDatabaseService::Count(Out<s32> out_count,
29 InBuffer<BufferAttr_HipcPointer> buffer_data) {
30 LOG_WARNING(Service_BCAT, "(STUBBED) called, buffer_size={}", buffer_data.size());
31 *out_count = 0;
32 R_SUCCEED();
33}
34
35} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_database_service.h b/src/core/hle/service/bcat/news/news_database_service.h
new file mode 100644
index 000000000..f5916634b
--- /dev/null
+++ b/src/core/hle/service/bcat/news/news_database_service.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::News {
14
15class INewsDatabaseService final : public ServiceFramework<INewsDatabaseService> {
16public:
17 explicit INewsDatabaseService(Core::System& system_);
18 ~INewsDatabaseService() override;
19
20private:
21 Result Count(Out<s32> out_count, InBuffer<BufferAttr_HipcPointer> buffer_data);
22};
23
24} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_service.cpp b/src/core/hle/service/bcat/news/news_service.cpp
new file mode 100644
index 000000000..e19cea7b5
--- /dev/null
+++ b/src/core/hle/service/bcat/news/news_service.cpp
@@ -0,0 +1,46 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/news/news_service.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::News {
8
9INewsService::INewsService(Core::System& system_) : ServiceFramework{system_, "INewsService"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {10100, nullptr, "PostLocalNews"},
13 {20100, nullptr, "SetPassphrase"},
14 {30100, C<&INewsService::GetSubscriptionStatus>, "GetSubscriptionStatus"},
15 {30101, nullptr, "GetTopicList"},
16 {30110, nullptr, "Unknown30110"},
17 {30200, nullptr, "IsSystemUpdateRequired"},
18 {30201, nullptr, "Unknown30201"},
19 {30210, nullptr, "Unknown30210"},
20 {30300, nullptr, "RequestImmediateReception"},
21 {30400, nullptr, "DecodeArchiveFile"},
22 {30500, nullptr, "Unknown30500"},
23 {30900, nullptr, "Unknown30900"},
24 {30901, nullptr, "Unknown30901"},
25 {30902, nullptr, "Unknown30902"},
26 {40100, nullptr, "SetSubscriptionStatus"},
27 {40101, nullptr, "RequestAutoSubscription"},
28 {40200, nullptr, "ClearStorage"},
29 {40201, nullptr, "ClearSubscriptionStatusAll"},
30 {90100, nullptr, "GetNewsDatabaseDump"},
31 };
32 // clang-format on
33
34 RegisterHandlers(functions);
35}
36
37INewsService::~INewsService() = default;
38
39Result INewsService::GetSubscriptionStatus(Out<u32> out_status,
40 InBuffer<BufferAttr_HipcPointer> buffer_data) {
41 LOG_WARNING(Service_BCAT, "(STUBBED) called, buffer_size={}", buffer_data.size());
42 *out_status = 0;
43 R_SUCCEED();
44}
45
46} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_service.h b/src/core/hle/service/bcat/news/news_service.h
new file mode 100644
index 000000000..8d06be9d6
--- /dev/null
+++ b/src/core/hle/service/bcat/news/news_service.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::News {
14
15class INewsService final : public ServiceFramework<INewsService> {
16public:
17 explicit INewsService(Core::System& system_);
18 ~INewsService() override;
19
20private:
21 Result GetSubscriptionStatus(Out<u32> out_status, InBuffer<BufferAttr_HipcPointer> buffer_data);
22};
23
24} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/overwrite_event_holder.cpp b/src/core/hle/service/bcat/news/overwrite_event_holder.cpp
new file mode 100644
index 000000000..c32a5ca8f
--- /dev/null
+++ b/src/core/hle/service/bcat/news/overwrite_event_holder.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/news/overwrite_event_holder.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::News {
8
9IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_)
10 : ServiceFramework{system_, "IOverwriteEventHolder"}, service_context{system_,
11 "IOverwriteEventHolder"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, C<&IOverwriteEventHolder::Get>, "Get"},
15 };
16 // clang-format on
17
18 RegisterHandlers(functions);
19 overwrite_event = service_context.CreateEvent("IOverwriteEventHolder::OverwriteEvent");
20}
21
22IOverwriteEventHolder::~IOverwriteEventHolder() {
23 service_context.CloseEvent(overwrite_event);
24}
25
26Result IOverwriteEventHolder::Get(OutCopyHandle<Kernel::KReadableEvent> out_event) {
27 LOG_INFO(Service_BCAT, "called");
28
29 *out_event = &overwrite_event->GetReadableEvent();
30 R_SUCCEED();
31}
32
33} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/overwrite_event_holder.h b/src/core/hle/service/bcat/news/overwrite_event_holder.h
new file mode 100644
index 000000000..cdc87d782
--- /dev/null
+++ b/src/core/hle/service/bcat/news/overwrite_event_holder.h
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Core {
11class System;
12}
13
14namespace Kernel {
15class KEvent;
16class KReadableEvent;
17} // namespace Kernel
18
19namespace Service::News {
20
21class IOverwriteEventHolder final : public ServiceFramework<IOverwriteEventHolder> {
22public:
23 explicit IOverwriteEventHolder(Core::System& system_);
24 ~IOverwriteEventHolder() override;
25
26private:
27 Result Get(OutCopyHandle<Kernel::KReadableEvent> out_event);
28
29 Kernel::KEvent* overwrite_event;
30 KernelHelpers::ServiceContext service_context;
31};
32
33} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/service_creator.cpp b/src/core/hle/service/bcat/news/service_creator.cpp
new file mode 100644
index 000000000..d5ba5dff7
--- /dev/null
+++ b/src/core/hle/service/bcat/news/service_creator.cpp
@@ -0,0 +1,64 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/bcat/news/newly_arrived_event_holder.h"
5#include "core/hle/service/bcat/news/news_data_service.h"
6#include "core/hle/service/bcat/news/news_database_service.h"
7#include "core/hle/service/bcat/news/news_service.h"
8#include "core/hle/service/bcat/news/overwrite_event_holder.h"
9#include "core/hle/service/bcat/news/service_creator.h"
10#include "core/hle/service/cmif_serialization.h"
11
12namespace Service::News {
13
14IServiceCreator::IServiceCreator(Core::System& system_, u32 permissions_, const char* name_)
15 : ServiceFramework{system_, name_}, permissions{permissions_} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, C<&IServiceCreator::CreateNewsService>, "CreateNewsService"},
19 {1, C<&IServiceCreator::CreateNewlyArrivedEventHolder>, "CreateNewlyArrivedEventHolder"},
20 {2, C<&IServiceCreator::CreateNewsDataService>, "CreateNewsDataService"},
21 {3, C<&IServiceCreator::CreateNewsDatabaseService>, "CreateNewsDatabaseService"},
22 {4, C<&IServiceCreator::CreateOverwriteEventHolder>, "CreateOverwriteEventHolder"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27}
28
29IServiceCreator::~IServiceCreator() = default;
30
31Result IServiceCreator::CreateNewsService(OutInterface<INewsService> out_interface) {
32 LOG_INFO(Service_BCAT, "called");
33 *out_interface = std::make_shared<INewsService>(system);
34 R_SUCCEED();
35}
36
37Result IServiceCreator::CreateNewlyArrivedEventHolder(
38 OutInterface<INewlyArrivedEventHolder> out_interface) {
39 LOG_INFO(Service_BCAT, "called");
40 *out_interface = std::make_shared<INewlyArrivedEventHolder>(system);
41 R_SUCCEED();
42}
43
44Result IServiceCreator::CreateNewsDataService(OutInterface<INewsDataService> out_interface) {
45 LOG_INFO(Service_BCAT, "called");
46 *out_interface = std::make_shared<INewsDataService>(system);
47 R_SUCCEED();
48}
49
50Result IServiceCreator::CreateNewsDatabaseService(
51 OutInterface<INewsDatabaseService> out_interface) {
52 LOG_INFO(Service_BCAT, "called");
53 *out_interface = std::make_shared<INewsDatabaseService>(system);
54 R_SUCCEED();
55}
56
57Result IServiceCreator::CreateOverwriteEventHolder(
58 OutInterface<IOverwriteEventHolder> out_interface) {
59 LOG_INFO(Service_BCAT, "called");
60 *out_interface = std::make_shared<IOverwriteEventHolder>(system);
61 R_SUCCEED();
62}
63
64} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/service_creator.h b/src/core/hle/service/bcat/news/service_creator.h
new file mode 100644
index 000000000..5a62e7c1a
--- /dev/null
+++ b/src/core/hle/service/bcat/news/service_creator.h
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::News {
14class INewsService;
15class INewlyArrivedEventHolder;
16class INewsDataService;
17class INewsDatabaseService;
18class IOverwriteEventHolder;
19
20class IServiceCreator final : public ServiceFramework<IServiceCreator> {
21public:
22 explicit IServiceCreator(Core::System& system_, u32 permissions_, const char* name_);
23 ~IServiceCreator() override;
24
25private:
26 Result CreateNewsService(OutInterface<INewsService> out_interface);
27 Result CreateNewlyArrivedEventHolder(OutInterface<INewlyArrivedEventHolder> out_interface);
28 Result CreateNewsDataService(OutInterface<INewsDataService> out_interface);
29 Result CreateNewsDatabaseService(OutInterface<INewsDatabaseService> out_interface);
30 Result CreateOverwriteEventHolder(OutInterface<IOverwriteEventHolder> out_interface);
31
32 u32 permissions;
33};
34
35} // namespace Service::News
diff --git a/src/core/hle/service/bcat/service_creator.cpp b/src/core/hle/service/bcat/service_creator.cpp
new file mode 100644
index 000000000..ca339e5a6
--- /dev/null
+++ b/src/core/hle/service/bcat/service_creator.cpp
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/bcat/bcat_service.h"
5#include "core/hle/service/bcat/delivery_cache_storage_service.h"
6#include "core/hle/service/bcat/service_creator.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/filesystem/filesystem.h"
9
10namespace Service::BCAT {
11
12std::unique_ptr<BcatBackend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
13 DirectoryGetter getter) {
14 return std::make_unique<NullBcatBackend>(std::move(getter));
15}
16
17IServiceCreator::IServiceCreator(Core::System& system_, const char* name_)
18 : ServiceFramework{system_, name_}, fsc{system.GetFileSystemController()} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IServiceCreator::CreateBcatService>, "CreateBcatService"},
22 {1, D<&IServiceCreator::CreateDeliveryCacheStorageService>, "CreateDeliveryCacheStorageService"},
23 {2, D<&IServiceCreator::CreateDeliveryCacheStorageServiceWithApplicationId>, "CreateDeliveryCacheStorageServiceWithApplicationId"},
24 {3, nullptr, "CreateDeliveryCacheProgressService"},
25 {4, nullptr, "CreateDeliveryCacheProgressServiceWithApplicationId"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30
31 backend =
32 CreateBackendFromSettings(system_, [this](u64 tid) { return fsc.GetBCATDirectory(tid); });
33}
34
35IServiceCreator::~IServiceCreator() = default;
36
37Result IServiceCreator::CreateBcatService(ClientProcessId process_id,
38 OutInterface<IBcatService> out_interface) {
39 LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
40 *out_interface = std::make_shared<IBcatService>(system, *backend);
41 R_SUCCEED();
42}
43
44Result IServiceCreator::CreateDeliveryCacheStorageService(
45 ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
46 LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
47
48 const auto title_id = system.GetApplicationProcessProgramID();
49 *out_interface =
50 std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
51 R_SUCCEED();
52}
53
54Result IServiceCreator::CreateDeliveryCacheStorageServiceWithApplicationId(
55 u64 application_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
56 LOG_DEBUG(Service_BCAT, "called, application_id={:016X}", application_id);
57 *out_interface = std::make_shared<IDeliveryCacheStorageService>(
58 system, fsc.GetBCATDirectory(application_id));
59 R_SUCCEED();
60}
61
62} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/service_creator.h b/src/core/hle/service/bcat/service_creator.h
new file mode 100644
index 000000000..50e663324
--- /dev/null
+++ b/src/core/hle/service/bcat/service_creator.h
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::FileSystem {
14class FileSystemController;
15}
16
17namespace Service::BCAT {
18class BcatBackend;
19class IBcatService;
20class IDeliveryCacheStorageService;
21
22class IServiceCreator final : public ServiceFramework<IServiceCreator> {
23public:
24 explicit IServiceCreator(Core::System& system_, const char* name_);
25 ~IServiceCreator() override;
26
27private:
28 Result CreateBcatService(ClientProcessId process_id, OutInterface<IBcatService> out_interface);
29
30 Result CreateDeliveryCacheStorageService(
31 ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface);
32
33 Result CreateDeliveryCacheStorageServiceWithApplicationId(
34 u64 application_id, OutInterface<IDeliveryCacheStorageService> out_interface);
35
36 std::unique_ptr<BcatBackend> backend;
37 Service::FileSystem::FileSystemController& fsc;
38};
39
40} // namespace Service::BCAT
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 06cbad268..f68c3c686 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -15,7 +15,7 @@
15#include "core/hle/service/aoc/aoc_u.h" 15#include "core/hle/service/aoc/aoc_u.h"
16#include "core/hle/service/apm/apm.h" 16#include "core/hle/service/apm/apm.h"
17#include "core/hle/service/audio/audio.h" 17#include "core/hle/service/audio/audio.h"
18#include "core/hle/service/bcat/bcat_module.h" 18#include "core/hle/service/bcat/bcat.h"
19#include "core/hle/service/bpc/bpc.h" 19#include "core/hle/service/bpc/bpc.h"
20#include "core/hle/service/btdrv/btdrv.h" 20#include "core/hle/service/btdrv/btdrv.h"
21#include "core/hle/service/btm/btm.h" 21#include "core/hle/service/btm/btm.h"