encoding.hex: remove strconv dependency (#11196)
parent
022503a107
commit
60f21f065f
|
@ -1,25 +1,39 @@
|
||||||
module hex
|
module hex
|
||||||
|
|
||||||
import strconv
|
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
// decode converts a hex string into an array of bytes. The expected
|
// 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
|
// 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.
|
// string length is not a multiple of 2, an implicit `0` is prepended to it.
|
||||||
pub fn decode(s string) ?[]byte {
|
pub fn decode(s string) ?[]byte {
|
||||||
if s.len == 0 {
|
mut hex_str := s
|
||||||
return []byte{}
|
if hex_str.len >= 2 {
|
||||||
} else if s.len <= 2 {
|
if s[0] == `0` && (s[1] == `x` || s[1] == `X`) {
|
||||||
return [byte(strconv.parse_uint(s, 16, 8) ?)]
|
hex_str = s[2..]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// calculate the first byte depending on if s.len is odd
|
if hex_str.len == 0 {
|
||||||
val := byte(strconv.parse_uint(s[..2 - (s.len & 1)], 16, 8) ?)
|
return []byte{}
|
||||||
// set cap to s.len/2 rounded up
|
} else if hex_str.len == 1 {
|
||||||
mut bytes := []byte{len: 1, cap: (s.len + 1) >> 1, init: val}
|
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
|
// iterate over every 2 bytes
|
||||||
// the start index depends on if s.len is odd
|
// the start index depends on if hex_str.len is odd
|
||||||
for i := 2 - (s.len & 1); i < s.len; i += 2 {
|
for i := 2 - (hex_str.len & 1); i < hex_str.len; i += 2 {
|
||||||
bytes << byte(strconv.parse_uint(s[i..i + 2], 16, 8) ?)
|
n1 := char2nibble(hex_str[i]) ?
|
||||||
|
n0 := char2nibble(hex_str[i + 1]) ?
|
||||||
|
bytes << (n1 << 4) | n0
|
||||||
}
|
}
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
@ -36,3 +50,13 @@ pub fn encode(bytes []byte) string {
|
||||||
unsafe { sb.free() }
|
unsafe { sb.free() }
|
||||||
return res
|
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()') }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ fn test_decode() ? {
|
||||||
assert decode('123') ? == [byte(0x1), 0x23]
|
assert decode('123') ? == [byte(0x1), 0x23]
|
||||||
assert decode('1234') ? == [byte(0x12), 0x34]
|
assert decode('1234') ? == [byte(0x12), 0x34]
|
||||||
assert decode('12345') ? == [byte(0x1), 0x23, 0x45]
|
assert decode('12345') ? == [byte(0x1), 0x23, 0x45]
|
||||||
|
assert decode('0123456789abcdef') ? == [byte(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
|
||||||
|
assert decode('123456789ABCDEF') ? == [byte(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_decode_fails() ? {
|
fn test_decode_fails() ? {
|
||||||
|
@ -38,4 +40,15 @@ fn test_encode() ? {
|
||||||
assert encode(decode('123') ?) == '0123'
|
assert encode(decode('123') ?) == '0123'
|
||||||
assert encode(decode('1234') ?) == '1234'
|
assert encode(decode('1234') ?) == '1234'
|
||||||
assert encode(decode('12345') ?) == '012345'
|
assert encode(decode('12345') ?) == '012345'
|
||||||
|
assert encode(decode('abcdef') ?) == 'abcdef'
|
||||||
|
assert encode(decode('ABCDEF') ?) == 'abcdef'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_decode_0x() ? {
|
||||||
|
assert decode('0x') ? == []
|
||||||
|
assert decode('0x0') ? == [byte(0x0)]
|
||||||
|
assert decode('0X1234') ? == [byte(0x12), 0x34]
|
||||||
|
assert decode('0x12345') ? == [byte(0x1), 0x23, 0x45]
|
||||||
|
assert decode('0x0123456789abcdef') ? == [byte(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
|
||||||
|
assert decode('0X123456789ABCDEF') ? == [byte(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue