1#include "uuid_manager.h"
2
3#include <base/hash_ctxt.h>
4#include <base/system.h>
5#include <engine/shared/packer.h>
6
7#include <algorithm>
8#include <cstdio>
9
10static const CUuid TEEWORLDS_NAMESPACE = {.m_aData: {// "e05ddaaa-c4e6-4cfb-b642-5d48e80c0029"
11 0xe0, 0x5d, 0xda, 0xaa, 0xc4, 0xe6, 0x4c, 0xfb,
12 0xb6, 0x42, 0x5d, 0x48, 0xe8, 0x0c, 0x00, 0x29}};
13
14const CUuid UUID_ZEROED = {.m_aData: {// "00000000-0000-0000-0000-000000000000"
15 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
17
18CUuid RandomUuid()
19{
20 CUuid Result;
21 secure_random_fill(bytes: &Result, length: sizeof(Result));
22
23 // set version 4 (UUID is randomly generated)
24 Result.m_aData[6] &= 0x0f;
25 Result.m_aData[6] |= 0x40;
26
27 // set variant 1 (RFC 4122)
28 Result.m_aData[8] &= 0x3f;
29 Result.m_aData[8] |= 0x80;
30
31 return Result;
32}
33
34CUuid CalculateUuid(const char *pName)
35{
36 MD5_CTX Md5;
37 md5_init(ctxt: &Md5);
38 md5_update(ctxt: &Md5, data: TEEWORLDS_NAMESPACE.m_aData, data_len: sizeof(TEEWORLDS_NAMESPACE.m_aData));
39 // Without terminating NUL.
40 md5_update(ctxt: &Md5, data: (const unsigned char *)pName, data_len: str_length(str: pName));
41 MD5_DIGEST Digest = md5_finish(ctxt: &Md5);
42
43 CUuid Result;
44 for(unsigned i = 0; i < sizeof(Result.m_aData); i++)
45 {
46 Result.m_aData[i] = Digest.data[i];
47 }
48
49 // set version 3 (UUID is generated by MD5 hashing a namespace identifier and a name)
50 Result.m_aData[6] &= 0x0f;
51 Result.m_aData[6] |= 0x30;
52
53 // set variant 1 (RFC 4122)
54 Result.m_aData[8] &= 0x3f;
55 Result.m_aData[8] |= 0x80;
56
57 return Result;
58}
59
60void FormatUuid(CUuid Uuid, char *pBuffer, unsigned BufferLength)
61{
62 unsigned char *p = Uuid.m_aData;
63 str_format(buffer: pBuffer, buffer_size: BufferLength,
64 format: "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
65 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
66 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
67}
68
69int ParseUuid(CUuid *pUuid, const char *pBuffer)
70{
71 if(str_length(str: pBuffer) + 1 != UUID_MAXSTRSIZE)
72 {
73 return 2;
74 }
75 char aCopy[UUID_MAXSTRSIZE];
76 str_copy(dst&: aCopy, src: pBuffer);
77 // 01234567-9012-4567-9012-456789012345
78 if(aCopy[8] != '-' || aCopy[13] != '-' || aCopy[18] != '-' || aCopy[23] != '-')
79 {
80 return 1;
81 }
82 aCopy[8] = aCopy[13] = aCopy[18] = aCopy[23] = 0;
83 if(static_cast<bool>(str_hex_decode(dst: pUuid->m_aData + 0, dst_size: 4, src: aCopy + 0)) ||
84 str_hex_decode(dst: pUuid->m_aData + 4, dst_size: 2, src: aCopy + 9) ||
85 str_hex_decode(dst: pUuid->m_aData + 6, dst_size: 2, src: aCopy + 14) ||
86 str_hex_decode(dst: pUuid->m_aData + 8, dst_size: 2, src: aCopy + 19) ||
87 str_hex_decode(dst: pUuid->m_aData + 10, dst_size: 6, src: aCopy + 24))
88 {
89 return 1;
90 }
91 return 0;
92}
93
94bool CUuid::operator==(const CUuid &Other) const
95{
96 return mem_comp(a: this, b: &Other, size: sizeof(*this)) == 0;
97}
98
99bool CUuid::operator!=(const CUuid &Other) const
100{
101 return !(*this == Other);
102}
103
104bool CUuid::operator<(const CUuid &Other) const
105{
106 return mem_comp(a: this, b: &Other, size: sizeof(*this)) < 0;
107}
108
109static int GetIndex(int Id)
110{
111 return Id - OFFSET_UUID;
112}
113
114static int GetId(int Index)
115{
116 return Index + OFFSET_UUID;
117}
118
119void CUuidManager::RegisterName(int Id, const char *pName)
120{
121 dbg_assert(GetIndex(Id) == (int)m_vNames.size(), "names must be registered with increasing ID");
122 CName Name;
123 Name.m_pName = pName;
124 Name.m_Uuid = CalculateUuid(pName);
125 dbg_assert(LookupUuid(Name.m_Uuid) == -1, "duplicate uuid");
126
127 m_vNames.push_back(x: Name);
128
129 CNameIndexed NameIndexed;
130 NameIndexed.m_Uuid = Name.m_Uuid;
131 NameIndexed.m_Id = GetIndex(Id);
132 m_vNamesSorted.insert(position: std::lower_bound(first: m_vNamesSorted.begin(), last: m_vNamesSorted.end(), val: NameIndexed), x: NameIndexed);
133}
134
135CUuid CUuidManager::GetUuid(int Id) const
136{
137 return m_vNames[GetIndex(Id)].m_Uuid;
138}
139
140const char *CUuidManager::GetName(int Id) const
141{
142 return m_vNames[GetIndex(Id)].m_pName;
143}
144
145int CUuidManager::LookupUuid(CUuid Uuid) const
146{
147 CNameIndexed Needle;
148 Needle.m_Uuid = Uuid;
149 Needle.m_Id = 0;
150 auto Range = std::equal_range(first: m_vNamesSorted.begin(), last: m_vNamesSorted.end(), val: Needle);
151 if(std::distance(first: Range.first, last: Range.second) == 1)
152 {
153 return GetId(Index: Range.first->m_Id);
154 }
155 return UUID_UNKNOWN;
156}
157
158int CUuidManager::NumUuids() const
159{
160 return m_vNames.size();
161}
162
163int CUuidManager::UnpackUuid(CUnpacker *pUnpacker) const
164{
165 CUuid Temp;
166 return UnpackUuid(pUnpacker, pOut: &Temp);
167}
168
169int CUuidManager::UnpackUuid(CUnpacker *pUnpacker, CUuid *pOut) const
170{
171 const CUuid *pUuid = (const CUuid *)pUnpacker->GetRaw(Size: sizeof(*pUuid));
172 if(pUuid == NULL)
173 {
174 return UUID_INVALID;
175 }
176 *pOut = *pUuid;
177 return LookupUuid(Uuid: *pUuid);
178}
179
180void CUuidManager::PackUuid(int Id, CPacker *pPacker) const
181{
182 CUuid Uuid = GetUuid(Id);
183 pPacker->AddRaw(pData: &Uuid, Size: sizeof(Uuid));
184}
185
186void CUuidManager::DebugDump() const
187{
188 for(const auto &Name : m_vNames)
189 {
190 char aBuf[UUID_MAXSTRSIZE];
191 FormatUuid(Uuid: Name.m_Uuid, pBuffer: aBuf, BufferLength: sizeof(aBuf));
192 dbg_msg(sys: "uuid", fmt: "%s %s", aBuf, Name.m_pName);
193 }
194}
195