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:
commit
365d82ed09
@ -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
|
||||
|
@ -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__
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user