feature: implement UUID generation and conversion functions for Linux and Windows
This commit is contained in:
parent
4917595535
commit
9a7fca48bb
4 changed files with 191 additions and 0 deletions
|
|
@ -62,6 +62,12 @@ endif ()
|
|||
|
||||
if (UNIX)
|
||||
target_compile_definitions(${MODULE_NAME} PRIVATE _GNU_SOURCE=1)
|
||||
find_library(UUID_LIB uuid NAMES libuuid)
|
||||
if (NOT UUID_LIB)
|
||||
target_compile_definitions(${MODULE_NAME} PRIVATE DRANG_NO_LIBUUID=1)
|
||||
else ()
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE ${UUID_LIB})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
|
|
|
|||
20
Source/DrangPlatform/Source/linux/uuid.c
Normal file
20
Source/DrangPlatform/Source/linux/uuid.c
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "drang/error.h"
|
||||
#include <drang/uuid.h>
|
||||
#include <uuid/uuid.h>
|
||||
int drang_uuid_generate(drang_uuid_t *out_uuid)
|
||||
{
|
||||
uuid_t linux_uuid;
|
||||
uuid_generate_random(linux_uuid);
|
||||
|
||||
// Convert to our format (UUID is stored as big-endian bytes)
|
||||
out_uuid->high = ((uint64_t)linux_uuid[0] << 56) | ((uint64_t)linux_uuid[1] << 48) |
|
||||
((uint64_t)linux_uuid[2] << 40) | ((uint64_t)linux_uuid[3] << 32) |
|
||||
((uint64_t)linux_uuid[4] << 24) | ((uint64_t)linux_uuid[5] << 16) |
|
||||
((uint64_t)linux_uuid[6] << 8) | ((uint64_t)linux_uuid[7]);
|
||||
|
||||
out_uuid->low = ((uint64_t)linux_uuid[8] << 56) | ((uint64_t)linux_uuid[9] << 48) |
|
||||
((uint64_t)linux_uuid[10] << 40) | ((uint64_t)linux_uuid[11] << 32) |
|
||||
((uint64_t)linux_uuid[12] << 24) | ((uint64_t)linux_uuid[13] << 16) |
|
||||
((uint64_t)linux_uuid[14] << 8) | ((uint64_t)linux_uuid[15]);
|
||||
return DRANG_EOK;
|
||||
}
|
||||
142
Source/DrangPlatform/Source/uuid.c
Normal file
142
Source/DrangPlatform/Source/uuid.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#include "drang/error.h"
|
||||
#include <ctype.h>
|
||||
#include <drang/uuid.h>
|
||||
#include <stdio.h>
|
||||
int drang_uuid_to_string(const drang_uuid_t *uuid, char *out_str, size_t str_size)
|
||||
{
|
||||
uint8_t bytes[16];
|
||||
// Convert back to bytes for string formatting
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bytes[i] = (uint8_t)(uuid->high >> (56 - i * 8));
|
||||
bytes[i + 8] = (uint8_t)(uuid->low >> (56 - i * 8));
|
||||
}
|
||||
|
||||
return snprintf(out_str, str_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
bytes[0], bytes[1], bytes[2], bytes[3],
|
||||
bytes[4], bytes[5], bytes[6], bytes[7],
|
||||
bytes[8], bytes[9], bytes[10], bytes[11],
|
||||
bytes[12], bytes[13], bytes[14], bytes[15]);
|
||||
}
|
||||
|
||||
static int hex_char_to_value(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_hex_byte(const char *str, uint8_t *byte) {
|
||||
int high = hex_char_to_value(str[0]);
|
||||
int low = hex_char_to_value(str[1]);
|
||||
|
||||
if (high < 0 || low < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*byte = (uint8_t)((high << 4) | low);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drang_uuid_from_string(const char *str, size_t str_size, drang_uuid_t *out_uuid)
|
||||
{
|
||||
DRANG_BEGIN_TRY()
|
||||
|
||||
DRANG_CHECK(str, DRANG_EINVAL);
|
||||
DRANG_CHECK(out_uuid, DRANG_EINVAL);
|
||||
|
||||
// Work with a copy to handle different formats
|
||||
char normalized[37] = {0}; // 36 chars + null terminator
|
||||
const char *src = str;
|
||||
char *dst = normalized;
|
||||
int hex_count = 0;
|
||||
|
||||
// Skip leading brace if present
|
||||
if (*src == '{') {
|
||||
src++;
|
||||
}
|
||||
|
||||
// Copy only hex digits and hyphens, convert to lowercase
|
||||
while (*src && dst < normalized + 36) {
|
||||
if (isxdigit(*src)) {
|
||||
*dst++ = (char)tolower(*src);
|
||||
hex_count++;
|
||||
} else if (*src == '-') {
|
||||
*dst++ = '-';
|
||||
} else if (*src == '}' && *(src + 1) == '\0') {
|
||||
// Allow trailing brace
|
||||
break;
|
||||
} else if (!isspace(*src)) {
|
||||
// Invalid character (ignoring whitespace)
|
||||
DRANG_FAIL(DRANG_EINVAL);
|
||||
}
|
||||
src++;
|
||||
}
|
||||
|
||||
// Must have exactly 32 hex digits
|
||||
DRANG_CHECK(hex_count == 32, DRANG_EINVAL);
|
||||
|
||||
// Determine format and validate
|
||||
const int len = (int)(dst - normalized);
|
||||
int has_hyphens = 0;
|
||||
|
||||
if (len == 36) {
|
||||
// Standard format with hyphens: 8-4-4-4-12
|
||||
if (normalized[8] != '-' || normalized[13] != '-' ||
|
||||
normalized[18] != '-' || normalized[23] != '-') {
|
||||
DRANG_FAIL(DRANG_EINVAL);
|
||||
}
|
||||
has_hyphens = 1;
|
||||
} else if (len == 32) {
|
||||
// No hyphens format
|
||||
has_hyphens = 0;
|
||||
} else {
|
||||
DRANG_FAIL(DRANG_EINVAL);
|
||||
}
|
||||
|
||||
// Parse the hex digits into bytes
|
||||
uint8_t bytes[16];
|
||||
const char *hex_positions[16];
|
||||
|
||||
if (has_hyphens) {
|
||||
// Standard format positions
|
||||
hex_positions[0] = &normalized[0]; // 8 chars: time_low
|
||||
hex_positions[1] = &normalized[2];
|
||||
hex_positions[2] = &normalized[4];
|
||||
hex_positions[3] = &normalized[6];
|
||||
hex_positions[4] = &normalized[9]; // 4 chars: time_mid
|
||||
hex_positions[5] = &normalized[11];
|
||||
hex_positions[6] = &normalized[14]; // 4 chars: time_hi_and_version
|
||||
hex_positions[7] = &normalized[16];
|
||||
hex_positions[8] = &normalized[19]; // 4 chars: clock_seq_and_reserved + clock_seq_low
|
||||
hex_positions[9] = &normalized[21];
|
||||
hex_positions[10] = &normalized[24]; // 12 chars: node
|
||||
hex_positions[11] = &normalized[26];
|
||||
hex_positions[12] = &normalized[28];
|
||||
hex_positions[13] = &normalized[30];
|
||||
hex_positions[14] = &normalized[32];
|
||||
hex_positions[15] = &normalized[34];
|
||||
} else {
|
||||
// No hyphens format
|
||||
for (int i = 0; i < 16; i++) {
|
||||
hex_positions[i] = &normalized[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
// Convert hex pairs to bytes
|
||||
for (int i = 0; i < 16; i++) {
|
||||
DRANG_CHECK(parse_hex_byte(hex_positions[i], &bytes[i]) == 0, DRANG_EINVAL);
|
||||
}
|
||||
|
||||
// Convert bytes to uint64_t values
|
||||
out_uuid->high = ((uint64_t)bytes[0] << 56) | ((uint64_t)bytes[1] << 48) |
|
||||
((uint64_t)bytes[2] << 40) | ((uint64_t)bytes[3] << 32) |
|
||||
((uint64_t)bytes[4] << 24) | ((uint64_t)bytes[5] << 16) |
|
||||
((uint64_t)bytes[6] << 8) | ((uint64_t)bytes[7]);
|
||||
|
||||
out_uuid->low = ((uint64_t)bytes[8] << 56) | ((uint64_t)bytes[9] << 48) |
|
||||
((uint64_t)bytes[10] << 40) | ((uint64_t)bytes[11] << 32) |
|
||||
((uint64_t)bytes[12] << 24) | ((uint64_t)bytes[13] << 16) |
|
||||
((uint64_t)bytes[14] << 8) | ((uint64_t)bytes[15]);
|
||||
|
||||
DRANG_END_TRY_IGNORE()
|
||||
}
|
||||
23
Source/DrangPlatform/Source/win32/uuid.c
Normal file
23
Source/DrangPlatform/Source/win32/uuid.c
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include "common.h"
|
||||
#include "drang/error.h"
|
||||
#include <drang/uuid.h>
|
||||
#include <rpc.h>
|
||||
#pragma comment(lib, "rpcrt4.lib")
|
||||
|
||||
int drang_uuid_generate(drang_uuid_t *out_uuid)
|
||||
{
|
||||
UUID win_uuid = {0};
|
||||
const RPC_STATUS status = UuidCreate(&win_uuid);
|
||||
if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
|
||||
return DRANG_EPLATFORM;
|
||||
}
|
||||
// Convert Windows UUID to our format
|
||||
// Windows UUID is stored in mixed-endian format
|
||||
out_uuid->high = ((uint64_t)win_uuid.Data1 << 32) | ((uint64_t)win_uuid.Data2 << 16) | win_uuid.Data3;
|
||||
out_uuid->low = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
out_uuid->low = (out_uuid->low << 8) | win_uuid.Data4[i];
|
||||
}
|
||||
|
||||
return DRANG_EOK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue