common: Extract UUID to its own class

Since the Mii database uses UUIDs very similar to the Accounts database, it makes no sense to not share code between them.
This commit is contained in:
Zach Hilman 2018-12-18 09:07:25 -05:00
parent 78574e7a47
commit ca5638a142
6 changed files with 108 additions and 78 deletions

View file

@ -123,6 +123,8 @@ add_library(common STATIC
timer.h
uint128.cpp
uint128.h
uuid.cpp
uuid.h
vector_math.h
web_result.h
zstd_compression.cpp

33
src/common/uuid.cpp Normal file
View file

@ -0,0 +1,33 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <random>
#include <fmt/format.h>
#include "common/uuid.h"
namespace Common {
UUID UUID::Generate() {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
return UUID{distribution(gen), distribution(gen)};
}
std::string UUID::Format() const {
return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
}
std::string UUID::FormatSwitch() const {
std::array<u8, 16> s{};
std::memcpy(s.data(), uuid.data(), sizeof(u128));
return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
":02x}{:02x}{:02x}{:02x}{:02x}",
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
s[12], s[13], s[14], s[15]);
}
} // namespace Common

45
src/common/uuid.h Normal file
View file

@ -0,0 +1,45 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace Common {
constexpr u128 INVALID_UUID{{0, 0}};
struct UUID {
// UUIDs which are 0 are considered invalid!
u128 uuid = INVALID_UUID;
constexpr UUID() = default;
constexpr explicit UUID(const u128& id) : uuid{id} {}
constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
explicit operator bool() const {
return uuid != INVALID_UUID;
}
bool operator==(const UUID& rhs) const {
return uuid == rhs.uuid;
}
bool operator!=(const UUID& rhs) const {
return !operator==(rhs);
}
// TODO(ogniK): Properly generate uuids based on RFC-4122
static UUID Generate();
// Set the UUID to {0,0} to be considered an invalid user
void Invalidate() {
uuid = INVALID_UUID;
}
std::string Format() const;
std::string FormatSwitch() const;
};
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
} // namespace Common

View file

@ -34,7 +34,7 @@ constexpr std::array<u8, backup_jpeg_size> backup_jpeg{{
0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
}};
static std::string GetImagePath(UUID uuid) {
static std::string GetImagePath(Common::UUID uuid) {
return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
"/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
}
@ -46,7 +46,7 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
class IProfile final : public ServiceFramework<IProfile> {
public:
explicit IProfile(UUID user_id, ProfileManager& profile_manager)
explicit IProfile(Common::UUID user_id, ProfileManager& profile_manager)
: ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) {
static const FunctionInfo functions[] = {
{0, &IProfile::Get, "Get"},
@ -131,7 +131,7 @@ private:
}
const ProfileManager& profile_manager;
UUID user_id; ///< The user id this profile refers to.
Common::UUID user_id; ///< The user id this profile refers to.
};
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
@ -179,7 +179,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
UUID user_id = rp.PopRaw<UUID>();
Common::UUID user_id = rp.PopRaw<Common::UUID>();
LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
IPC::ResponseBuilder rb{ctx, 3};
@ -205,12 +205,12 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<UUID>(profile_manager->GetLastOpenedUser());
rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
}
void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
UUID user_id = rp.PopRaw<UUID>();
Common::UUID user_id = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@ -245,15 +245,15 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
IPC::ResponseBuilder rb{ctx, 6};
if (profile_manager->GetUserCount() != 1) {
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u128>(INVALID_UUID);
rb.PushRaw<u128>(Common::INVALID_UUID);
return;
}
const auto user_list = profile_manager->GetAllUsers();
if (std::all_of(user_list.begin(), user_list.end(),
[](const auto& user) { return user.uuid == INVALID_UUID; })) {
[](const auto& user) { return user.uuid == Common::INVALID_UUID; })) {
rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
rb.PushRaw<u128>(INVALID_UUID);
rb.PushRaw<u128>(Common::INVALID_UUID);
return;
}

View file

@ -13,6 +13,8 @@
namespace Service::Account {
using namespace Common;
struct UserRaw {
UUID uuid;
UUID uuid2;
@ -35,26 +37,6 @@ constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20);
constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/avators/";
UUID UUID::Generate() {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
return UUID{distribution(gen), distribution(gen)};
}
std::string UUID::Format() const {
return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
}
std::string UUID::FormatSwitch() const {
std::array<u8, 16> s{};
std::memcpy(s.data(), uuid.data(), sizeof(u128));
return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
":02x}{:02x}{:02x}{:02x}{:02x}",
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
s[12], s[13], s[14], s[15]);
}
ProfileManager::ProfileManager() {
ParseUserSaveFile();

View file

@ -9,47 +9,15 @@
#include "common/common_types.h"
#include "common/swap.h"
#include "common/uuid.h"
#include "core/hle/result.h"
namespace Service::Account {
constexpr std::size_t MAX_USERS = 8;
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{{lo, hi}} {}
explicit operator bool() const {
return uuid != INVALID_UUID;
}
bool operator==(const UUID& rhs) const {
return uuid == rhs.uuid;
}
bool operator!=(const UUID& rhs) const {
return !operator==(rhs);
}
// TODO(ogniK): Properly generate uuids based on RFC-4122
static UUID Generate();
// Set the UUID to {0,0} to be considered an invalid user
void Invalidate() {
uuid = INVALID_UUID;
}
std::string Format() const;
std::string FormatSwitch() const;
};
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
constexpr std::size_t profile_username_size = 32;
using ProfileUsername = std::array<u8, profile_username_size>;
using UserIDArray = std::array<UUID, MAX_USERS>;
using UserIDArray = std::array<Common::UUID, MAX_USERS>;
/// Contains extra data related to a user.
/// TODO: RE this structure
@ -66,7 +34,7 @@ static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect
/// 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;
Common::UUID user_uuid;
ProfileUsername username;
u64 creation_time;
ProfileData data; // TODO(ognik): Work out what this is
@ -74,7 +42,7 @@ struct ProfileInfo {
};
struct ProfileBase {
UUID user_uuid;
Common::UUID user_uuid;
u64_le timestamp;
ProfileUsername username;
@ -96,33 +64,33 @@ public:
~ProfileManager();
ResultCode AddUser(const ProfileInfo& user);
ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username);
ResultCode CreateNewUser(UUID uuid, const std::string& username);
std::optional<UUID> GetUser(std::size_t index) const;
std::optional<std::size_t> GetUserIndex(const UUID& uuid) const;
ResultCode CreateNewUser(Common::UUID uuid, const ProfileUsername& username);
ResultCode CreateNewUser(Common::UUID uuid, const std::string& username);
std::optional<Common::UUID> GetUser(std::size_t index) const;
std::optional<std::size_t> GetUserIndex(const Common::UUID& uuid) const;
std::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const;
bool GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const;
bool GetProfileBase(UUID uuid, ProfileBase& profile) const;
bool GetProfileBase(Common::UUID uuid, ProfileBase& profile) const;
bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const;
bool GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile,
ProfileData& data) const;
bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const;
bool GetProfileBaseAndData(Common::UUID uuid, ProfileBase& profile, ProfileData& data) const;
bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile,
ProfileData& data) const;
std::size_t GetUserCount() const;
std::size_t GetOpenUserCount() const;
bool UserExists(UUID uuid) const;
bool UserExists(Common::UUID uuid) const;
bool UserExistsIndex(std::size_t index) const;
void OpenUser(UUID uuid);
void CloseUser(UUID uuid);
void OpenUser(Common::UUID uuid);
void CloseUser(Common::UUID uuid);
UserIDArray GetOpenUsers() const;
UserIDArray GetAllUsers() const;
UUID GetLastOpenedUser() const;
Common::UUID GetLastOpenedUser() const;
bool CanSystemRegisterUser() const;
bool RemoveUser(UUID uuid);
bool SetProfileBase(UUID uuid, const ProfileBase& profile_new);
bool RemoveUser(Common::UUID uuid);
bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new);
private:
void ParseUserSaveFile();
@ -132,7 +100,7 @@ private:
std::array<ProfileInfo, MAX_USERS> profiles{};
std::size_t user_count = 0;
UUID last_opened_user{INVALID_UUID};
Common::UUID last_opened_user{Common::INVALID_UUID};
};
}; // namespace Service::Account