| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include <memory>
- #include "common/logging/log.h"
- #include "core/hle/service/ipc_helpers.h"
- #include "core/hle/service/mii/mii.h"
- #include "core/hle/service/mii/mii_manager.h"
- #include "core/hle/service/server_manager.h"
- #include "core/hle/service/service.h"
- namespace Service::Mii {
- constexpr Result ERROR_INVALID_ARGUMENT{ErrorModule::Mii, 1};
- class IDatabaseService final : public ServiceFramework<IDatabaseService> {
- public:
- explicit IDatabaseService(Core::System& system_)
- : ServiceFramework{system_, "IDatabaseService"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IDatabaseService::IsUpdated, "IsUpdated"},
- {1, &IDatabaseService::IsFullDatabase, "IsFullDatabase"},
- {2, &IDatabaseService::GetCount, "GetCount"},
- {3, &IDatabaseService::Get, "Get"},
- {4, &IDatabaseService::Get1, "Get1"},
- {5, &IDatabaseService::UpdateLatest, "UpdateLatest"},
- {6, &IDatabaseService::BuildRandom, "BuildRandom"},
- {7, &IDatabaseService::BuildDefault, "BuildDefault"},
- {8, nullptr, "Get2"},
- {9, nullptr, "Get3"},
- {10, nullptr, "UpdateLatest1"},
- {11, nullptr, "FindIndex"},
- {12, nullptr, "Move"},
- {13, nullptr, "AddOrReplace"},
- {14, nullptr, "Delete"},
- {15, nullptr, "DestroyFile"},
- {16, nullptr, "DeleteFile"},
- {17, nullptr, "Format"},
- {18, nullptr, "Import"},
- {19, nullptr, "Export"},
- {20, nullptr, "IsBrokenDatabaseWithClearFlag"},
- {21, &IDatabaseService::GetIndex, "GetIndex"},
- {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
- {23, &IDatabaseService::Convert, "Convert"},
- {24, nullptr, "ConvertCoreDataToCharInfo"},
- {25, nullptr, "ConvertCharInfoToCoreData"},
- {26, nullptr, "Append"},
- };
- // clang-format on
- RegisterHandlers(functions);
- }
- private:
- template <typename T>
- std::vector<u8> SerializeArray(const std::vector<T>& values) {
- std::vector<u8> out(values.size() * sizeof(T));
- std::size_t offset{};
- for (const auto& value : values) {
- std::memcpy(out.data() + offset, &value, sizeof(T));
- offset += sizeof(T);
- }
- return out;
- }
- void IsUpdated(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto source_flag{rp.PopRaw<SourceFlag>()};
- LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter));
- }
- void IsFullDatabase(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Mii, "called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(manager.IsFullDatabase());
- }
- void GetCount(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto source_flag{rp.PopRaw<SourceFlag>()};
- LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(manager.GetCount(source_flag));
- }
- void Get(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto source_flag{rp.PopRaw<SourceFlag>()};
- LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
- const auto default_miis{manager.GetDefault(source_flag)};
- if (default_miis.size() > 0) {
- ctx.WriteBuffer(SerializeArray(default_miis));
- }
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(default_miis.size()));
- }
- void Get1(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto source_flag{rp.PopRaw<SourceFlag>()};
- LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
- const auto default_miis{manager.GetDefault(source_flag)};
- std::vector<CharInfo> values;
- for (const auto& element : default_miis) {
- values.emplace_back(element.info);
- }
- ctx.WriteBuffer(SerializeArray(values));
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(default_miis.size()));
- }
- void UpdateLatest(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto info{rp.PopRaw<CharInfo>()};
- const auto source_flag{rp.PopRaw<SourceFlag>()};
- LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
- CharInfo new_char_info{};
- const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)};
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
- IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
- rb.Push(ResultSuccess);
- rb.PushRaw<CharInfo>(new_char_info);
- }
- void BuildRandom(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto age{rp.PopRaw<Age>()};
- const auto gender{rp.PopRaw<Gender>()};
- const auto race{rp.PopRaw<Race>()};
- LOG_DEBUG(Service_Mii, "called with age={}, gender={}, race={}", age, gender, race);
- if (age > Age::All) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_ARGUMENT);
- LOG_ERROR(Service_Mii, "invalid age={}", age);
- return;
- }
- if (gender > Gender::All) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_ARGUMENT);
- LOG_ERROR(Service_Mii, "invalid gender={}", gender);
- return;
- }
- if (race > Race::All) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_ARGUMENT);
- LOG_ERROR(Service_Mii, "invalid race={}", race);
- return;
- }
- IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
- rb.Push(ResultSuccess);
- rb.PushRaw<CharInfo>(manager.BuildRandom(age, gender, race));
- }
- void BuildDefault(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto index{rp.Pop<u32>()};
- LOG_DEBUG(Service_Mii, "called with index={}", index);
- if (index > 5) {
- LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}",
- index);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_ARGUMENT);
- return;
- }
- IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
- rb.Push(ResultSuccess);
- rb.PushRaw<CharInfo>(manager.BuildDefault(index));
- }
- void GetIndex(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto info{rp.PopRaw<CharInfo>()};
- LOG_DEBUG(Service_Mii, "called");
- u32 index{};
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(manager.GetIndex(info, index));
- rb.Push(index);
- }
- void SetInterfaceVersion(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- current_interface_version = rp.PopRaw<u32>();
- LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version);
- UNIMPLEMENTED_IF(current_interface_version != 1);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
- void Convert(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
- LOG_INFO(Service_Mii, "called");
- IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
- rb.Push(ResultSuccess);
- rb.PushRaw<CharInfo>(manager.ConvertV3ToCharInfo(mii_v3));
- }
- constexpr bool IsInterfaceVersionSupported(u32 interface_version) const {
- return current_interface_version >= interface_version;
- }
- MiiManager manager;
- u32 current_interface_version{};
- u64 current_update_counter{};
- };
- class MiiDBModule final : public ServiceFramework<MiiDBModule> {
- public:
- explicit MiiDBModule(Core::System& system_, const char* name_)
- : ServiceFramework{system_, name_} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
- };
- // clang-format on
- RegisterHandlers(functions);
- }
- private:
- void GetDatabaseService(HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IDatabaseService>(system);
- LOG_DEBUG(Service_Mii, "called");
- }
- };
- class MiiImg final : public ServiceFramework<MiiImg> {
- public:
- explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Initialize"},
- {10, nullptr, "Reload"},
- {11, nullptr, "GetCount"},
- {12, nullptr, "IsEmpty"},
- {13, nullptr, "IsFull"},
- {14, nullptr, "GetAttribute"},
- {15, nullptr, "LoadImage"},
- {16, nullptr, "AddOrUpdateImage"},
- {17, nullptr, "DeleteImages"},
- {100, nullptr, "DeleteFile"},
- {101, nullptr, "DestroyFile"},
- {102, nullptr, "ImportFile"},
- {103, nullptr, "ExportFile"},
- {104, nullptr, "ForceInitialize"},
- };
- // clang-format on
- RegisterHandlers(functions);
- }
- };
- void LoopProcess(Core::System& system) {
- auto server_manager = std::make_unique<ServerManager>(system);
- server_manager->RegisterNamedService("mii:e", std::make_shared<MiiDBModule>(system, "mii:e"));
- server_manager->RegisterNamedService("mii:u", std::make_shared<MiiDBModule>(system, "mii:u"));
- server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system));
- ServerManager::RunServer(std::move(server_manager));
- }
- } // namespace Service::Mii
|