aboutsummaryrefslogtreecommitdiff
path: root/core/encoding/hex/hex.odin
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2023-05-12 19:26:29 +0200
committerLaytan Laats <laytanlaats@hotmail.com>2023-05-14 03:23:24 +0200
commita38184603411e3ce5a22040196b8b3e482c0987e (patch)
tree7cc3e1babe3d0304bf257b70dd46bd40cafb2bf0 /core/encoding/hex/hex.odin
parent8693a045bbba40c5614ff5912137540c91e61cb0 (diff)
add encoding/hex and use it to expand the percent decoding chars
Diffstat (limited to 'core/encoding/hex/hex.odin')
-rw-r--r--core/encoding/hex/hex.odin74
1 files changed, 74 insertions, 0 deletions
diff --git a/core/encoding/hex/hex.odin b/core/encoding/hex/hex.odin
new file mode 100644
index 000000000..f66febbff
--- /dev/null
+++ b/core/encoding/hex/hex.odin
@@ -0,0 +1,74 @@
+package hex
+
+import "core:strings"
+
+encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds_check {
+ dst := make([]byte, len(src) * 2, allocator)
+ for i := 0; i < len(src); i += 1 {
+ v := src[i]
+ dst[i] = HEXTABLE[v>>4]
+ dst[i+1] = HEXTABLE[v&0x0f]
+ i += 2
+ }
+
+ return dst
+}
+
+
+decode :: proc(src: []byte, allocator := context.allocator) -> (dst: []byte, ok: bool) #no_bounds_check {
+ if len(src) % 2 == 1 {
+ return
+ }
+
+ dst = make([]byte, len(src) / 2, allocator)
+ for i, j := 0, 1; j < len(src); j += 2 {
+ p := src[j-1]
+ q := src[j]
+
+ a := hex_digit(p) or_return
+ b := hex_digit(q) or_return
+
+ dst[i] = (a << 4) | b
+ i += 1
+ }
+
+ return dst, true
+}
+
+// Decodes the given sequence into one byte.
+// Should be called with one rune worth of the source, eg: 0x23 -> '#'.
+decode_sequence :: proc(str: string) -> (byte, bool) {
+ no_prefix_str := strings.trim_prefix(str, "0x")
+ val: byte
+ for i := 0; i < len(no_prefix_str); i += 1 {
+ index := (len(no_prefix_str) - 1) - i // reverse the loop.
+
+ hd, ok := hex_digit(no_prefix_str[i])
+ if !ok {
+ return 0, false
+ }
+
+ val += u8(hd) << uint(4 * index)
+ }
+
+ return val, true
+}
+
+@(private)
+HEXTABLE := [16]byte {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f',
+}
+
+@(private)
+hex_digit :: proc(char: byte) -> (u8, bool) {
+ switch char {
+ case '0' ..= '9': return char - '0', true
+ case 'a' ..= 'f': return char - 'a' + 10, true
+ case 'A' ..= 'F': return char - 'A' + 10, true
+ case: return 0, false
+ }
+}
+