From c00945ec1e5804003fb47798e86cd0c737a14d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Sat, 6 Jun 2020 14:47:45 +0200 Subject: UUID: random generation and format checking functions --- include/erebos/uuid.h | 9 ++++++++- src/uuid.cpp | 47 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/include/erebos/uuid.h b/include/erebos/uuid.h index 9b615f8..e67677a 100644 --- a/include/erebos/uuid.h +++ b/include/erebos/uuid.h @@ -1,15 +1,22 @@ #pragma once #include +#include #include namespace erebos { struct UUID { - explicit UUID(std::string); + UUID(): uuid({}) {} + explicit UUID(const std::string &); explicit operator std::string() const; + static std::optional fromString(const std::string &); + static bool fromString(const std::string &, UUID &); + + static UUID generate(); + bool operator==(const UUID &) const; bool operator!=(const UUID &) const; diff --git a/src/uuid.cpp b/src/uuid.cpp index 9af32b7..a53bf27 100644 --- a/src/uuid.cpp +++ b/src/uuid.cpp @@ -2,8 +2,12 @@ #include +#include + using namespace erebos; +using std::nullopt; +using std::optional; using std::runtime_error; using std::string; @@ -12,15 +16,9 @@ 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(string str) +UUID::UUID(const string & str) { - if (str.size() != UUID_STR_LEN) - throw runtime_error("invalid UUID"); - - if (sscanf(str.c_str(), 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]) - != 16) + if (!fromString(str, *this)) throw runtime_error("invalid UUID"); } @@ -33,6 +31,39 @@ UUID::operator string() const return str; } +optional 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)); -- cgit v1.2.3