mii.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <memory>
  4. #include "common/logging/log.h"
  5. #include "core/hle/service/ipc_helpers.h"
  6. #include "core/hle/service/mii/mii.h"
  7. #include "core/hle/service/mii/mii_manager.h"
  8. #include "core/hle/service/server_manager.h"
  9. #include "core/hle/service/service.h"
  10. namespace Service::Mii {
  11. constexpr Result ERROR_INVALID_ARGUMENT{ErrorModule::Mii, 1};
  12. class IDatabaseService final : public ServiceFramework<IDatabaseService> {
  13. public:
  14. explicit IDatabaseService(Core::System& system_)
  15. : ServiceFramework{system_, "IDatabaseService"} {
  16. // clang-format off
  17. static const FunctionInfo functions[] = {
  18. {0, &IDatabaseService::IsUpdated, "IsUpdated"},
  19. {1, &IDatabaseService::IsFullDatabase, "IsFullDatabase"},
  20. {2, &IDatabaseService::GetCount, "GetCount"},
  21. {3, &IDatabaseService::Get, "Get"},
  22. {4, &IDatabaseService::Get1, "Get1"},
  23. {5, &IDatabaseService::UpdateLatest, "UpdateLatest"},
  24. {6, &IDatabaseService::BuildRandom, "BuildRandom"},
  25. {7, &IDatabaseService::BuildDefault, "BuildDefault"},
  26. {8, nullptr, "Get2"},
  27. {9, nullptr, "Get3"},
  28. {10, nullptr, "UpdateLatest1"},
  29. {11, nullptr, "FindIndex"},
  30. {12, nullptr, "Move"},
  31. {13, nullptr, "AddOrReplace"},
  32. {14, nullptr, "Delete"},
  33. {15, nullptr, "DestroyFile"},
  34. {16, nullptr, "DeleteFile"},
  35. {17, nullptr, "Format"},
  36. {18, nullptr, "Import"},
  37. {19, nullptr, "Export"},
  38. {20, nullptr, "IsBrokenDatabaseWithClearFlag"},
  39. {21, &IDatabaseService::GetIndex, "GetIndex"},
  40. {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
  41. {23, &IDatabaseService::Convert, "Convert"},
  42. {24, nullptr, "ConvertCoreDataToCharInfo"},
  43. {25, nullptr, "ConvertCharInfoToCoreData"},
  44. {26, nullptr, "Append"},
  45. };
  46. // clang-format on
  47. RegisterHandlers(functions);
  48. }
  49. private:
  50. template <typename T>
  51. std::vector<u8> SerializeArray(const std::vector<T>& values) {
  52. std::vector<u8> out(values.size() * sizeof(T));
  53. std::size_t offset{};
  54. for (const auto& value : values) {
  55. std::memcpy(out.data() + offset, &value, sizeof(T));
  56. offset += sizeof(T);
  57. }
  58. return out;
  59. }
  60. void IsUpdated(HLERequestContext& ctx) {
  61. IPC::RequestParser rp{ctx};
  62. const auto source_flag{rp.PopRaw<SourceFlag>()};
  63. LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
  64. IPC::ResponseBuilder rb{ctx, 3};
  65. rb.Push(ResultSuccess);
  66. rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter));
  67. }
  68. void IsFullDatabase(HLERequestContext& ctx) {
  69. LOG_DEBUG(Service_Mii, "called");
  70. IPC::ResponseBuilder rb{ctx, 3};
  71. rb.Push(ResultSuccess);
  72. rb.Push(manager.IsFullDatabase());
  73. }
  74. void GetCount(HLERequestContext& ctx) {
  75. IPC::RequestParser rp{ctx};
  76. const auto source_flag{rp.PopRaw<SourceFlag>()};
  77. LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
  78. IPC::ResponseBuilder rb{ctx, 3};
  79. rb.Push(ResultSuccess);
  80. rb.Push<u32>(manager.GetCount(source_flag));
  81. }
  82. void Get(HLERequestContext& ctx) {
  83. IPC::RequestParser rp{ctx};
  84. const auto source_flag{rp.PopRaw<SourceFlag>()};
  85. LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
  86. const auto default_miis{manager.GetDefault(source_flag)};
  87. if (default_miis.size() > 0) {
  88. ctx.WriteBuffer(SerializeArray(default_miis));
  89. }
  90. IPC::ResponseBuilder rb{ctx, 3};
  91. rb.Push(ResultSuccess);
  92. rb.Push<u32>(static_cast<u32>(default_miis.size()));
  93. }
  94. void Get1(HLERequestContext& ctx) {
  95. IPC::RequestParser rp{ctx};
  96. const auto source_flag{rp.PopRaw<SourceFlag>()};
  97. LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
  98. const auto default_miis{manager.GetDefault(source_flag)};
  99. std::vector<CharInfo> values;
  100. for (const auto& element : default_miis) {
  101. values.emplace_back(element.info);
  102. }
  103. ctx.WriteBuffer(SerializeArray(values));
  104. IPC::ResponseBuilder rb{ctx, 3};
  105. rb.Push(ResultSuccess);
  106. rb.Push<u32>(static_cast<u32>(default_miis.size()));
  107. }
  108. void UpdateLatest(HLERequestContext& ctx) {
  109. IPC::RequestParser rp{ctx};
  110. const auto info{rp.PopRaw<CharInfo>()};
  111. const auto source_flag{rp.PopRaw<SourceFlag>()};
  112. LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
  113. CharInfo new_char_info{};
  114. const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)};
  115. if (result != ResultSuccess) {
  116. IPC::ResponseBuilder rb{ctx, 2};
  117. rb.Push(result);
  118. return;
  119. }
  120. IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
  121. rb.Push(ResultSuccess);
  122. rb.PushRaw<CharInfo>(new_char_info);
  123. }
  124. void BuildRandom(HLERequestContext& ctx) {
  125. IPC::RequestParser rp{ctx};
  126. const auto age{rp.PopRaw<Age>()};
  127. const auto gender{rp.PopRaw<Gender>()};
  128. const auto race{rp.PopRaw<Race>()};
  129. LOG_DEBUG(Service_Mii, "called with age={}, gender={}, race={}", age, gender, race);
  130. if (age > Age::All) {
  131. IPC::ResponseBuilder rb{ctx, 2};
  132. rb.Push(ERROR_INVALID_ARGUMENT);
  133. LOG_ERROR(Service_Mii, "invalid age={}", age);
  134. return;
  135. }
  136. if (gender > Gender::All) {
  137. IPC::ResponseBuilder rb{ctx, 2};
  138. rb.Push(ERROR_INVALID_ARGUMENT);
  139. LOG_ERROR(Service_Mii, "invalid gender={}", gender);
  140. return;
  141. }
  142. if (race > Race::All) {
  143. IPC::ResponseBuilder rb{ctx, 2};
  144. rb.Push(ERROR_INVALID_ARGUMENT);
  145. LOG_ERROR(Service_Mii, "invalid race={}", race);
  146. return;
  147. }
  148. IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
  149. rb.Push(ResultSuccess);
  150. rb.PushRaw<CharInfo>(manager.BuildRandom(age, gender, race));
  151. }
  152. void BuildDefault(HLERequestContext& ctx) {
  153. IPC::RequestParser rp{ctx};
  154. const auto index{rp.Pop<u32>()};
  155. LOG_DEBUG(Service_Mii, "called with index={}", index);
  156. if (index > 5) {
  157. LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}",
  158. index);
  159. IPC::ResponseBuilder rb{ctx, 2};
  160. rb.Push(ERROR_INVALID_ARGUMENT);
  161. return;
  162. }
  163. IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
  164. rb.Push(ResultSuccess);
  165. rb.PushRaw<CharInfo>(manager.BuildDefault(index));
  166. }
  167. void GetIndex(HLERequestContext& ctx) {
  168. IPC::RequestParser rp{ctx};
  169. const auto info{rp.PopRaw<CharInfo>()};
  170. LOG_DEBUG(Service_Mii, "called");
  171. u32 index{};
  172. IPC::ResponseBuilder rb{ctx, 3};
  173. rb.Push(manager.GetIndex(info, index));
  174. rb.Push(index);
  175. }
  176. void SetInterfaceVersion(HLERequestContext& ctx) {
  177. IPC::RequestParser rp{ctx};
  178. current_interface_version = rp.PopRaw<u32>();
  179. LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version);
  180. UNIMPLEMENTED_IF(current_interface_version != 1);
  181. IPC::ResponseBuilder rb{ctx, 2};
  182. rb.Push(ResultSuccess);
  183. }
  184. void Convert(HLERequestContext& ctx) {
  185. IPC::RequestParser rp{ctx};
  186. const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
  187. LOG_INFO(Service_Mii, "called");
  188. IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
  189. rb.Push(ResultSuccess);
  190. rb.PushRaw<CharInfo>(manager.ConvertV3ToCharInfo(mii_v3));
  191. }
  192. constexpr bool IsInterfaceVersionSupported(u32 interface_version) const {
  193. return current_interface_version >= interface_version;
  194. }
  195. MiiManager manager;
  196. u32 current_interface_version{};
  197. u64 current_update_counter{};
  198. };
  199. class MiiDBModule final : public ServiceFramework<MiiDBModule> {
  200. public:
  201. explicit MiiDBModule(Core::System& system_, const char* name_)
  202. : ServiceFramework{system_, name_} {
  203. // clang-format off
  204. static const FunctionInfo functions[] = {
  205. {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
  206. };
  207. // clang-format on
  208. RegisterHandlers(functions);
  209. }
  210. private:
  211. void GetDatabaseService(HLERequestContext& ctx) {
  212. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  213. rb.Push(ResultSuccess);
  214. rb.PushIpcInterface<IDatabaseService>(system);
  215. LOG_DEBUG(Service_Mii, "called");
  216. }
  217. };
  218. class MiiImg final : public ServiceFramework<MiiImg> {
  219. public:
  220. explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} {
  221. // clang-format off
  222. static const FunctionInfo functions[] = {
  223. {0, nullptr, "Initialize"},
  224. {10, nullptr, "Reload"},
  225. {11, nullptr, "GetCount"},
  226. {12, nullptr, "IsEmpty"},
  227. {13, nullptr, "IsFull"},
  228. {14, nullptr, "GetAttribute"},
  229. {15, nullptr, "LoadImage"},
  230. {16, nullptr, "AddOrUpdateImage"},
  231. {17, nullptr, "DeleteImages"},
  232. {100, nullptr, "DeleteFile"},
  233. {101, nullptr, "DestroyFile"},
  234. {102, nullptr, "ImportFile"},
  235. {103, nullptr, "ExportFile"},
  236. {104, nullptr, "ForceInitialize"},
  237. };
  238. // clang-format on
  239. RegisterHandlers(functions);
  240. }
  241. };
  242. void LoopProcess(Core::System& system) {
  243. auto server_manager = std::make_unique<ServerManager>(system);
  244. server_manager->RegisterNamedService("mii:e", std::make_shared<MiiDBModule>(system, "mii:e"));
  245. server_manager->RegisterNamedService("mii:u", std::make_shared<MiiDBModule>(system, "mii:u"));
  246. server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system));
  247. ServerManager::RunServer(std::move(server_manager));
  248. }
  249. } // namespace Service::Mii