diff options
| author | 2023-12-24 04:26:00 -0600 | |
|---|---|---|
| committer | 2023-12-24 04:26:00 -0600 | |
| commit | 20d9fc5b5356a1054cb104ba6651b77184abf0db (patch) | |
| tree | 5f115d8051dad73069d3a632a6f2c260cf7efdac /src/uuid | |
initial commit
Diffstat (limited to 'src/uuid')
| -rw-r--r-- | src/uuid/uuid.c | 123 | ||||
| -rw-r--r-- | src/uuid/uuid.h | 27 |
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 */ |
