| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- // Copyright 2018 yuzu emulator team
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included.
- #include <memory>
- #include "common/logging/log.h"
- #include "core/hle/ipc_helpers.h"
- #include "core/hle/kernel/hle_ipc.h"
- #include "core/hle/service/mii/manager.h"
- #include "core/hle/service/mii/mii.h"
- #include "core/hle/service/service.h"
- #include "core/hle/service/sm/sm.h"
- namespace Service::Mii {
- constexpr ResultCode 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, nullptr, "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(Kernel::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(RESULT_SUCCESS);
- rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter));
- }
- void IsFullDatabase(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_Mii, "called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(RESULT_SUCCESS);
- rb.Push(manager.IsFullDatabase());
- }
- void GetCount(Kernel::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(RESULT_SUCCESS);
- rb.Push<u32>(manager.GetCount(source_flag));
- }
- void Get(Kernel::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 result{manager.GetDefault(source_flag)};
- if (result.Failed()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.Code());
- return;
- }
- if (result->size() > 0) {
- ctx.WriteBuffer(SerializeArray(*result));
- }
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(static_cast<u32>(result->size()));
- }
- void Get1(Kernel::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 result{manager.GetDefault(source_flag)};
- if (result.Failed()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.Code());
- return;
- }
- std::vector<MiiInfo> values;
- for (const auto& element : *result) {
- values.emplace_back(element.info);
- }
- ctx.WriteBuffer(SerializeArray(values));
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(static_cast<u32>(result->size()));
- }
- void UpdateLatest(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto info{rp.PopRaw<MiiInfo>()};
- const auto source_flag{rp.PopRaw<SourceFlag>()};
- LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
- const auto result{manager.UpdateLatest(info, source_flag)};
- if (result.Failed()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.Code());
- return;
- }
- IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)};
- rb.Push(RESULT_SUCCESS);
- rb.PushRaw<MiiInfo>(*result);
- }
- void BuildRandom(Kernel::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(MiiInfo) / sizeof(u32)};
- rb.Push(RESULT_SUCCESS);
- rb.PushRaw<MiiInfo>(manager.BuildRandom(age, gender, race));
- }
- void BuildDefault(Kernel::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(MiiInfo) / sizeof(u32)};
- rb.Push(RESULT_SUCCESS);
- rb.PushRaw<MiiInfo>(manager.BuildDefault(index));
- }
- void GetIndex(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto info{rp.PopRaw<MiiInfo>()};
- LOG_DEBUG(Service_Mii, "called");
- u32 index{};
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(manager.GetIndex(info, index));
- rb.Push(index);
- }
- void SetInterfaceVersion(Kernel::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(RESULT_SUCCESS);
- }
- 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(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- 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 InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<MiiDBModule>(system, "mii:e")->InstallAsService(sm);
- std::make_shared<MiiDBModule>(system, "mii:u")->InstallAsService(sm);
- std::make_shared<MiiImg>(system)->InstallAsService(sm);
- }
- } // namespace Service::Mii
|