diff options
Diffstat (limited to 'src/core/hle/service/mii/mii.cpp')
-rw-r--r-- | src/core/hle/service/mii/mii.cpp | 315 |
1 files changed, 96 insertions, 219 deletions
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index a128edb43..b81bf6277 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -4,22 +4,17 @@ #include <memory> -#include <fmt/ostream.h> - #include "common/logging/log.h" -#include "common/string_util.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/mii/mii_manager.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}; -constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; -constexpr ResultCode ERROR_NOT_IN_TEST_MODE{ErrorModule::Mii, 99}; class IDatabaseService final : public ServiceFramework<IDatabaseService> { public: @@ -31,19 +26,19 @@ public: {2, &IDatabaseService::GetCount, "GetCount"}, {3, &IDatabaseService::Get, "Get"}, {4, &IDatabaseService::Get1, "Get1"}, - {5, nullptr, "UpdateLatest"}, + {5, &IDatabaseService::UpdateLatest, "UpdateLatest"}, {6, &IDatabaseService::BuildRandom, "BuildRandom"}, {7, &IDatabaseService::BuildDefault, "BuildDefault"}, - {8, &IDatabaseService::Get2, "Get2"}, - {9, &IDatabaseService::Get3, "Get3"}, + {8, nullptr, "Get2"}, + {9, nullptr, "Get3"}, {10, nullptr, "UpdateLatest1"}, - {11, &IDatabaseService::FindIndex, "FindIndex"}, - {12, &IDatabaseService::Move, "Move"}, - {13, &IDatabaseService::AddOrReplace, "AddOrReplace"}, - {14, &IDatabaseService::Delete, "Delete"}, - {15, &IDatabaseService::DestroyFile, "DestroyFile"}, - {16, &IDatabaseService::DeleteFile, "DeleteFile"}, - {17, &IDatabaseService::Format, "Format"}, + {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"}, @@ -59,31 +54,26 @@ public: } private: - template <typename OutType> - std::vector<u8> SerializeArray(OutType (MiiManager::*getter)(u32) const, u32 offset, - u32 requested_size, u32& read_size) { - read_size = std::min(requested_size, db.Size() - offset); - - std::vector<u8> out(read_size * sizeof(OutType)); - - for (u32 i = 0; i < read_size; ++i) { - const auto obj = (db.*getter)(offset + i); - std::memcpy(out.data() + i * sizeof(OutType), &obj, sizeof(OutType)); + 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{rp.PopRaw<Source>()}; + const auto source_flag{rp.PopRaw<SourceFlag>()}; - LOG_DEBUG(Service_Mii, "called with source={}", source); + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(db.CheckUpdatedFlag()); - db.ResetUpdatedFlag(); + rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter)); } void IsFullDatabase(Kernel::HLERequestContext& ctx) { @@ -91,264 +81,149 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(db.Full()); + rb.Push(manager.IsFullDatabase()); } void GetCount(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto source{rp.PopRaw<Source>()}; + const auto source_flag{rp.PopRaw<SourceFlag>()}; - LOG_DEBUG(Service_Mii, "called with source={}", source); + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(db.Size()); + rb.Push<u32>(manager.GetCount(source_flag)); } - // Gets Miis from database at offset and index in format MiiInfoElement void Get(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; - - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[0], source); - - u32 read_size{}; - ctx.WriteBuffer(SerializeArray(&MiiManager::GetInfoElement, offsets[0], size, read_size)); - offsets[0] += read_size; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); - } + const auto source_flag{rp.PopRaw<SourceFlag>()}; - // Gets Miis from database at offset and index in format MiiInfo - void Get1(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[1], source); + const auto result{manager.GetDefault(source_flag)}; + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } - u32 read_size{}; - ctx.WriteBuffer(SerializeArray(&MiiManager::GetInfo, offsets[1], size, read_size)); - offsets[1] += read_size; + if (result->size() > 0) { + ctx.WriteBuffer(SerializeArray(*result)); + } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); + rb.Push<u32>(static_cast<u32>(result->size())); } - void BuildRandom(Kernel::HLERequestContext& ctx) { + void Get1(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto [unknown1, unknown2, unknown3] = rp.PopRaw<RandomParameters>(); + const auto source_flag{rp.PopRaw<SourceFlag>()}; - if (unknown1 > 3) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - LOG_ERROR(Service_Mii, "Invalid unknown1 value: {}", unknown1); - return; - } + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); - if (unknown2 > 2) { + const auto result{manager.GetDefault(source_flag)}; + if (result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - LOG_ERROR(Service_Mii, "Invalid unknown2 value: {}", unknown2); + rb.Push(result.Code()); return; } - if (unknown3 > 3) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - LOG_ERROR(Service_Mii, "Invalid unknown3 value: {}", unknown3); - return; + std::vector<MiiInfo> values; + for (const auto& element : *result) { + values.emplace_back(element.info); } - LOG_DEBUG(Service_Mii, "called with param_1={:08X}, param_2={:08X}, param_3={:08X}", - unknown1, unknown2, unknown3); + ctx.WriteBuffer(SerializeArray(values)); - const auto info = db.CreateRandom({unknown1, unknown2, unknown3}); - IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.PushRaw<MiiInfo>(info); + rb.Push<u32>(static_cast<u32>(result->size())); } - void BuildDefault(Kernel::HLERequestContext& ctx) { + void UpdateLatest(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto index{rp.PopRaw<u32>()}; + const auto info{rp.PopRaw<MiiInfo>()}; + const auto source_flag{rp.PopRaw<SourceFlag>()}; - if (index > 5) { - LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}", - index); + 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(ERROR_INVALID_ARGUMENT); + rb.Push(result.Code()); return; } - LOG_DEBUG(Service_Mii, "called with index={:08X}", index); - - const auto info = db.CreateDefault(index); IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; rb.Push(RESULT_SUCCESS); - rb.PushRaw<MiiInfo>(info); + rb.PushRaw<MiiInfo>(*result); } - // Gets Miis from database at offset and index in format MiiStoreDataElement - void Get2(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; - - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[2], source); - - u32 read_size{}; - ctx.WriteBuffer( - SerializeArray(&MiiManager::GetStoreDataElement, offsets[2], size, read_size)); - offsets[2] += read_size; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); - } - - // Gets Miis from database at offset and index in format MiiStoreData - void Get3(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; - - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[3], source); - - u32 read_size{}; - ctx.WriteBuffer(SerializeArray(&MiiManager::GetStoreData, offsets[3], size, read_size)); - offsets[3] += read_size; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); - } - - void FindIndex(Kernel::HLERequestContext& ctx) { + void BuildRandom(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto uuid{rp.PopRaw<Common::UUID>()}; - const auto unknown{rp.PopRaw<bool>()}; - LOG_DEBUG(Service_Mii, "called with uuid={}, unknown={}", uuid.FormatSwitch(), unknown); + const auto age{rp.PopRaw<Age>()}; + const auto gender{rp.PopRaw<Gender>()}; + const auto race{rp.PopRaw<Race>()}; - IPC::ResponseBuilder rb{ctx, 3}; + LOG_DEBUG(Service_Mii, "called with age={}, gender={}, race={}", age, gender, race); - const auto index = db.IndexOf(uuid); - if (index > MAX_MIIS) { - // TODO(DarkLordZach): Find a better error code - rb.Push(RESULT_UNKNOWN); - rb.Push(index); - } else { - rb.Push(RESULT_SUCCESS); - rb.Push(index); + if (age > Age::All) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + LOG_ERROR(Service_Mii, "invalid age={}", age); + return; } - } - void Move(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto uuid{rp.PopRaw<Common::UUID>()}; - const auto index{rp.PopRaw<s32>()}; - - if (index < 0) { - LOG_ERROR(Service_Mii, "Index cannot be negative but is {:08X}!", index); + if (gender > Gender::All) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_ARGUMENT); + LOG_ERROR(Service_Mii, "invalid gender={}", gender); return; } - LOG_DEBUG(Service_Mii, "called with uuid={}, index={:08X}", uuid.FormatSwitch(), index); - - const auto success = db.Move(uuid, index); - - IPC::ResponseBuilder rb{ctx, 2}; - // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); - } - - void AddOrReplace(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto data{rp.PopRaw<MiiStoreData>()}; - - LOG_DEBUG(Service_Mii, "called with Mii data uuid={}, name={}", data.uuid.FormatSwitch(), - Common::UTF16ToUTF8(data.Name())); - - const auto success = db.AddOrReplace(data); - - IPC::ResponseBuilder rb{ctx, 2}; - // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); - } - - void Delete(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto uuid{rp.PopRaw<Common::UUID>()}; - - LOG_DEBUG(Service_Mii, "called with uuid={}", uuid.FormatSwitch()); - - const auto success = db.Remove(uuid); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(success ? RESULT_SUCCESS : ERROR_CANNOT_FIND_ENTRY); - } - - void DestroyFile(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Mii, "called"); - - if (!db.IsTestModeEnabled()) { - LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot destory database file."); + if (race > Race::All) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NOT_IN_TEST_MODE); + rb.Push(ERROR_INVALID_ARGUMENT); + LOG_ERROR(Service_Mii, "invalid race={}", race); return; } - IPC::ResponseBuilder rb{ctx, 3}; + IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; rb.Push(RESULT_SUCCESS); - rb.Push(db.DestroyFile()); + rb.PushRaw<MiiInfo>(manager.BuildRandom(age, gender, race)); } - void DeleteFile(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Mii, "called"); + void BuildDefault(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto index{rp.Pop<u32>()}; + + LOG_DEBUG(Service_Mii, "called with index={}", index); - if (!db.IsTestModeEnabled()) { - LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot delete database file."); + 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_NOT_IN_TEST_MODE); + rb.Push(ERROR_INVALID_ARGUMENT); return; } - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push(db.DeleteFile()); - } - - void Format(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Mii, "called"); - - db.Clear(); - - IPC::ResponseBuilder rb{ctx, 2}; + 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 with Mii info uuid={}, name={}", info.uuid.FormatSwitch(), - Common::UTF16ToUTF8(info.Name())); - - const auto index = db.IndexOf(info); + LOG_DEBUG(Service_Mii, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + u32 index{}; + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(manager.GetIndex(info, index)); rb.Push(index); } @@ -364,12 +239,14 @@ private: rb.Push(RESULT_SUCCESS); } - MiiManager db; + constexpr bool IsInterfaceVersionSupported(u32 interface_version) const { + return current_interface_version >= interface_version; + } - u32 current_interface_version = 0; + MiiManager manager; - // Last read offsets of Get functions - std::array<u32, 4> offsets{}; + u32 current_interface_version{}; + u64 current_update_counter{}; }; class MiiDBModule final : public ServiceFramework<MiiDBModule> { |