uuid.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <bit>
  4. #include <optional>
  5. #include <random>
  6. #include <fmt/format.h>
  7. #include "common/assert.h"
  8. #include "common/tiny_mt.h"
  9. #include "common/uuid.h"
  10. namespace Common {
  11. namespace {
  12. constexpr size_t RawStringSize = sizeof(UUID) * 2;
  13. constexpr size_t FormattedStringSize = RawStringSize + 4;
  14. std::optional<u8> HexCharToByte(char c) {
  15. if (c >= '0' && c <= '9') {
  16. return static_cast<u8>(c - '0');
  17. }
  18. if (c >= 'a' && c <= 'f') {
  19. return static_cast<u8>(c - 'a' + 10);
  20. }
  21. if (c >= 'A' && c <= 'F') {
  22. return static_cast<u8>(c - 'A' + 10);
  23. }
  24. ASSERT_MSG(false, "{} is not a hexadecimal digit!", c);
  25. return std::nullopt;
  26. }
  27. std::array<u8, 0x10> ConstructFromRawString(std::string_view raw_string) {
  28. std::array<u8, 0x10> uuid;
  29. for (size_t i = 0; i < RawStringSize; i += 2) {
  30. const auto upper = HexCharToByte(raw_string[i]);
  31. const auto lower = HexCharToByte(raw_string[i + 1]);
  32. if (!upper || !lower) {
  33. return {};
  34. }
  35. uuid[i / 2] = static_cast<u8>((*upper << 4) | *lower);
  36. }
  37. return uuid;
  38. }
  39. std::array<u8, 0x10> ConstructFromFormattedString(std::string_view formatted_string) {
  40. std::array<u8, 0x10> uuid;
  41. size_t i = 0;
  42. // Process the first 8 characters.
  43. const auto* str = formatted_string.data();
  44. for (; i < 4; ++i) {
  45. const auto upper = HexCharToByte(*(str++));
  46. const auto lower = HexCharToByte(*(str++));
  47. if (!upper || !lower) {
  48. return {};
  49. }
  50. uuid[i] = static_cast<u8>((*upper << 4) | *lower);
  51. }
  52. // Process the next 4 characters.
  53. ++str;
  54. for (; i < 6; ++i) {
  55. const auto upper = HexCharToByte(*(str++));
  56. const auto lower = HexCharToByte(*(str++));
  57. if (!upper || !lower) {
  58. return {};
  59. }
  60. uuid[i] = static_cast<u8>((*upper << 4) | *lower);
  61. }
  62. // Process the next 4 characters.
  63. ++str;
  64. for (; i < 8; ++i) {
  65. const auto upper = HexCharToByte(*(str++));
  66. const auto lower = HexCharToByte(*(str++));
  67. if (!upper || !lower) {
  68. return {};
  69. }
  70. uuid[i] = static_cast<u8>((*upper << 4) | *lower);
  71. }
  72. // Process the next 4 characters.
  73. ++str;
  74. for (; i < 10; ++i) {
  75. const auto upper = HexCharToByte(*(str++));
  76. const auto lower = HexCharToByte(*(str++));
  77. if (!upper || !lower) {
  78. return {};
  79. }
  80. uuid[i] = static_cast<u8>((*upper << 4) | *lower);
  81. }
  82. // Process the last 12 characters.
  83. ++str;
  84. for (; i < 16; ++i) {
  85. const auto upper = HexCharToByte(*(str++));
  86. const auto lower = HexCharToByte(*(str++));
  87. if (!upper || !lower) {
  88. return {};
  89. }
  90. uuid[i] = static_cast<u8>((*upper << 4) | *lower);
  91. }
  92. return uuid;
  93. }
  94. std::array<u8, 0x10> ConstructUUID(std::string_view uuid_string) {
  95. const auto length = uuid_string.length();
  96. if (length == 0) {
  97. return {};
  98. }
  99. // Check if the input string contains 32 hexadecimal characters.
  100. if (length == RawStringSize) {
  101. return ConstructFromRawString(uuid_string);
  102. }
  103. // Check if the input string has the length of a RFC 4122 formatted UUID string.
  104. if (length == FormattedStringSize) {
  105. return ConstructFromFormattedString(uuid_string);
  106. }
  107. ASSERT_MSG(false, "UUID string has an invalid length of {} characters!", length);
  108. return {};
  109. }
  110. } // Anonymous namespace
  111. UUID::UUID(std::string_view uuid_string) : uuid{ConstructUUID(uuid_string)} {}
  112. std::string UUID::RawString() const {
  113. return fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"
  114. "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
  115. uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
  116. uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
  117. uuid[15]);
  118. }
  119. std::string UUID::FormattedString() const {
  120. return fmt::format("{:02x}{:02x}{:02x}{:02x}"
  121. "-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-"
  122. "{: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. size_t UUID::Hash() const noexcept {
  128. u64 upper_hash;
  129. u64 lower_hash;
  130. std::memcpy(&upper_hash, uuid.data(), sizeof(u64));
  131. std::memcpy(&lower_hash, uuid.data() + sizeof(u64), sizeof(u64));
  132. return upper_hash ^ std::rotl(lower_hash, 1);
  133. }
  134. u128 UUID::AsU128() const {
  135. u128 uuid_old;
  136. std::memcpy(&uuid_old, uuid.data(), sizeof(UUID));
  137. return uuid_old;
  138. }
  139. UUID UUID::MakeRandom() {
  140. std::random_device device;
  141. return MakeRandomWithSeed(device());
  142. }
  143. UUID UUID::MakeRandomWithSeed(u32 seed) {
  144. // Create and initialize our RNG.
  145. TinyMT rng;
  146. rng.Initialize(seed);
  147. UUID uuid;
  148. // Populate the UUID with random bytes.
  149. rng.GenerateRandomBytes(uuid.uuid.data(), sizeof(UUID));
  150. return uuid;
  151. }
  152. UUID UUID::MakeRandomRFC4122V4() {
  153. auto uuid = MakeRandom();
  154. // According to Proposed Standard RFC 4122 Section 4.4, we must:
  155. // 1. Set the two most significant bits (bits 6 and 7) of the
  156. // clock_seq_hi_and_reserved to zero and one, respectively.
  157. uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
  158. // 2. Set the four most significant bits (bits 12 through 15) of the
  159. // time_hi_and_version field to the 4-bit version number from Section 4.1.3.
  160. uuid.uuid[6] = 0x40 | (uuid.uuid[6] & 0xF);
  161. return uuid;
  162. }
  163. } // namespace Common