aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-05-08 21:29:52 -0400
committerDavid Robillard <d@drobilla.net>2023-05-08 21:29:52 -0400
commit86894351ffb6cc7f9fd9a4d63ba0a6eecc64d29d (patch)
treecf08668affe83c2a0eb9c9e2eb16689c5b3517f6
parented77fe14175e94138390f2ebf5348656e4421746 (diff)
downloadserd-86894351ffb6cc7f9fd9a4d63ba0a6eecc64d29d.tar.gz
serd-86894351ffb6cc7f9fd9a4d63ba0a6eecc64d29d.tar.bz2
serd-86894351ffb6cc7f9fd9a4d63ba0a6eecc64d29d.zip
Avoid use of strtoul()
This function is overkill for the simple cases actually needed here, and pretty slow anyway.
-rw-r--r--src/n3.c14
-rw-r--r--src/string_utils.h6
-rw-r--r--src/uri.c5
3 files changed, 16 insertions, 9 deletions
diff --git a/src/n3.c b/src/n3.c
index d332504d..d5866393 100644
--- a/src/n3.c
+++ b/src/n3.c
@@ -15,7 +15,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
#if defined(__clang__) && __clang_major__ >= 10
@@ -71,17 +70,18 @@ read_UCHAR(SerdReader* const reader, const Ref dest, uint32_t* const char_code)
skip_byte(reader, b);
- uint8_t buf[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
- for (unsigned i = 0; i < length; ++i) {
+ // Read character code point in hex
+ uint8_t buf[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t code = 0U;
+ for (unsigned i = 0U; i < length; ++i) {
if (!(buf[i] = read_HEX(reader))) {
return SERD_ERR_BAD_SYNTAX;
}
- }
- char* endptr = NULL;
- const uint32_t code = (uint32_t)strtoul((const char*)buf, &endptr, 16);
- assert(endptr == (char*)buf + length);
+ code = (code << (i ? 4U : 0U)) | hex_digit_value(buf[i]);
+ }
+ // Determine the encoded size from the code point
unsigned size = 0;
if (code < 0x00000080) {
size = 1;
diff --git a/src/string_utils.h b/src/string_utils.h
index 9ae0abcb..7770e1eb 100644
--- a/src/string_utils.h
+++ b/src/string_utils.h
@@ -89,6 +89,12 @@ serd_substrlen(const uint8_t* str,
size_t* n_bytes,
SerdNodeFlags* flags);
+static inline uint8_t
+hex_digit_value(const uint8_t c)
+{
+ return (uint8_t)((c > '9') ? ((c & ~0x20) - 'A' + 10) : (c - '0'));
+}
+
static inline char
serd_to_upper(const char c)
{
diff --git a/src/uri.c b/src/uri.c
index d78b8e8c..b45f7e16 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -72,8 +72,9 @@ serd_file_uri_parse(const uint8_t* const uri, uint8_t** const hostname)
serd_chunk_sink("%", 1, &chunk);
++s;
} else if (is_hexdig(*(s + 1)) && is_hexdig(*(s + 2))) {
- const uint8_t code[3] = {*(s + 1), *(s + 2), 0};
- const uint8_t c = (uint8_t)strtoul((const char*)code, NULL, 16);
+ const uint8_t hi = hex_digit_value(s[1]);
+ const uint8_t lo = hex_digit_value(s[2]);
+ const char c = (char)((hi << 4U) | lo);
serd_chunk_sink(&c, 1, &chunk);
s += 2;
} else {