commit 86425c7d0d5337c4187b2e7e5de8c813a9e31cbd
parent 2ab02483e5356939d332ee44933787f6bc3e7cc2
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 24 Mar 2021 11:33:39 -0400
encoding::hex: add decode
Diffstat:
1 file changed, 31 insertions(+), 0 deletions(-)
diff --git a/encoding/hex/hex.ha b/encoding/hex/hex.ha
@@ -1,8 +1,12 @@
+use bytes;
use io;
use strconv;
use strings;
use strio;
+// Error returned when attempting to decode an invalid hex string.
+export type invalid = void!;
+
// Encodes a byte slice to hex and writes it to a string. The caller must free
// this string.
export fn encode(b: []u8) str = {
@@ -23,3 +27,30 @@ export fn encode(b: []u8) str = {
defer free(s);
assert(s == "cafebabedeadf00d");
};
+
+// Decodes a string of hexadecimal bytes into a byte slice. The caller must free
+// the return value.
+export fn decode(s: str) ([]u8 | invalid) = {
+ if (len(s) % 2 != 0) {
+ return invalid;
+ };
+ let buf: []u8 = alloc([], len(s) / 2);
+ let s = strings::to_utf8(s);
+ for (let i = 0z; i < len(s) / 2; i += 1) {
+ let oct = strings::from_utf8_unsafe(s[i * 2..i * 2 + 2]);
+ let u = match (strconv::stou8b(oct, 16)) {
+ (strconv::invalid | strconv::overflow) => return invalid,
+ u: u8 => u,
+ };
+ append(buf, u);
+ };
+ return buf;
+};
+
+@test fn decode() void = {
+ let s = decode("cafebabedeadf00d") as []u8;
+ defer free(s);
+ assert(bytes::equal(s, [0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xF0, 0x0D]));
+
+ decode("this is not hex") as invalid;
+};