135 lines
2.8 KiB
C
135 lines
2.8 KiB
C
|
|
#include "amduat/util/hex.h"
|
||
|
|
|
||
|
|
#include <limits.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
size_t amduat_hex_encoded_len(size_t byte_len) {
|
||
|
|
if (byte_len > (SIZE_MAX / 2u)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return byte_len * 2u;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t amduat_hex_encoded_size(size_t byte_len) {
|
||
|
|
size_t encoded_len = amduat_hex_encoded_len(byte_len);
|
||
|
|
if (encoded_len == 0 && byte_len != 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (encoded_len > (SIZE_MAX - 1u)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return encoded_len + 1u;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool amduat_hex_encode_lower(const uint8_t *bytes,
|
||
|
|
size_t byte_len,
|
||
|
|
char *out,
|
||
|
|
size_t out_len) {
|
||
|
|
static const char kHexLower[] = "0123456789abcdef";
|
||
|
|
size_t encoded_len = amduat_hex_encoded_len(byte_len);
|
||
|
|
size_t encoded_size = amduat_hex_encoded_size(byte_len);
|
||
|
|
|
||
|
|
if (encoded_len == 0 && byte_len != 0) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (encoded_size == 0 || out == NULL || out_len < encoded_size) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (byte_len > 0 && bytes == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (size_t i = 0; i < byte_len; ++i) {
|
||
|
|
uint8_t byte = bytes[i];
|
||
|
|
out[i * 2u] = kHexLower[(byte >> 4u) & 0x0fu];
|
||
|
|
out[i * 2u + 1u] = kHexLower[byte & 0x0fu];
|
||
|
|
}
|
||
|
|
out[encoded_len] = '\0';
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool amduat_hex_nibble(char c, uint8_t *out) {
|
||
|
|
if (c >= '0' && c <= '9') {
|
||
|
|
*out = (uint8_t)(c - '0');
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if (c >= 'a' && c <= 'f') {
|
||
|
|
*out = (uint8_t)(c - 'a' + 10);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if (c >= 'A' && c <= 'F') {
|
||
|
|
*out = (uint8_t)(c - 'A' + 10);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool amduat_hex_decode(const char *hex, uint8_t *out, size_t out_len) {
|
||
|
|
if (hex == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (out_len > 0 && out == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t hex_len = strlen(hex);
|
||
|
|
if ((hex_len & 1u) != 0u) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t expected_len = hex_len / 2u;
|
||
|
|
if (expected_len != out_len) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (size_t i = 0; i < out_len; ++i) {
|
||
|
|
uint8_t hi = 0;
|
||
|
|
uint8_t lo = 0;
|
||
|
|
|
||
|
|
if (!amduat_hex_nibble(hex[i * 2u], &hi) ||
|
||
|
|
!amduat_hex_nibble(hex[i * 2u + 1u], &lo)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
out[i] = (uint8_t)((hi << 4u) | lo);
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool amduat_hex_decode_alloc(const char *hex, uint8_t **out, size_t *out_len) {
|
||
|
|
if (out != NULL) {
|
||
|
|
*out = NULL;
|
||
|
|
}
|
||
|
|
if (out_len != NULL) {
|
||
|
|
*out_len = 0;
|
||
|
|
}
|
||
|
|
if (hex == NULL || out == NULL || out_len == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t hex_len = strlen(hex);
|
||
|
|
if ((hex_len & 1u) != 0u) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t bytes_len = hex_len / 2u;
|
||
|
|
if (bytes_len == 0) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t *buf = (uint8_t *)malloc(bytes_len);
|
||
|
|
if (buf == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduat_hex_decode(hex, buf, bytes_len)) {
|
||
|
|
free(buf);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*out = buf;
|
||
|
|
*out_len = bytes_len;
|
||
|
|
return true;
|
||
|
|
}
|