aboutsummaryrefslogtreecommitdiff
path: root/core/encoding/hex/hex.odin
blob: ef0bab1d075c6ad5e06943ef254f7dbf9ef7d12c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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, j := 0, 0; i < len(src); i += 1 {
		v := src[i]
		dst[j]   = HEXTABLE[v>>4]
		dst[j+1] = HEXTABLE[v&0x0f]
		j += 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 byte worth of the source, eg: 0x23 -> '#'.
decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
	str := str
	if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") {
		str = str[2:]
	}

	if len(str) != 2 {
		return 0, false
	}

	upper := hex_digit(str[0]) or_return
	lower := hex_digit(str[1]) or_return

	return upper << 4 | lower, 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
	}
}