Cuberite
A lightweight, fast and extensible game server for Minecraft
UUID.cpp
Go to the documentation of this file.
1 // UUID.h
2 
3 // Defines the cUUID class representing a Universally Unique Identifier
4 
5 #include "Globals.h"
6 #include "UUID.h"
7 
8 #include "mbedtls/md5.h"
9 
10 
12 struct sShortUUID
13 {
14  char Data[32]{};
15  bool IsValid = false;
16 };
17 
20 static sShortUUID ShortenUUID(const AString & a_StringUUID)
21 {
22  sShortUUID UUID;
23  switch (a_StringUUID.size())
24  {
25  case 32:
26  {
27  // Already a short UUID
28  std::memcpy(UUID.Data, a_StringUUID.data(), 32);
29  UUID.IsValid = true;
30  break;
31  }
32  case 36:
33  {
34  // Long UUID, confirm dashed
35  if (
36  (a_StringUUID[ 8] != '-') ||
37  (a_StringUUID[13] != '-') ||
38  (a_StringUUID[18] != '-') ||
39  (a_StringUUID[23] != '-')
40  )
41  {
42  break;
43  }
44 
45  // Copy everying but the dashes from the string
46  std::memcpy(UUID.Data, a_StringUUID.data(), 8);
47  std::memcpy(UUID.Data + 8, a_StringUUID.data() + 9, 4);
48  std::memcpy(UUID.Data + 12, a_StringUUID.data() + 14, 4);
49  std::memcpy(UUID.Data + 16, a_StringUUID.data() + 19, 4);
50  std::memcpy(UUID.Data + 20, a_StringUUID.data() + 24, 12);
51  UUID.IsValid = true;
52  }
53  default: break;
54  }
55  return UUID;
56 }
57 
58 
59 
60 
61 
63 static Byte FromHexDigit(char a_Hex)
64 {
65  if (('0' <= a_Hex) && (a_Hex <= '9'))
66  {
67  return static_cast<Byte>(a_Hex - '0');
68  }
69  if (('a' <= a_Hex) && (a_Hex <= 'f'))
70  {
71  return static_cast<Byte>(10 + (a_Hex - 'a'));
72  }
73  if (('A' <= a_Hex) && (a_Hex <= 'F'))
74  {
75  return static_cast<Byte>(10 + (a_Hex - 'A'));
76  }
77  return 0xff;
78 }
79 
80 
81 
82 
83 
85 static char ToHexDigit(UInt8 a_Nibble)
86 {
87  ASSERT((a_Nibble & 0xf0) == 0);
88  return static_cast<char>(
89  (a_Nibble < 10) ?
90  ('0' + a_Nibble) :
91  ('a' + (a_Nibble - 10))
92  );
93 }
94 
95 
96 
97 
98 
100 // cUUID:
101 
102 bool cUUID::FromString(const AString & a_StringUUID)
103 {
104  sShortUUID Norm = ShortenUUID(a_StringUUID);
105  if (!Norm.IsValid)
106  {
107  return false;
108  }
109 
110  std::array<Byte, 16> ParsedUUID{{0}};
111  for (size_t i = 0; i != m_UUID.size(); ++i)
112  {
113  Byte HighNibble = FromHexDigit(Norm.Data[2 * i ]);
114  Byte LowNibble = FromHexDigit(Norm.Data[2 * i + 1]);
115  if ((HighNibble > 0x0f) || (LowNibble > 0x0f))
116  {
117  // Invalid hex digit
118  return false;
119  }
120 
121  ParsedUUID[i] = static_cast<Byte>((HighNibble << 4) | LowNibble);
122  }
123 
124  // Parsed successfully
125  m_UUID = ParsedUUID;
126  return true;
127 }
128 
129 
130 
131 
132 
134 {
135  AString ShortString(32, '\0');
136  for (size_t i = 0; i != m_UUID.size(); ++i)
137  {
138  Byte HighNibble = (m_UUID[i] >> 4) & 0x0f;
139  Byte LowNibble = m_UUID[i] & 0x0f;
140 
141  ShortString[2 * i ] = ToHexDigit(HighNibble);
142  ShortString[2 * i + 1] = ToHexDigit(LowNibble);
143  }
144  return ShortString;
145 }
146 
147 
148 
149 
150 
152 {
153  AString LongString = ToShortString();
154  LongString.reserve(36);
155 
156  // Convert to long form by inserting the dashes
157  auto First = LongString.begin();
158  LongString.insert(First + 8, '-');
159  LongString.insert(First + 13, '-');
160  LongString.insert(First + 18, '-');
161  LongString.insert(First + 23, '-');
162 
163  return LongString;
164 }
165 
166 
167 
168 
169 
171 {
172  return static_cast<UInt8>((m_UUID[6] >> 4) & 0x0f);
173 }
174 
175 
176 
177 
178 
180 {
181  const Byte VariantBits = static_cast<Byte>((m_UUID[8] >> 5) & 0x07);
182 
183  /* Variant bits format:
184  bits | variant | Description
185  -----|---------|----------------------
186  0xx | 0 | Obsolete
187  10x | 1 | Standard UUID
188  110 | 2 | Microsoft Legacy GUID
189  111 | 3 | Reserved
190  */
191 
192  if ((VariantBits & 0x04) == 0)
193  {
194  return 0;
195  }
196  else if ((VariantBits & 0x02) == 0)
197  {
198  return 1;
199  }
200  else if ((VariantBits & 0x01) == 0)
201  {
202  return 2;
203  }
204  else
205  {
206  return 3;
207  }
208 }
209 
210 
211 
212 
213 
214 std::array<Byte, 16> cUUID::ToRaw() const
215 {
216  std::array<Byte, 16> Raw(m_UUID);
217  if (Variant() == 2)
218  {
219  // Convert to microsoft mixed-endian format
220  // First 3 components are host-endian, last 2 are network
221  auto First = reinterpret_cast<UInt32 *>(Raw.data());
222  *First = ntohl(*First);
223 
224  auto Second = reinterpret_cast<UInt16 *>(&Raw[4]);
225  *Second = ntohs(*Second);
226 
227  auto Third = Second + 1;
228  *Third = ntohs(*Third);
229  }
230 
231  return Raw;
232 }
233 
234 
235 
236 
237 
238 void cUUID::FromRaw(const std::array<Byte, 16> & a_Raw)
239 {
240  m_UUID = a_Raw;
241  if (Variant() != 2)
242  {
243  // Standard big-endian formats
244  return;
245  }
246 
247  // Convert from microsoft mixed-endian format
248  // First 3 components are host-endian, last 2 are network
249  auto First = reinterpret_cast<UInt32 *>(m_UUID.data());
250  *First = htonl(*First);
251 
252  auto Second = reinterpret_cast<UInt16 *>(&m_UUID[4]);
253  *Second = htons(*Second);
254 
255  auto Third = Second + 1;
256  *Third = htons(*Third);
257 }
258 
259 
260 
261 
262 
264 {
265  cUUID UUID;
266  // Generate an md5 checksum, and use it as base for the ID:
267  const Byte * ByteString = reinterpret_cast<const Byte *>(a_Name.data());
268  mbedtls_md5(ByteString, a_Name.length(), UUID.m_UUID.data());
269 
270  // Insert version number
271  UUID.m_UUID[6] = (UUID.m_UUID[6] & 0x0f) | 0x30;
272 
273  // Insert variant number
274  UUID.m_UUID[8] = (UUID.m_UUID[8] & 0x3f) | 0x80;
275 
276  return UUID;
277 }
278 
279 
280 
281 
unsigned int UInt32
Definition: Globals.h:157
unsigned char UInt8
Definition: Globals.h:159
#define ASSERT(x)
Definition: Globals.h:276
unsigned short UInt16
Definition: Globals.h:158
unsigned char Byte
Definition: Globals.h:161
std::string AString
Definition: StringUtils.h:11
static sShortUUID ShortenUUID(const AString &a_StringUUID)
Returns the given UUID in shortened form with IsValid indicating success.
Definition: UUID.cpp:20
static char ToHexDigit(UInt8 a_Nibble)
From a number in the range [0, 16), returns the corresponding hex digit in lowercase.
Definition: UUID.cpp:85
static Byte FromHexDigit(char a_Hex)
Returns the integer value of the hex digit or 0xff if invalid.
Definition: UUID.cpp:63
UUID normalised in textual form.
Definition: UUID.cpp:13
bool IsValid
Definition: UUID.cpp:15
char Data[32]
Definition: UUID.cpp:14
Definition: UUID.h:11
AString ToShortString() const
Converts the UUID to a short form string (i.e without dashes).
Definition: UUID.cpp:133
bool FromString(const AString &a_StringUUID)
Tries to interpret the string as a short or long form UUID and assign from it.
Definition: UUID.cpp:102
static cUUID GenerateVersion3(const AString &a_Name)
Generates a version 3, variant 1 UUID based on the md5 hash of a_Name.
Definition: UUID.cpp:263
std::array< Byte, 16 > m_UUID
Binary UUID stored big-endian.
Definition: UUID.h:64
UInt8 Variant() const
Returns the variant number of the UUID.
Definition: UUID.cpp:179
UInt8 Version() const
Returns the version number of the UUID.
Definition: UUID.cpp:170
AString ToLongString() const
Converts the UUID to a long form string (i.e.
Definition: UUID.cpp:151
void FromRaw(const std::array< Byte, 16 > &a_Raw)
Assigns from raw memory representation, respecting UUID variant.
Definition: UUID.cpp:238
std::array< Byte, 16 > ToRaw() const
Converts UUID to raw memory representation, respecting UUID variant.
Definition: UUID.cpp:214