63 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			63 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			V
		
	
	
| module hex
 | |
| 
 | |
| import strings
 | |
| 
 | |
| // decode converts a hex string into an array of bytes. The expected
 | |
| // input format is 2 ASCII characters for each output byte. If the provided
 | |
| // string length is not a multiple of 2, an implicit `0` is prepended to it.
 | |
| pub fn decode(s string) ?[]byte {
 | |
| 	mut hex_str := s
 | |
| 	if hex_str.len >= 2 {
 | |
| 		if s[0] == `0` && (s[1] == `x` || s[1] == `X`) {
 | |
| 			hex_str = s[2..]
 | |
| 		}
 | |
| 	}
 | |
| 	if hex_str.len == 0 {
 | |
| 		return []byte{}
 | |
| 	} else if hex_str.len == 1 {
 | |
| 		return [char2nibble(hex_str[0]) ?]
 | |
| 	} else if hex_str.len == 2 {
 | |
| 		n1 := char2nibble(hex_str[0]) ?
 | |
| 		n0 := char2nibble(hex_str[1]) ?
 | |
| 		return [(n1 << 4) | n0]
 | |
| 	}
 | |
| 	// calculate the first byte depending on if hex_str.len is odd
 | |
| 	mut val := char2nibble(hex_str[0]) ?
 | |
| 	if hex_str.len & 1 == 0 {
 | |
| 		val = (val << 4) | char2nibble(hex_str[1]) ?
 | |
| 	}
 | |
| 	// set cap to hex_str.len/2 rounded up
 | |
| 	mut bytes := []byte{len: 1, cap: (hex_str.len + 1) >> 1, init: val}
 | |
| 	// iterate over every 2 bytes
 | |
| 	// the start index depends on if hex_str.len is odd
 | |
| 	for i := 2 - (hex_str.len & 1); i < hex_str.len; i += 2 {
 | |
| 		n1 := char2nibble(hex_str[i]) ?
 | |
| 		n0 := char2nibble(hex_str[i + 1]) ?
 | |
| 		bytes << (n1 << 4) | n0
 | |
| 	}
 | |
| 	return bytes
 | |
| }
 | |
| 
 | |
| // encode converts an array of bytes into a string of ASCII hex bytes. The
 | |
| // output will always be a string with length a multiple of 2.
 | |
| [manualfree]
 | |
| pub fn encode(bytes []byte) string {
 | |
| 	mut sb := strings.new_builder(bytes.len << 1)
 | |
| 	for b in bytes {
 | |
| 		sb.write_string(b.hex())
 | |
| 	}
 | |
| 	res := sb.str()
 | |
| 	unsafe { sb.free() }
 | |
| 	return res
 | |
| }
 | |
| 
 | |
| // char2nibble converts an ASCII hex character to it's hex value
 | |
| fn char2nibble(b byte) ?byte {
 | |
| 	match b {
 | |
| 		`0`...`9` { return b - byte(`0`) }
 | |
| 		`A`...`F` { return b - byte(`A`) + 10 }
 | |
| 		`a`...`f` { return b - byte(`a`) + 10 }
 | |
| 		else { return error('invalid hex char $b.ascii_str()') }
 | |
| 	}
 | |
| }
 |