mii.cpp 10.0 KB

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