Skip to content

Commit

Permalink
Merge pull request #9829 from OTAkeys/pr/uuid_string
Browse files Browse the repository at this point in the history
uuid: add uuid_to_string() and uuid_from_string()
  • Loading branch information
emmanuelsearch authored Oct 30, 2018
2 parents 18570b6 + 73e971f commit 365d82e
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 2 deletions.
1 change: 1 addition & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ endif
ifneq (,$(filter uuid,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += random
USEMODULE += fmt
endif

# Enable periph_gpio when periph_gpio_irq is enabled
Expand Down
68 changes: 68 additions & 0 deletions sys/fmt/fmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ static inline int _is_digit(char c)
return (c >= '0' && c <= '9');
}

static inline int _is_upper(char c)
{
return (c >= 'A' && c <= 'Z');
}

static inline char _to_lower(char c)
{
return 'a' + (c - 'A');
}

size_t fmt_byte_hex(char *out, uint8_t byte)
{
if (out) {
Expand Down Expand Up @@ -153,6 +163,11 @@ size_t fmt_hex_bytes(uint8_t *out, const char *hex)
return final_len;
}

size_t fmt_u16_hex(char *out, uint16_t val)
{
return fmt_bytes_hex_reverse(out, (uint8_t*) &val, 2);
}

size_t fmt_u32_hex(char *out, uint32_t val)
{
return fmt_bytes_hex_reverse(out, (uint8_t*) &val, 4);
Expand Down Expand Up @@ -400,6 +415,35 @@ size_t fmt_lpad(char *out, size_t in_len, size_t pad_len, char pad_char)
return pad_len;
}

size_t fmt_char(char *out, char c)
{
if (out) {
*out = c;
}

return 1;
}

size_t fmt_to_lower(char *out, const char *str)
{
size_t len = 0;

while (str && *str) {
if (_is_upper(*str)) {
if (out) {
*out++ = _to_lower(*str);
}
}
else if (out) {
*out++ = *str;
}
str++;
len++;
}

return len;
}

uint32_t scn_u32_dec(const char *str, size_t n)
{
uint32_t res = 0;
Expand All @@ -416,6 +460,30 @@ uint32_t scn_u32_dec(const char *str, size_t n)
return res;
}

uint32_t scn_u32_hex(const char *str, size_t n)
{
uint32_t res = 0;

while (n--) {
char c = *str++;
if (!_is_digit(c)) {
if (_is_upper(c)) {
c = _to_lower(c);
}
if (c == '\0' || c > 'f') {
break;
}
res <<= 4;
res |= c - 'a' + 0xa;
}
else {
res <<= 4;
res |= c - '0';
}
}
return res;
}

void print(const char *s, size_t n)
{
#ifdef __WITH_AVRLIBC__
Expand Down
47 changes: 47 additions & 0 deletions sys/include/fmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,20 @@ uint8_t fmt_hex_byte(const char *hex);
*/
size_t fmt_hex_bytes(uint8_t *out, const char *hex);

/**
* @brief Convert a uint16 value to hex string.
*
* Will write 4 bytes to @p out.
* If @p out is NULL, will only return the number of bytes that would have
* been written.
*
* @param[out] out Pointer to output buffer, or NULL
* @param[in] val Value to convert
*
* @return 4
*/
size_t fmt_u16_hex(char *out, uint16_t val);

/**
* @brief Convert a uint32 value to hex string.
*
Expand Down Expand Up @@ -296,6 +310,19 @@ size_t fmt_s32_dfp(char *out, int32_t val, int fp_digits);
*/
size_t fmt_float(char *out, float f, unsigned precision);

/**
* @brief Copy @p in char to string (without terminating '\0')
*
* If @p out is NULL, will only return the number of bytes that would have
* been written.
*
* @param[out] out string to write to (or NULL)
* @param[in] c char value to append
*
* @return nr of bytes the function did or would write to out
*/
size_t fmt_char(char *out, char c);

/**
* @brief Count characters until '\0' (exclusive) in @p str
*
Expand Down Expand Up @@ -329,6 +356,14 @@ size_t fmt_strnlen(const char *str, size_t maxlen);
*/
size_t fmt_str(char *out, const char *str);

/**
* @brief Copy null-terminated string to a lowercase string (excluding terminating \0)
*
* @param[out] out Pointer to output buffer, or NULL
* @param[in] str Pointer to null-terminated source string
*/
size_t fmt_to_lower(char *out, const char *str);

/**
* @brief Convert digits to uint32
*
Expand All @@ -341,6 +376,18 @@ size_t fmt_str(char *out, const char *str);
*/
uint32_t scn_u32_dec(const char *str, size_t n);

/**
* @brief Convert hexadecimal characters to uin32_t
*
* Will convert up to @p n char. Stop at any non-hexadecimal or '\0' character
*
* @param[in] str Pointer to tring to read from
* @param[in] n Maximum number of characters to consider
*
* @return converted uint32_t value
*/
uint32_t scn_u32_hex(const char *str, size_t n);

/**
* @brief Print string to stdout
*
Expand Down
24 changes: 22 additions & 2 deletions sys/include/uuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ extern "C" {

#define UUID_NODE_LEN (6U) /**< Size of the node identifier in bytes */

#define UUID_STR_LEN (36U) /**< Size of a string UUID without null character */

/**
* @name UUID version identifiers
* @{
Expand Down Expand Up @@ -120,7 +122,7 @@ void uuid_v5(uuid_t *uuid, const uuid_t *ns, const uint8_t *name, size_t len);
*
* @return Version number
*/
static inline unsigned uuid_version(uuid_t *uuid)
static inline unsigned uuid_version(const uuid_t *uuid)
{
uint16_t time_hi_vers = byteorder_ntohs(uuid->time_hi);

Expand All @@ -135,11 +137,29 @@ static inline unsigned uuid_version(uuid_t *uuid)
*
* @return True when equal
*/
static inline bool uuid_equal(uuid_t *uuid1, uuid_t *uuid2)
static inline bool uuid_equal(const uuid_t *uuid1, const uuid_t *uuid2)
{
return (memcmp(uuid1, uuid2, sizeof(uuid_t)) == 0);
}

/**
* @brief Generate an UUID string from an UUID structure
*
* @param[in] uuid UUID
* @param[out] str null-terminated UUID string, must be at least UUID_STR_LEN + 1 bytes
*/
void uuid_to_string(const uuid_t *uuid, char *str);

/**
* @brief Populate an UUID structure from an UUID string
*
* @param[out] uuid out UUID
* @param[in] str null-terminated input UUID string, must be UUID_STR_LEN bytes
*
* @return 0 on succes, < 0 if @p str is not valid
*/
int uuid_from_string(uuid_t *uuid, const char *str);

#ifdef __cplusplus
}
#endif
Expand Down
57 changes: 57 additions & 0 deletions sys/uuid/uuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "hashes/sha1.h"
#include "random.h"
#include "uuid.h"
#include "fmt.h"

const uuid_t uuid_namespace_dns = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
.time_low.u8 = { 0x6b, 0xa7, 0xb8, 0x10 },
Expand Down Expand Up @@ -110,3 +111,59 @@ void uuid_v5(uuid_t *uuid, const uuid_t *ns, const uint8_t *name, size_t len)
_set_version(uuid, UUID_V5);
_set_reserved(uuid);
}

void uuid_to_string(const uuid_t *uuid, char *str)
{
char *p = str;
p += fmt_u32_hex(p, byteorder_ntohl(uuid->time_low));
p += fmt_char(p, '-');
p += fmt_u16_hex(p, byteorder_ntohs(uuid->time_mid));
p += fmt_char(p, '-');
p += fmt_u16_hex(p, byteorder_ntohs(uuid->time_hi));
p += fmt_char(p, '-');
p += fmt_byte_hex(p, uuid->clk_seq_hi_res);
p += fmt_byte_hex(p, uuid->clk_seq_low);
p += fmt_char(p, '-');
p += fmt_bytes_hex(p, uuid->node, UUID_NODE_LEN);
*p = '\0';
fmt_to_lower(str, str);
}

int uuid_from_string(uuid_t *uuid, const char *str)
{
uint32_t tmp;
if (fmt_strlen(str) < UUID_STR_LEN) {
return -1;
}
tmp = scn_u32_hex(str, 8);
uuid->time_low = byteorder_htonl(tmp);
str += 8;
if (*str++ != '-') {
return -2;
}
tmp = scn_u32_hex(str, 4);
uuid->time_mid = byteorder_htons(tmp);
str += 4;
if (*str++ != '-') {
return -2;
}
tmp = scn_u32_hex(str, 4);
uuid->time_hi = byteorder_htons(tmp);
str += 4;
if (*str++ != '-') {
return -2;
}
uuid->clk_seq_hi_res = scn_u32_hex(str, 2);
str += 2;
uuid->clk_seq_low = scn_u32_hex(str, 2);
str += 2;
if (*str++ != '-') {
return -2;
}
for (unsigned i = 0; i < UUID_NODE_LEN; i++) {
uuid->node[i] = scn_u32_hex(str, 2);
str += 2;
}

return 0;
}
34 changes: 34 additions & 0 deletions tests/unittests/tests-fmt/tests-fmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,26 @@ static void test_fmt_str(void)
TEST_ASSERT_EQUAL_STRING(string1, &string2[0]);
}

static void test_fmt_char(void)
{
char string[] = "zzzzzzzzz";

TEST_ASSERT_EQUAL_INT(1, fmt_char(NULL, 'c'));
TEST_ASSERT_EQUAL_INT(1, fmt_char(string, 'c'));
string[1] = '\0';
TEST_ASSERT_EQUAL_STRING("c", &string[0]);
}

static void test_fmt_to_lower(void)
{
const char string_up[] = "AbCdeFGHijkLM";
char string[] = "zzzzzzzzzzzzzzz";

TEST_ASSERT_EQUAL_INT(fmt_strlen(string_up), fmt_to_lower(string, string_up));
string[fmt_strlen(string_up)] = '\0';
TEST_ASSERT_EQUAL_STRING("abcdefghijklm", &string[0]);
}

static void test_scn_u32_dec(void)
{
const char *string1 = "123456789";
Expand All @@ -759,6 +779,17 @@ static void test_scn_u32_dec(void)
TEST_ASSERT_EQUAL_INT(val2, scn_u32_dec(string1, 5));
}

static void test_scn_u32_hex(void)
{
const char *string1 = "aB12cE4F";
uint32_t val1 = 0xab12ce4f;
uint32_t val2 = 0xab1;

TEST_ASSERT_EQUAL_INT(val1, scn_u32_hex(string1, 8));
TEST_ASSERT_EQUAL_INT(val2, scn_u32_hex(string1, 3));
TEST_ASSERT_EQUAL_INT(val1, scn_u32_hex(string1, 9));
}

static void test_fmt_lpad(void)
{
const char base[] = "abcd";
Expand Down Expand Up @@ -817,7 +848,10 @@ Test *tests_fmt_tests(void)
new_TestFixture(test_fmt_strlen),
new_TestFixture(test_fmt_strnlen),
new_TestFixture(test_fmt_str),
new_TestFixture(test_fmt_char),
new_TestFixture(test_fmt_to_lower),
new_TestFixture(test_scn_u32_dec),
new_TestFixture(test_scn_u32_hex),
new_TestFixture(test_fmt_lpad),
};

Expand Down
34 changes: 34 additions & 0 deletions tests/unittests/tests-uuid/tests-uuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,46 @@ void test_uuid_v5(void)
TEST_ASSERT_EQUAL_INT(uuid_version(&uuid_next), UUID_V5);
}

void test_uuid_str(void)
{
char str[40];
const char dns[] = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
uuid_to_string(&uuid_namespace_dns, str);
TEST_ASSERT_EQUAL_INT(0, memcmp(dns, str, sizeof(dns)));

const char url[] = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
uuid_to_string(&uuid_namespace_url, str);
TEST_ASSERT_EQUAL_INT(0, memcmp(url, str, sizeof(dns)));

const char iso[] = "6ba7b812-9dad-11d1-80b4-00c04fd430c8";
uuid_to_string(&uuid_namespace_iso, str);
TEST_ASSERT_EQUAL_INT(0, memcmp(iso, str, sizeof(dns)));

const char x500[] = "6ba7b814-9dad-11d1-80b4-00c04fd430c8";
uuid_to_string(&uuid_namespace_x500, str);
TEST_ASSERT_EQUAL_INT(0, memcmp(x500, str, sizeof(dns)));

uuid_t uuid;
TEST_ASSERT_EQUAL_INT(0, uuid_from_string(&uuid, dns));
TEST_ASSERT_EQUAL_INT(true, uuid_equal(&uuid, &uuid_namespace_dns));

TEST_ASSERT_EQUAL_INT(0, uuid_from_string(&uuid, url));
TEST_ASSERT_EQUAL_INT(true, uuid_equal(&uuid, &uuid_namespace_url));

TEST_ASSERT_EQUAL_INT(0, uuid_from_string(&uuid, iso));
TEST_ASSERT_EQUAL_INT(true, uuid_equal(&uuid, &uuid_namespace_iso));

TEST_ASSERT_EQUAL_INT(0, uuid_from_string(&uuid, x500));
TEST_ASSERT_EQUAL_INT(true, uuid_equal(&uuid, &uuid_namespace_x500));
}

Test *tests_uuid_all(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_uuid_v3),
new_TestFixture(test_uuid_v4),
new_TestFixture(test_uuid_v5),
new_TestFixture(test_uuid_str),
};

EMB_UNIT_TESTCALLER(uuid_tests, NULL, NULL, fixtures);
Expand Down

0 comments on commit 365d82e

Please sign in to comment.