#include "uuid.h" #include #include #include #include /* 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, "%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; } int l2_uuid_compare(const uuid_t *c1, const uuid_t *c2) { return memcmp(c1, c2, 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; }