Merge pull request #1122 from lioncash/acc
acc/profile_manager: General cleanup
This commit is contained in:
		| @@ -13,7 +13,7 @@ | ||||
| #include "core/hle/service/acc/acc_su.h" | ||||
| #include "core/hle/service/acc/acc_u0.h" | ||||
| #include "core/hle/service/acc/acc_u1.h" | ||||
| #include "core/settings.h" | ||||
| #include "core/hle/service/acc/profile_manager.h" | ||||
|  | ||||
| namespace Service::Account { | ||||
| // TODO: RE this structure | ||||
| @@ -27,13 +27,10 @@ struct UserData { | ||||
| }; | ||||
| static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); | ||||
|  | ||||
| // TODO(ogniK): Generate a real user id based on username, md5(username) maybe? | ||||
| static UUID DEFAULT_USER_ID{1ull, 0ull}; | ||||
|  | ||||
| class IProfile final : public ServiceFramework<IProfile> { | ||||
| public: | ||||
|     explicit IProfile(UUID user_id, ProfileManager& profile_manager) | ||||
|         : ServiceFramework("IProfile"), user_id(user_id), profile_manager(profile_manager) { | ||||
|         : ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IProfile::Get, "Get"}, | ||||
|             {1, &IProfile::GetBase, "GetBase"}, | ||||
| @@ -79,8 +76,8 @@ private: | ||||
|         LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||||
|         // smallest jpeg https://github.com/mathiasbynens/small/blob/master/jpeg.jpg | ||||
|         // TODO(mailwl): load actual profile image from disk, width 256px, max size 0x20000 | ||||
|         const u32 jpeg_size = 107; | ||||
|         static const std::array<u8, jpeg_size> jpeg{ | ||||
|         constexpr u32 jpeg_size = 107; | ||||
|         static constexpr std::array<u8, jpeg_size> jpeg{ | ||||
|             0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, | ||||
|             0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, | ||||
|             0x08, 0x06, 0x06, 0x05, 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, | ||||
| @@ -90,7 +87,7 @@ private: | ||||
|             0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, | ||||
|             0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, | ||||
|         }; | ||||
|         ctx.WriteBuffer(jpeg.data(), jpeg_size); | ||||
|         ctx.WriteBuffer(jpeg); | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(jpeg_size); | ||||
| @@ -205,6 +202,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module, | ||||
|     : ServiceFramework(name), module(std::move(module)), | ||||
|       profile_manager(std::move(profile_manager)) {} | ||||
|  | ||||
| Module::Interface::~Interface() = default; | ||||
|  | ||||
| void InstallInterfaces(SM::ServiceManager& service_manager) { | ||||
|     auto module = std::make_shared<Module>(); | ||||
|     auto profile_manager = std::make_shared<ProfileManager>(); | ||||
|   | ||||
| @@ -4,17 +4,19 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "core/hle/service/acc/profile_manager.h" | ||||
| #include "core/hle/service/service.h" | ||||
|  | ||||
| namespace Service::Account { | ||||
|  | ||||
| class ProfileManager; | ||||
|  | ||||
| class Module final { | ||||
| public: | ||||
|     class Interface : public ServiceFramework<Interface> { | ||||
|     public: | ||||
|         explicit Interface(std::shared_ptr<Module> module, | ||||
|                            std::shared_ptr<ProfileManager> profile_manager, const char* name); | ||||
|         ~Interface() override; | ||||
|  | ||||
|         void GetUserCount(Kernel::HLERequestContext& ctx); | ||||
|         void GetUserExistence(Kernel::HLERequestContext& ctx); | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <random> | ||||
| #include <boost/optional.hpp> | ||||
| #include "core/hle/service/acc/profile_manager.h" | ||||
| #include "core/settings.h" | ||||
| @@ -12,6 +13,15 @@ constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1); | ||||
| constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, -2); | ||||
| constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20); | ||||
|  | ||||
| const UUID& UUID::Generate() { | ||||
|     std::random_device device; | ||||
|     std::mt19937 gen(device()); | ||||
|     std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max()); | ||||
|     uuid[0] = distribution(gen); | ||||
|     uuid[1] = distribution(gen); | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| ProfileManager::ProfileManager() { | ||||
|     // TODO(ogniK): Create the default user we have for now until loading/saving users is added | ||||
|     auto user_uuid = UUID{1, 0}; | ||||
| @@ -25,7 +35,7 @@ boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { | ||||
|     if (user_count >= MAX_USERS) { | ||||
|         return boost::none; | ||||
|     } | ||||
|     profiles[user_count] = std::move(user); | ||||
|     profiles[user_count] = user; | ||||
|     return user_count++; | ||||
| } | ||||
|  | ||||
| @@ -43,7 +53,7 @@ bool ProfileManager::RemoveProfileAtIndex(size_t index) { | ||||
| } | ||||
|  | ||||
| /// Helper function to register a user to the system | ||||
| ResultCode ProfileManager::AddUser(ProfileInfo user) { | ||||
| ResultCode ProfileManager::AddUser(const ProfileInfo& user) { | ||||
|     if (AddToProfiles(user) == boost::none) { | ||||
|         return ERROR_TOO_MANY_USERS; | ||||
|     } | ||||
| @@ -52,7 +62,7 @@ ResultCode ProfileManager::AddUser(ProfileInfo user) { | ||||
|  | ||||
| /// Create a new user on the system. If the uuid of the user already exists, the user is not | ||||
| /// created. | ||||
| ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20>& username) { | ||||
| ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& username) { | ||||
|     if (user_count == MAX_USERS) { | ||||
|         return ERROR_TOO_MANY_USERS; | ||||
|     } | ||||
| @@ -67,7 +77,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20>& userna | ||||
|         return ERROR_USER_ALREADY_EXISTS; | ||||
|     } | ||||
|     ProfileInfo profile; | ||||
|     profile.user_uuid = std::move(uuid); | ||||
|     profile.user_uuid = uuid; | ||||
|     profile.username = username; | ||||
|     profile.data = {}; | ||||
|     profile.creation_time = 0x0; | ||||
| @@ -79,7 +89,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20>& userna | ||||
| /// specifically by allowing an std::string for the username. This is required specifically since | ||||
| /// we're loading a string straight from the config | ||||
| ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) { | ||||
|     std::array<u8, 0x20> username_output; | ||||
|     ProfileUsername username_output; | ||||
|     if (username.size() > username_output.size()) { | ||||
|         std::copy_n(username.begin(), username_output.size(), username_output.begin()); | ||||
|     } else { | ||||
| @@ -102,7 +112,7 @@ boost::optional<size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { | ||||
| } | ||||
|  | ||||
| /// Returns a users profile index based on their profile | ||||
| boost::optional<size_t> ProfileManager::GetUserIndex(ProfileInfo user) const { | ||||
| boost::optional<size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const { | ||||
|     return GetUserIndex(user.user_uuid); | ||||
| } | ||||
|  | ||||
| @@ -125,7 +135,7 @@ bool ProfileManager::GetProfileBase(UUID uuid, ProfileBase& profile) const { | ||||
| } | ||||
|  | ||||
| /// Returns the data structure used by the switch when GetProfileBase is called on acc:* | ||||
| bool ProfileManager::GetProfileBase(ProfileInfo user, ProfileBase& profile) const { | ||||
| bool ProfileManager::GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const { | ||||
|     return GetProfileBase(user.user_uuid, profile); | ||||
| } | ||||
|  | ||||
| @@ -168,8 +178,8 @@ void ProfileManager::CloseUser(UUID uuid) { | ||||
| } | ||||
|  | ||||
| /// Gets all valid user ids on the system | ||||
| std::array<UUID, MAX_USERS> ProfileManager::GetAllUsers() const { | ||||
|     std::array<UUID, MAX_USERS> output; | ||||
| UserIDArray ProfileManager::GetAllUsers() const { | ||||
|     UserIDArray output; | ||||
|     std::transform(profiles.begin(), profiles.end(), output.begin(), | ||||
|                    [](const ProfileInfo& p) { return p.user_uuid; }); | ||||
|     return output; | ||||
| @@ -177,8 +187,8 @@ std::array<UUID, MAX_USERS> ProfileManager::GetAllUsers() const { | ||||
|  | ||||
| /// Get all the open users on the system and zero out the rest of the data. This is specifically | ||||
| /// needed for GetOpenUsers and we need to ensure the rest of the output buffer is zero'd out | ||||
| std::array<UUID, MAX_USERS> ProfileManager::GetOpenUsers() const { | ||||
|     std::array<UUID, MAX_USERS> output; | ||||
| UserIDArray ProfileManager::GetOpenUsers() const { | ||||
|     UserIDArray output; | ||||
|     std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) { | ||||
|         if (p.is_open) | ||||
|             return p.user_uuid; | ||||
| @@ -195,9 +205,9 @@ UUID ProfileManager::GetLastOpenedUser() const { | ||||
|  | ||||
| /// Return the users profile base and the unknown arbitary data. | ||||
| bool ProfileManager::GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile, | ||||
|                                            std::array<u8, MAX_DATA>& data) const { | ||||
|                                            ProfileData& data) const { | ||||
|     if (GetProfileBase(index, profile)) { | ||||
|         std::memcpy(data.data(), profiles[index.get()].data.data(), MAX_DATA); | ||||
|         data = profiles[index.get()].data; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| @@ -205,14 +215,14 @@ bool ProfileManager::GetProfileBaseAndData(boost::optional<size_t> index, Profil | ||||
|  | ||||
| /// Return the users profile base and the unknown arbitary data. | ||||
| bool ProfileManager::GetProfileBaseAndData(UUID uuid, ProfileBase& profile, | ||||
|                                            std::array<u8, MAX_DATA>& data) const { | ||||
|                                            ProfileData& data) const { | ||||
|     auto idx = GetUserIndex(uuid); | ||||
|     return GetProfileBaseAndData(idx, profile, data); | ||||
| } | ||||
|  | ||||
| /// Return the users profile base and the unknown arbitary data. | ||||
| bool ProfileManager::GetProfileBaseAndData(ProfileInfo user, ProfileBase& profile, | ||||
|                                            std::array<u8, MAX_DATA>& data) const { | ||||
| bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, | ||||
|                                            ProfileData& data) const { | ||||
|     return GetProfileBaseAndData(user.user_uuid, profile, data); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <random> | ||||
|  | ||||
| #include "boost/optional.hpp" | ||||
| #include "common/common_types.h" | ||||
| #include "common/swap.h" | ||||
| @@ -14,23 +14,21 @@ | ||||
| namespace Service::Account { | ||||
| constexpr size_t MAX_USERS = 8; | ||||
| constexpr size_t MAX_DATA = 128; | ||||
| static const u128 INVALID_UUID = {0, 0}; | ||||
| constexpr u128 INVALID_UUID{{0, 0}}; | ||||
|  | ||||
| struct UUID { | ||||
|     // UUIDs which are 0 are considered invalid! | ||||
|     u128 uuid = INVALID_UUID; | ||||
|     UUID() = default; | ||||
|     explicit UUID(const u128& id) : uuid{id} {} | ||||
|     explicit UUID(const u64 lo, const u64 hi) { | ||||
|         uuid[0] = lo; | ||||
|         uuid[1] = hi; | ||||
|     }; | ||||
|     explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} | ||||
|  | ||||
|     explicit operator bool() const { | ||||
|         return uuid[0] != INVALID_UUID[0] || uuid[1] != INVALID_UUID[1]; | ||||
|         return uuid != INVALID_UUID; | ||||
|     } | ||||
|  | ||||
|     bool operator==(const UUID& rhs) const { | ||||
|         return std::tie(uuid[0], uuid[1]) == std::tie(rhs.uuid[0], rhs.uuid[1]); | ||||
|         return uuid == rhs.uuid; | ||||
|     } | ||||
|  | ||||
|     bool operator!=(const UUID& rhs) const { | ||||
| @@ -38,15 +36,7 @@ struct UUID { | ||||
|     } | ||||
|  | ||||
|     // TODO(ogniK): Properly generate uuids based on RFC-4122 | ||||
|     const UUID& Generate() { | ||||
|         std::random_device device; | ||||
|         std::mt19937 gen(device()); | ||||
|         std::uniform_int_distribution<uint64_t> distribution(1, | ||||
|                                                              std::numeric_limits<uint64_t>::max()); | ||||
|         uuid[0] = distribution(gen); | ||||
|         uuid[1] = distribution(gen); | ||||
|         return *this; | ||||
|     } | ||||
|     const UUID& Generate(); | ||||
|  | ||||
|     // Set the UUID to {0,0} to be considered an invalid user | ||||
|     void Invalidate() { | ||||
| @@ -58,20 +48,24 @@ struct UUID { | ||||
| }; | ||||
| static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | ||||
|  | ||||
| using ProfileUsername = std::array<u8, 0x20>; | ||||
| using ProfileData = std::array<u8, MAX_DATA>; | ||||
| using UserIDArray = std::array<UUID, MAX_USERS>; | ||||
|  | ||||
| /// This holds general information about a users profile. This is where we store all the information | ||||
| /// based on a specific user | ||||
| struct ProfileInfo { | ||||
|     UUID user_uuid; | ||||
|     std::array<u8, 0x20> username; | ||||
|     ProfileUsername username; | ||||
|     u64 creation_time; | ||||
|     std::array<u8, MAX_DATA> data; // TODO(ognik): Work out what this is | ||||
|     ProfileData data; // TODO(ognik): Work out what this is | ||||
|     bool is_open; | ||||
| }; | ||||
|  | ||||
| struct ProfileBase { | ||||
|     UUID user_uuid; | ||||
|     u64_le timestamp; | ||||
|     std::array<u8, 0x20> username; | ||||
|     ProfileUsername username; | ||||
|  | ||||
|     // Zero out all the fields to make the profile slot considered "Empty" | ||||
|     void Invalidate() { | ||||
| @@ -88,27 +82,26 @@ static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size"); | ||||
| class ProfileManager { | ||||
| public: | ||||
|     ProfileManager(); // TODO(ogniK): Load from system save | ||||
|     ResultCode AddUser(ProfileInfo user); | ||||
|     ResultCode CreateNewUser(UUID uuid, std::array<u8, 0x20>& username); | ||||
|     ResultCode AddUser(const ProfileInfo& user); | ||||
|     ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username); | ||||
|     ResultCode CreateNewUser(UUID uuid, const std::string& username); | ||||
|     boost::optional<size_t> GetUserIndex(const UUID& uuid) const; | ||||
|     boost::optional<size_t> GetUserIndex(ProfileInfo user) const; | ||||
|     boost::optional<size_t> GetUserIndex(const ProfileInfo& user) const; | ||||
|     bool GetProfileBase(boost::optional<size_t> index, ProfileBase& profile) const; | ||||
|     bool GetProfileBase(UUID uuid, ProfileBase& profile) const; | ||||
|     bool GetProfileBase(ProfileInfo user, ProfileBase& profile) const; | ||||
|     bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; | ||||
|     bool GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile, | ||||
|                                std::array<u8, MAX_DATA>& data) const; | ||||
|     bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, | ||||
|                                std::array<u8, MAX_DATA>& data) const; | ||||
|     bool GetProfileBaseAndData(ProfileInfo user, ProfileBase& profile, | ||||
|                                std::array<u8, MAX_DATA>& data) const; | ||||
|                                ProfileData& data) const; | ||||
|     bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const; | ||||
|     bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, | ||||
|                                ProfileData& data) const; | ||||
|     size_t GetUserCount() const; | ||||
|     size_t GetOpenUserCount() const; | ||||
|     bool UserExists(UUID uuid) const; | ||||
|     void OpenUser(UUID uuid); | ||||
|     void CloseUser(UUID uuid); | ||||
|     std::array<UUID, MAX_USERS> GetOpenUsers() const; | ||||
|     std::array<UUID, MAX_USERS> GetAllUsers() const; | ||||
|     UserIDArray GetOpenUsers() const; | ||||
|     UserIDArray GetAllUsers() const; | ||||
|     UUID GetLastOpenedUser() const; | ||||
|  | ||||
|     bool CanSystemRegisterUser() const; | ||||
| @@ -118,7 +111,7 @@ private: | ||||
|     size_t user_count = 0; | ||||
|     boost::optional<size_t> AddToProfiles(const ProfileInfo& profile); | ||||
|     bool RemoveProfileAtIndex(size_t index); | ||||
|     UUID last_opened_user{0, 0}; | ||||
|     UUID last_opened_user{INVALID_UUID}; | ||||
| }; | ||||
|  | ||||
| }; // namespace Service::Account | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei