new_uuid.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright 2022 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <bit>
  5. #include <random>
  6. #include <fmt/format.h>
  7. #include "common/assert.h"
  8. #include "common/new_uuid.h"
  9. #include "common/tiny_mt.h"
  10. namespace Common {
  11. namespace {
  12. constexpr size_t RawStringSize = sizeof(NewUUID) * 2;
  13. constexpr size_t FormattedStringSize = RawStringSize + 4;
  14. 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 u8{0};
  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. uuid[i / 2] =
  31. static_cast<u8>((HexCharToByte(raw_string[i]) << 4) | HexCharToByte(raw_string[i + 1]));
  32. }
  33. return uuid;
  34. }
  35. std::array<u8, 0x10> ConstructFromFormattedString(std::string_view formatted_string) {
  36. std::array<u8, 0x10> uuid;
  37. size_t i = 0;
  38. // Process the first 8 characters.
  39. const auto* str = formatted_string.data();
  40. for (; i < 4; ++i) {
  41. uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
  42. uuid[i] |= HexCharToByte(*(str++));
  43. }
  44. // Process the next 4 characters.
  45. ++str;
  46. for (; i < 6; ++i) {
  47. uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
  48. uuid[i] |= HexCharToByte(*(str++));
  49. }
  50. // Process the next 4 characters.
  51. ++str;
  52. for (; i < 8; ++i) {
  53. uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
  54. uuid[i] |= HexCharToByte(*(str++));
  55. }
  56. // Process the next 4 characters.
  57. ++str;
  58. for (; i < 10; ++i) {
  59. uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
  60. uuid[i] |= HexCharToByte(*(str++));
  61. }
  62. // Process the last 12 characters.
  63. ++str;
  64. for (; i < 16; ++i) {
  65. uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
  66. uuid[i] |= HexCharToByte(*(str++));
  67. }
  68. return uuid;
  69. }
  70. std::array<u8, 0x10> ConstructUUID(std::string_view uuid_string) {
  71. const auto length = uuid_string.length();
  72. if (length == 0) {
  73. return {};
  74. }
  75. // Check if the input string contains 32 hexadecimal characters.
  76. if (length == RawStringSize) {
  77. return ConstructFromRawString(uuid_string);
  78. }
  79. // Check if the input string has the length of a RFC 4122 formatted UUID string.
  80. if (length == FormattedStringSize) {
  81. return ConstructFromFormattedString(uuid_string);
  82. }
  83. ASSERT_MSG(false, "UUID string has an invalid length of {} characters!", length);
  84. return {};
  85. }
  86. } // Anonymous namespace
  87. NewUUID::NewUUID(std::string_view uuid_string) : uuid{ConstructUUID(uuid_string)} {}
  88. std::string NewUUID::RawString() const {
  89. return fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"
  90. "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
  91. uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
  92. uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
  93. uuid[15]);
  94. }
  95. std::string NewUUID::FormattedString() const {
  96. return fmt::format("{:02x}{:02x}{:02x}{:02x}"
  97. "-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-"
  98. "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
  99. uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
  100. uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
  101. uuid[15]);
  102. }
  103. size_t NewUUID::Hash() const noexcept {
  104. u64 hash;
  105. u64 temp;
  106. std::memcpy(&hash, uuid.data(), sizeof(u64));
  107. std::memcpy(&temp, uuid.data() + 8, sizeof(u64));
  108. return hash ^ std::rotl(temp, 1);
  109. }
  110. NewUUID NewUUID::MakeRandom() {
  111. std::random_device device;
  112. return MakeRandomWithSeed(device());
  113. }
  114. NewUUID NewUUID::MakeRandomWithSeed(u32 seed) {
  115. // Create and initialize our RNG.
  116. TinyMT rng;
  117. rng.Initialize(seed);
  118. NewUUID uuid;
  119. // Populate the UUID with random bytes.
  120. rng.GenerateRandomBytes(uuid.uuid.data(), sizeof(NewUUID));
  121. return uuid;
  122. }
  123. NewUUID NewUUID::MakeRandomRFC4122V4() {
  124. auto uuid = MakeRandom();
  125. // According to Proposed Standard RFC 4122 Section 4.4, we must:
  126. // 1. Set the two most significant bits (bits 6 and 7) of the
  127. // clock_seq_hi_and_reserved to zero and one, respectively.
  128. uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
  129. // 2. Set the four most significant bits (bits 12 through 15) of the
  130. // time_hi_and_version field to the 4-bit version number from Section 4.1.3.
  131. uuid.uuid[6] = 0x40 | (uuid.uuid[6] & 0xF);
  132. return uuid;
  133. }
  134. } // namespace Common