///|
/// Lowercase hex encoding of a byte view.
pub fn to_hex_lower(data : BytesView) -> String {
let sb = StringBuilder()
for b in data {
let v = b.to_int()
sb.write_char(lower_hex_digit((v >> 4) & 0xF))
sb.write_char(lower_hex_digit(v & 0xF))
}
sb.to_string()
}
///|
/// Uppercase hex encoding of a byte view.
pub fn to_hex_upper(data : BytesView) -> String {
let sb = StringBuilder()
for b in data {
let v = b.to_int()
sb.write_char(upper_hex_digit((v >> 4) & 0xF))
sb.write_char(upper_hex_digit(v & 0xF))
}
sb.to_string()
}
///|
fn lower_hex_digit(nibble : Int) -> Char {
if nibble < 10 {
('0'.to_int() + nibble).unsafe_to_char()
} else {
('a'.to_int() + nibble - 10).unsafe_to_char()
}
}
///|
fn upper_hex_digit(nibble : Int) -> Char {
if nibble < 10 {
('0'.to_int() + nibble).unsafe_to_char()
} else {
('A'.to_int() + nibble - 10).unsafe_to_char()
}
}
///|
/// Decode an even-length hexadecimal string into bytes.
pub fn from_hex(s : String) -> Result[Bytes, String] {
let bs = @utf8.encode(s)
let n = bs.length()
if n % 2 != 0 {
return Err("hex string has odd length")
}
let out : Array[Byte] = []
let mut i = 0
while i < n {
let hi = hex_value_int(bs.get(i).unwrap().to_int())
let lo = hex_value_int(bs.get(i + 1).unwrap().to_int())
if hi < 0 || lo < 0 {
return Err("invalid hex digit in: \{s}")
}
out.push(((hi << 4) | lo).to_byte())
i = i + 2
}
Ok(Bytes::from_array(out))
}
///|
fn hex_value_int(c : Int) -> Int {
if c >= '0'.to_int() && c <= '9'.to_int() {
return c - '0'.to_int()
}
if c >= 'a'.to_int() && c <= 'f'.to_int() {
return c - 'a'.to_int() + 10
}
if c >= 'A'.to_int() && c <= 'F'.to_int() {
return c - 'A'.to_int() + 10
}
-1
}