From ca5638a1426ce560f3896b3ff0d3efd02b654585 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Tue, 18 Dec 2018 09:07:25 -0500
Subject: [PATCH] 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.
---
 src/common/CMakeLists.txt                    |  2 +
 src/common/uuid.cpp                          | 33 ++++++++++
 src/common/uuid.h                            | 45 +++++++++++++
 src/core/hle/service/acc/acc.cpp             | 18 +++---
 src/core/hle/service/acc/profile_manager.cpp | 22 +------
 src/core/hle/service/acc/profile_manager.h   | 66 +++++---------------
 6 files changed, 108 insertions(+), 78 deletions(-)
 create mode 100644 src/common/uuid.cpp
 create mode 100644 src/common/uuid.h

diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 1e8e1b215b..cb514a0d27 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -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
diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp
new file mode 100644
index 0000000000..8e63b58b85
--- /dev/null
+++ b/src/common/uuid.cpp
@@ -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
diff --git a/src/common/uuid.h b/src/common/uuid.h
new file mode 100644
index 0000000000..4a5e5fa7cc
--- /dev/null
+++ b/src/common/uuid.h
@@ -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
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index ba7d7acbd4..86bf53d08f 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -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;
     }
 
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 1316d0b07b..767523dbca 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -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();
 
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index c4ce2e0b38..fd7abb5417 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -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