summaryrefslogtreecommitdiff
path: root/src/uuid.cpp
blob: a53bf27c9fb3e846b3bb958ec6ffbc4e661a4a3e (plain)
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
#include <erebos/uuid.h>

#include <stdexcept>

#include <openssl/rand.h>

using namespace erebos;

using std::nullopt;
using std::optional;
using std::runtime_error;
using std::string;

static const size_t UUID_STR_LEN = 36;

static const char * FORMAT_STRING = "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-"
	"%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx";

UUID::UUID(const string & str)
{
	if (!fromString(str, *this))
		throw runtime_error("invalid UUID");
}

UUID::operator string() const
{
	string str(UUID_STR_LEN, '\0');
	snprintf(str.data(), UUID_STR_LEN + 1, FORMAT_STRING,
			uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
			uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
	return str;
}

optional<UUID> UUID::fromString(const string & str)
{
	UUID u;
	if (fromString(str, u))
		return u;
	return nullopt;
}

bool UUID::fromString(const string & str, UUID & u)
{
	if (str.size() != UUID_STR_LEN)
		return false;

	if (sscanf(str.c_str(), FORMAT_STRING,
				&u.uuid[0], &u.uuid[1], &u.uuid[2], &u.uuid[3], &u.uuid[4], &u.uuid[5], &u.uuid[6], &u.uuid[7],
				&u.uuid[8], &u.uuid[9], &u.uuid[10], &u.uuid[11], &u.uuid[12], &u.uuid[13], &u.uuid[14], &u.uuid[15])
			!= 16)
		return false;

	return true;
}

UUID UUID::generate()
{
	UUID u;
	if (RAND_bytes(u.uuid.data(), u.uuid.size()) != 1)
		throw runtime_error("failed to generate random UUID");

	u.uuid[6] = (u.uuid[6] & 0x0f) | 0x40;
	u.uuid[8] = (u.uuid[8] & 0x3f) | 0x80;
	return u;
}

bool UUID::operator==(const UUID & other) const
{
	return std::equal(std::begin(uuid), std::end(uuid), std::begin(other.uuid));
}

bool UUID::operator!=(const UUID & other) const
{
	return !(*this == other);
}