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