1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
#include "uuid.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <sys/random.h> /* not very portable but idc */
bool l2__str_to_uint64(uint64_t *out, const char *str);
void l2_uuid__set_version(uuid_t *id, unsigned version)
{
version &= 0x0F;
id->uuid_ms &= ~(UINT64_C(0x0F) << 12);
id->uuid_ms |= (uint64_t)version << 12;
}
void l2_uuid__set_variant(uuid_t *id, unsigned variant, unsigned bits)
{
uint64_t mask = (UINT64_C(1) << (64 - bits)) - 1;
uint64_t lvariant = (uint64_t)variant << (64 - bits);
lvariant &= ~mask;
id->uuid_ls &= mask;
id->uuid_ls |= lvariant;
}
void l2_uuid_random(uuid_t *id)
{
getentropy(id, sizeof(uuid_t));
l2_uuid__set_version(id, 4);
l2_uuid__set_variant(id, 2, 2);
}
void l2_uuid_to_string(const uuid_t *id, char *out)
{
snprintf(out, UUID_STRLEN + 1, "%08" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%012" PRIx64,
id->uuid_ms >> 32, /* time-low */
id->uuid_ms >> 16 & 0xffff, /* time-mid */
id->uuid_ms & 0xffff, /* time-high-and-version */
id->uuid_ls >> 48, /* clock-seq-and-reserved, clock-seq-low */
id->uuid_ls & UINT64_C(0xffffffffffff)); /* node */
}
void l2_uuid_to_string_short(const uuid_t *id, char *out)
{
snprintf(out, UUID_STRLEN_SHORT + 1, "%016" PRIx64 "%016" PRIx64, id->halves[1], id->halves[0]);
}
bool l2_uuid_from_string(uuid_t *id, const char *str)
{
size_t slen = strlen(str);
char rbuf[UUID_STRLEN_SHORT + 1];
if (slen != UUID_STRLEN) return false;
memcpy(rbuf, str, 8);
memcpy(rbuf + 8, str + 9, 4);
memcpy(rbuf + 12, str + 14, 4);
memcpy(rbuf + 16, str + 19, 4);
memcpy(rbuf + 20, str + 24, 12);
rbuf[UUID_STRLEN_SHORT] = '\0';
return l2_uuid_from_string_short(id, rbuf);
}
bool l2_uuid_from_string_short(uuid_t *id, const char *str)
{
size_t slen = strlen(str);
uuid_t outid;
if (slen != UUID_STRLEN_SHORT) return false;
if (!l2__str_to_uint64(outid.halves + 1, str)) return false;
if (!l2__str_to_uint64(outid.halves, str + 16)) return false;
l2_uuid_copy(id, &outid);
return true;
}
int l2_uuid_compare(const uuid_t *c1, const uuid_t *c2)
{
return memcmp(c1, c2, sizeof(uuid_t));
}
void l2_uuid_copy(uuid_t *restrict dest, const uuid_t *restrict in) {
memcpy(dest, in, sizeof(uuid_t));
}
/* This function exists because there's not a portable way to do this.
* Don't suggest strtoull, because uint64_t may not be a ulonglong. */
bool l2__str_to_uint64(uint64_t *out, const char *str)
{
*out = 0;
str += 15;
for (unsigned i = 0; i < 16; ++i, --str) {
switch (*str) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
*out |= (uint64_t)(*str - '0') << (i * 4);
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
*out |= (uint64_t)(*str - 'a' + 10) << (i * 4);
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
*out |= (uint64_t)(*str - 'A' + 10) << (i * 4);
break;
default:
return false;
}
}
return true;
}
|