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