summaryrefslogtreecommitdiff
path: root/src/common/uuid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/uuid.cpp')
-rw-r--r--src/common/uuid.cpp185
1 files changed, 143 insertions, 42 deletions
diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp
index d7435a6e9..10a1b86e0 100644
--- a/src/common/uuid.cpp
+++ b/src/common/uuid.cpp
@@ -1,21 +1,22 @@
1// Copyright 2018 yuzu Emulator Project 1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <bit>
5#include <random> 6#include <random>
6 7
7#include <fmt/format.h> 8#include <fmt/format.h>
8 9
9#include "common/assert.h" 10#include "common/assert.h"
11#include "common/tiny_mt.h"
10#include "common/uuid.h" 12#include "common/uuid.h"
11 13
12namespace Common { 14namespace Common {
13 15
14namespace { 16namespace {
15 17
16bool IsHexDigit(char c) { 18constexpr size_t RawStringSize = sizeof(UUID) * 2;
17 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); 19constexpr size_t FormattedStringSize = RawStringSize + 4;
18}
19 20
20u8 HexCharToByte(char c) { 21u8 HexCharToByte(char c) {
21 if (c >= '0' && c <= '9') { 22 if (c >= '0' && c <= '9') {
@@ -31,57 +32,157 @@ u8 HexCharToByte(char c) {
31 return u8{0}; 32 return u8{0};
32} 33}
33 34
34} // Anonymous namespace 35std::array<u8, 0x10> ConstructFromRawString(std::string_view raw_string) {
36 std::array<u8, 0x10> uuid;
37
38 for (size_t i = 0; i < RawStringSize; i += 2) {
39 uuid[i / 2] =
40 static_cast<u8>((HexCharToByte(raw_string[i]) << 4) | HexCharToByte(raw_string[i + 1]));
41 }
42
43 return uuid;
44}
45
46std::array<u8, 0x10> ConstructFromFormattedString(std::string_view formatted_string) {
47 std::array<u8, 0x10> uuid;
35 48
36u128 HexStringToU128(std::string_view hex_string) { 49 size_t i = 0;
37 const size_t length = hex_string.length();
38 50
39 // Detect "0x" prefix. 51 // Process the first 8 characters.
40 const bool has_0x_prefix = length > 2 && hex_string[0] == '0' && hex_string[1] == 'x'; 52 const auto* str = formatted_string.data();
41 const size_t offset = has_0x_prefix ? 2 : 0;
42 53
43 // Check length. 54 for (; i < 4; ++i) {
44 if (length > 32 + offset) { 55 uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
45 ASSERT_MSG(false, "hex_string has more than 32 hexadecimal characters!"); 56 uuid[i] |= HexCharToByte(*(str++));
46 return INVALID_UUID;
47 } 57 }
48 58
49 u64 lo = 0; 59 // Process the next 4 characters.
50 u64 hi = 0; 60 ++str;
51 for (size_t i = 0; i < length - offset; ++i) { 61
52 const char c = hex_string[length - 1 - i]; 62 for (; i < 6; ++i) {
53 if (!IsHexDigit(c)) { 63 uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
54 ASSERT_MSG(false, "{} is not a hexadecimal digit!", c); 64 uuid[i] |= HexCharToByte(*(str++));
55 return INVALID_UUID; 65 }
56 } 66
57 if (i < 16) { 67 // Process the next 4 characters.
58 lo |= u64{HexCharToByte(c)} << (i * 4); 68 ++str;
59 } 69
60 if (i >= 16) { 70 for (; i < 8; ++i) {
61 hi |= u64{HexCharToByte(c)} << ((i - 16) * 4); 71 uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
62 } 72 uuid[i] |= HexCharToByte(*(str++));
63 } 73 }
64 return u128{lo, hi}; 74
75 // Process the next 4 characters.
76 ++str;
77
78 for (; i < 10; ++i) {
79 uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
80 uuid[i] |= HexCharToByte(*(str++));
81 }
82
83 // Process the last 12 characters.
84 ++str;
85
86 for (; i < 16; ++i) {
87 uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
88 uuid[i] |= HexCharToByte(*(str++));
89 }
90
91 return uuid;
65} 92}
66 93
67UUID UUID::Generate() { 94std::array<u8, 0x10> ConstructUUID(std::string_view uuid_string) {
95 const auto length = uuid_string.length();
96
97 if (length == 0) {
98 return {};
99 }
100
101 // Check if the input string contains 32 hexadecimal characters.
102 if (length == RawStringSize) {
103 return ConstructFromRawString(uuid_string);
104 }
105
106 // Check if the input string has the length of a RFC 4122 formatted UUID string.
107 if (length == FormattedStringSize) {
108 return ConstructFromFormattedString(uuid_string);
109 }
110
111 ASSERT_MSG(false, "UUID string has an invalid length of {} characters!", length);
112
113 return {};
114}
115
116} // Anonymous namespace
117
118UUID::UUID(std::string_view uuid_string) : uuid{ConstructUUID(uuid_string)} {}
119
120std::string UUID::RawString() const {
121 return fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"
122 "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
123 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
124 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
125 uuid[15]);
126}
127
128std::string UUID::FormattedString() const {
129 return fmt::format("{:02x}{:02x}{:02x}{:02x}"
130 "-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-"
131 "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
132 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
133 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
134 uuid[15]);
135}
136
137size_t UUID::Hash() const noexcept {
138 u64 hash;
139 u64 temp;
140
141 std::memcpy(&hash, uuid.data(), sizeof(u64));
142 std::memcpy(&temp, uuid.data() + 8, sizeof(u64));
143
144 return hash ^ std::rotl(temp, 1);
145}
146
147u128 UUID::AsU128() const {
148 u128 uuid_old;
149 std::memcpy(&uuid_old, uuid.data(), sizeof(UUID));
150 return uuid_old;
151}
152
153UUID UUID::MakeRandom() {
68 std::random_device device; 154 std::random_device device;
69 std::mt19937 gen(device()); 155
70 std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max()); 156 return MakeRandomWithSeed(device());
71 return UUID{distribution(gen), distribution(gen)};
72} 157}
73 158
74std::string UUID::Format() const { 159UUID UUID::MakeRandomWithSeed(u32 seed) {
75 return fmt::format("{:016x}{:016x}", uuid[1], uuid[0]); 160 // Create and initialize our RNG.
161 TinyMT rng;
162 rng.Initialize(seed);
163
164 UUID uuid;
165
166 // Populate the UUID with random bytes.
167 rng.GenerateRandomBytes(uuid.uuid.data(), sizeof(UUID));
168
169 return uuid;
76} 170}
77 171
78std::string UUID::FormatSwitch() const { 172UUID UUID::MakeRandomRFC4122V4() {
79 std::array<u8, 16> s{}; 173 auto uuid = MakeRandom();
80 std::memcpy(s.data(), uuid.data(), sizeof(u128)); 174
81 return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{" 175 // According to Proposed Standard RFC 4122 Section 4.4, we must:
82 ":02x}{:02x}{:02x}{:02x}{:02x}", 176
83 s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], 177 // 1. Set the two most significant bits (bits 6 and 7) of the
84 s[12], s[13], s[14], s[15]); 178 // clock_seq_hi_and_reserved to zero and one, respectively.
179 uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
180
181 // 2. Set the four most significant bits (bits 12 through 15) of the
182 // time_hi_and_version field to the 4-bit version number from Section 4.1.3.
183 uuid.uuid[6] = 0x40 | (uuid.uuid[6] & 0xF);
184
185 return uuid;
85} 186}
86 187
87} // namespace Common 188} // namespace Common