1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #9829 from OTAkeys/pr/uuid_string

uuid: add uuid_to_string() and uuid_from_string()
This commit is contained in:
Emmanuel Baccelli 2018-10-30 14:30:47 +01:00 committed by GitHub
commit 365d82ed09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 263 additions and 2 deletions

View File

@ -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

View File

@ -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) {
@ -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);
@ -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;
@ -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__

View File

@ -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.
*
@ -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
*
@ -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
*
@ -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
*

View File

@ -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
* @{
@ -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);
@ -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

View File

@ -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 },
@ -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;
}

View File

@ -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";
@ -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";
@ -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),
};

View File

@ -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);