aboutsummaryrefslogtreecommitdiffstats
path: root/src/uuid
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2023-12-24 04:26:00 -0600
committerLibravatar bigfoot547 <[email protected]>2023-12-24 04:26:00 -0600
commit20d9fc5b5356a1054cb104ba6651b77184abf0db (patch)
tree5f115d8051dad73069d3a632a6f2c260cf7efdac /src/uuid
initial commit
Diffstat (limited to 'src/uuid')
-rw-r--r--src/uuid/uuid.c123
-rw-r--r--src/uuid/uuid.h27
2 files changed, 150 insertions, 0 deletions
diff --git a/src/uuid/uuid.c b/src/uuid/uuid.c
new file mode 100644
index 0000000..0d49f0b
--- /dev/null
+++ b/src/uuid/uuid.c
@@ -0,0 +1,123 @@
+#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->halves[1] &= ~(UINT64_C(0x0F) << 12);
+ id->halves[1] |= (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->halves[0] &= mask;
+ id->halves[0] |= 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->halves[1] >> 32, /* time-low */
+ id->halves[1] >> 16 & 0xffff, /* time-mid */
+ id->halves[1] & 0xffff, /* time-high-and-version */
+ id->halves[0] >> 48, /* clock-seq-and-reserved, clock-seq-low */
+ id->halves[0] & UINT64_C(0xffffffffffff)); /* node */
+}
+
+void l2_uuid_to_string_short(const uuid_t *id, char *out)
+{
+ snprintf(out, UUID_STRLEN_SHORT + 1, "%08" PRIx64 "%08" 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;
+
+ memcpy(id, &outid, sizeof(uuid_t));
+ return true;
+}
+
+/* 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;
+}
diff --git a/src/uuid/uuid.h b/src/uuid/uuid.h
new file mode 100644
index 0000000..740fa17
--- /dev/null
+++ b/src/uuid/uuid.h
@@ -0,0 +1,27 @@
+#ifndef L2SU_UUID_H_INCLUDED
+#define L2SU_UUID_H_INCLUDED
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/* A 128-bit GUID as specified by RFC 4122.
+ * NOTE: halves[0] is the least significant half of the GUID. */
+typedef union tag_uuid_t {
+ uint8_t bytes[16];
+ uint64_t halves[2];
+} uuid_t;
+
+#define UUID_NULL_INIT { { 0 } }
+
+#define UUID_STRLEN (36u)
+#define UUID_STRLEN_SHORT (32u)
+
+void l2_uuid_random(uuid_t *id);
+
+void l2_uuid_to_string(const uuid_t *id, char *out);
+void l2_uuid_to_string_short(const uuid_t *id, char *out);
+
+bool l2_uuid_from_string(uuid_t *id, const char *str);
+bool l2_uuid_from_string_short(uuid_t *id, const char *str);
+
+#endif /* include guard */