Hex codec, for convenience
This commit is contained in:
parent
790782fc87
commit
7e3bf2ade5
|
@ -0,0 +1,126 @@
|
||||||
|
pub enum HexParser {
|
||||||
|
Liberal,
|
||||||
|
WhitespaceAllowed,
|
||||||
|
Strict,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum HexFormatter {
|
||||||
|
Lines(usize),
|
||||||
|
Packed,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hexdigit(v: u8) -> char {
|
||||||
|
(if v < 10 {('0' as u8) + v} else {('a' as u8) + v - 10}) as char
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unhex(c: char) -> Option<u8> {
|
||||||
|
if c >= '0' && c <= '9' {
|
||||||
|
return Some((c as u8) - ('0' as u8));
|
||||||
|
}
|
||||||
|
if c >= 'a' && c <= 'f' {
|
||||||
|
return Some((c as u8) - ('a' as u8) + 10);
|
||||||
|
}
|
||||||
|
if c >= 'A' && c <= 'F' {
|
||||||
|
return Some((c as u8) - ('A' as u8) + 10);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HexParser {
|
||||||
|
pub fn decode(&self, s: &str) -> Option<Vec<u8>> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
let mut buf: u8 = 0;
|
||||||
|
let mut buf_full = false;
|
||||||
|
for c in s.chars() {
|
||||||
|
match unhex(c) {
|
||||||
|
None =>
|
||||||
|
match self {
|
||||||
|
HexParser::Liberal => (),
|
||||||
|
HexParser::WhitespaceAllowed => if !c.is_whitespace() { return None },
|
||||||
|
HexParser::Strict => return None,
|
||||||
|
},
|
||||||
|
Some(nibble) =>
|
||||||
|
if buf_full {
|
||||||
|
result.push(buf << 4 | nibble);
|
||||||
|
buf_full = false;
|
||||||
|
} else {
|
||||||
|
buf = nibble;
|
||||||
|
buf_full = true;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HexFormatter {
|
||||||
|
pub fn encode(&self, bs: &[u8]) -> String {
|
||||||
|
match self {
|
||||||
|
HexFormatter::Lines(max_line_length) => {
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
let mut line = String::new();
|
||||||
|
for b in bs {
|
||||||
|
if line.len() + 2 > *max_line_length {
|
||||||
|
lines.push(std::mem::take(&mut line));
|
||||||
|
}
|
||||||
|
line.push(hexdigit(b >> 4));
|
||||||
|
line.push(hexdigit(b & 15));
|
||||||
|
}
|
||||||
|
lines.push(std::mem::take(&mut line));
|
||||||
|
lines.join("\n")
|
||||||
|
}
|
||||||
|
HexFormatter::Packed => {
|
||||||
|
let mut result = String::new();
|
||||||
|
for b in bs {
|
||||||
|
result.push(hexdigit(b >> 4));
|
||||||
|
result.push(hexdigit(b & 15));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test] fn test_decode_packed() {
|
||||||
|
let s = "01ab00ff";
|
||||||
|
assert_eq!(HexParser::Strict.decode(s), Some(vec![1, 171, 0, 255]));
|
||||||
|
assert_eq!(HexParser::WhitespaceAllowed.decode(s), Some(vec![1, 171, 0, 255]));
|
||||||
|
assert_eq!(HexParser::Liberal.decode(s), Some(vec![1, 171, 0, 255]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] fn test_decode_whitespace() {
|
||||||
|
let s = "01ab 00ff";
|
||||||
|
assert_eq!(HexParser::Strict.decode(s), None);
|
||||||
|
assert_eq!(HexParser::WhitespaceAllowed.decode(s), Some(vec![1, 171, 0, 255]));
|
||||||
|
assert_eq!(HexParser::Liberal.decode(s), Some(vec![1, 171, 0, 255]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] fn test_decode_liberal() {
|
||||||
|
let s = "01ab zz 00ff";
|
||||||
|
assert_eq!(HexParser::Strict.decode(s), None);
|
||||||
|
assert_eq!(HexParser::WhitespaceAllowed.decode(s), None);
|
||||||
|
assert_eq!(HexParser::Liberal.decode(s), Some(vec![1, 171, 0, 255]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] fn test_encode_lines() {
|
||||||
|
assert_eq!(HexFormatter::Lines(10).encode(&vec![0x5a; 11]), "5a5a5a5a5a\n5a5a5a5a5a\n5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(10).encode(&vec![0x5a; 10]), "5a5a5a5a5a\n5a5a5a5a5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(10).encode(&vec![0x5a; 9]), "5a5a5a5a5a\n5a5a5a5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(9).encode(&vec![0x5a; 11]), "5a5a5a5a\n5a5a5a5a\n5a5a5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(9).encode(&vec![0x5a; 10]), "5a5a5a5a\n5a5a5a5a\n5a5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(9).encode(&vec![0x5a; 9]), "5a5a5a5a\n5a5a5a5a\n5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(8).encode(&vec![0x5a; 11]), "5a5a5a5a\n5a5a5a5a\n5a5a5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(8).encode(&vec![0x5a; 10]), "5a5a5a5a\n5a5a5a5a\n5a5a");
|
||||||
|
assert_eq!(HexFormatter::Lines(8).encode(&vec![0x5a; 9]), "5a5a5a5a\n5a5a5a5a\n5a");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] fn test_encode_packed() {
|
||||||
|
assert_eq!(HexFormatter::Packed.encode(&vec![0x5a; 11]), "5a5a5a5a5a5a5a5a5a5a5a");
|
||||||
|
assert_eq!(HexFormatter::Packed.encode(&vec![0x5a; 10]), "5a5a5a5a5a5a5a5a5a5a");
|
||||||
|
assert_eq!(HexFormatter::Packed.encode(&vec![0x5a; 9]), "5a5a5a5a5a5a5a5a5a");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod de;
|
pub mod de;
|
||||||
pub mod ser;
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod hex;
|
||||||
|
pub mod ser;
|
||||||
pub mod set;
|
pub mod set;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
Loading…
Reference in New Issue