///|
fn nibble_char(value : Int) -> Char {
if value < 10 {
(48 + value).unsafe_to_char()
} else {
(87 + value).unsafe_to_char()
}
}
///|
fn hex_nibble(c : Int) -> Int? {
if c >= 48 && c <= 57 {
Some(c - 48)
} else if c >= 65 && c <= 70 {
Some(c - 55)
} else if c >= 97 && c <= 102 {
Some(c - 87)
} else {
None
}
}
///|
/// Encode bytes as lowercase hexadecimal.
pub fn hex_encode(data : Bytes) -> String {
let out = StringBuilder()
for byte in data {
let value = byte.to_int()
out.write_char(nibble_char((value >> 4) & 15))
out.write_char(nibble_char(value & 15))
}
out.to_string()
}
///|
fn hex_byte(value : Int) -> String {
let out = StringBuilder()
out.write_char(nibble_char((value >> 4) & 15))
out.write_char(nibble_char(value & 15))
out.to_string()
}
///|
/// Decode a hex string into bytes. Odd length is rejected.
pub fn hex_decode(text : String) -> Result[Bytes, EvtxError] {
if text.length() % 2 != 0 {
return Err(InvalidName("odd hex length"))
}
let out : Array[Byte] = []
let mut i = 0
while i < text.length() {
match (hex_nibble(text[i].to_int()), hex_nibble(text[i + 1].to_int())) {
(Some(hi), Some(lo)) => out.push(((hi << 4) | lo).to_byte())
_ => return Err(InvalidName("invalid hex digit"))
}
i = i + 2
}
Ok(Bytes::from_array(out))
}
///|
fn hex_int32_string(data : Bytes, pos : Int) -> Result[String, EvtxError] {
let _ = match need(data, pos, 4, "hex32") {
Ok(v) => v
Err(e) => return Err(e)
}
let out = StringBuilder()
out.write_string("0x")
for i = 3; i >= 0; i = i - 1 {
out.write_string(hex_byte(data[pos + i].to_int()))
}
Ok(out.to_string())
}
///|
fn hex_int64_string(data : Bytes, pos : Int) -> Result[String, EvtxError] {
let _ = match need(data, pos, 8, "hex64") {
Ok(v) => v
Err(e) => return Err(e)
}
let out = StringBuilder()
out.write_string("0x")
for i = 7; i >= 0; i = i - 1 {
out.write_string(hex_byte(data[pos + i].to_int()))
}
Ok(out.to_string())
}