diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2023-08-24 03:04:58 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2023-08-24 04:19:07 +0200 |
commit | eddc0ffdab239c61cc0e064b6ebd33dfadcef3cd (patch) | |
tree | 831a5b64ed6bbd34d8c3e721665599e7197a4dec | |
parent | e3c0eca95642a846ab65261424a51dd99d954017 (diff) |
Lib: Add functions for reading and writing of bytestrings
Based on patch from Alexander Zubkov, thanks!
-rw-r--r-- | conf/cf-lex.l | 46 | ||||
-rw-r--r-- | lib/string.h | 3 | ||||
-rw-r--r-- | lib/strtoul.c | 104 |
3 files changed, 101 insertions, 52 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 9025a84d..965e1e3f 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -256,38 +256,22 @@ WHITE [ \t] } ({XIGIT}{2}){16,}|{XIGIT}{2}(:{XIGIT}{2}){15,}|hex:({XIGIT}{2}(:?{XIGIT}{2})*)? { - char *s, *sb = yytext; - size_t len = 0, i; - struct bytestring *bytes; - byte *b; - - /* skip 'hex:' prefix */ - if (sb[0] == 'h' && sb[1] == 'e' && sb[2] == 'x' && sb[3] == ':') - sb += 4; - - s = sb; - while (*s) { - len++; - s += 2; - if (*s == ':') - s++; - } - bytes = cfg_allocz(sizeof(*bytes) + len); + char *s = yytext; + struct bytestring *bs; - bytes->length = len; - b = &bytes->data[0]; - s = sb; - errno = 0; - for (i = 0; i < len; i++) { - *b = bstrtobyte16(s); - if (errno == ERANGE) - cf_error("Invalid hex string"); - b++; - s += 2; - if (*s == ':') - s++; - } - cf_lval.bs = bytes; + /* Skip 'hex:' prefix */ + if (s[0] == 'h' && s[1] == 'e' && s[2] == 'x' && s[3] == ':') + s += 4; + + int len = bstrhextobin(s, NULL); + if (len < 0) + cf_error("Invalid hex string"); + + bs = cfg_allocz(sizeof(struct bytestring) + len); + bs->length = bstrhextobin(s, bs->data); + ASSERT(bs->length == len); + + cf_lval.bs = bs; return BYTESTRING; } diff --git a/lib/string.h b/lib/string.h index 2829943d..161b7651 100644 --- a/lib/string.h +++ b/lib/string.h @@ -33,6 +33,9 @@ u64 bstrtoul10(const char *str, char **end); u64 bstrtoul16(const char *str, char **end); byte bstrtobyte16(const char *str); +int bstrhextobin(const char *s, byte *b); +int bstrbintohex(const byte *b, size_t len, char *buf, size_t size, char delim); + int patmatch(const byte *pat, const byte *str); static inline char *xbasename(const char *str) diff --git a/lib/strtoul.c b/lib/strtoul.c index a5b11f68..e0c0142f 100644 --- a/lib/strtoul.c +++ b/lib/strtoul.c @@ -25,7 +25,7 @@ bstrtoul10(const char *str, char **end) errno = ERANGE; return UINT64_MAX; } - + out *= 10; out += (**end) - '0'; } @@ -60,29 +60,91 @@ bstrtoul16(const char *str, char **end) return UINT64_MAX; } -byte -bstrtobyte16(const char *str) +static int +fromxdigit(char c) { - byte out = 0; - for (int i=0; i<2; i++) { - switch (str[i]) { - case '0' ... '9': - out *= 16; - out += str[i] - '0'; - break; - case 'a' ... 'f': - out *= 16; - out += str[i] + 10 - 'a'; - break; - case 'A' ... 'F': - out *= 16; - out += str[i] + 10 - 'A'; - break; - default: - errno = ERANGE; + switch (c) + { + case '0' ... '9': + return c - '0'; + case 'a' ... 'f': + return c + 10 - 'a'; + case 'A' ... 'F': + return c + 10 - 'A'; + default: + return -1; + } +} + +int +bstrhextobin(const char *s, byte *b) +{ + int len = 0; + int hi = 0; + + for (; *s; s++) + { + int v = fromxdigit(*s); + if (v < 0) + { + if (strchr(" :-", *s) && !hi) + continue; + else return -1; } + + if (len == INT32_MAX) + return -1; + + if (b) + { + if (!hi) + b[len] = (v << 4); + else + b[len] |= v; + } + + len += hi; + hi = !hi; } - return out; + return !hi ? len : -1; +} + +static char +toxdigit(uint b) +{ + if (b < 10) + return ('0' + b); + else if (b < 16) + return ('a' + b - 10); + else + return 0; +} + +int +bstrbintohex(const byte *b, size_t len, char *buf, size_t size, char delim) +{ + ASSERT(size >= 6); + char *bound = buf + size - 3; + + size_t i; + for (i = 0; i < len; i++) + { + if (buf > bound) + { + strcpy(buf - 4, "..."); + return -1; + } + + uint x = b[i]; + buf[0] = toxdigit(x >> 4); + buf[1] = toxdigit(x & 0xF); + buf[2] = delim; + buf += 3; + } + + buf[i ? -1 : 0] = 0; + + return 0; } |