You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.4 KiB
85 lines
2.4 KiB
#[derive(Clone, Copy, Eq, PartialEq)]
|
|
enum State {
|
|
/// The state after seeing a `\`.
|
|
Escape,
|
|
/// The state after seeing a `\x`.
|
|
HexFirst,
|
|
/// The state after seeing a `\x[0-9A-Fa-f]`.
|
|
HexSecond(char),
|
|
/// Default state.
|
|
Literal,
|
|
}
|
|
|
|
pub fn unescape(s: &str) -> Vec<u8> {
|
|
use self::State::*;
|
|
|
|
let mut bytes = vec![];
|
|
let mut state = Literal;
|
|
for c in s.chars() {
|
|
match state {
|
|
Escape => match c {
|
|
'\\' => {
|
|
bytes.push(b'\\');
|
|
state = Literal;
|
|
}
|
|
'n' => {
|
|
bytes.push(b'\n');
|
|
state = Literal;
|
|
}
|
|
'r' => {
|
|
bytes.push(b'\r');
|
|
state = Literal;
|
|
}
|
|
't' => {
|
|
bytes.push(b'\t');
|
|
state = Literal;
|
|
}
|
|
'x' => {
|
|
state = HexFirst;
|
|
}
|
|
c => {
|
|
bytes.extend(format!(r"\{}", c).into_bytes());
|
|
state = Literal;
|
|
}
|
|
},
|
|
HexFirst => match c {
|
|
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
|
state = HexSecond(c);
|
|
}
|
|
c => {
|
|
bytes.extend(format!(r"\x{}", c).into_bytes());
|
|
state = Literal;
|
|
}
|
|
},
|
|
HexSecond(first) => match c {
|
|
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
|
let ordinal = format!("{}{}", first, c);
|
|
let byte = u8::from_str_radix(&ordinal, 16).unwrap();
|
|
bytes.push(byte);
|
|
state = Literal;
|
|
}
|
|
c => {
|
|
let original = format!(r"\x{}{}", first, c);
|
|
bytes.extend(original.into_bytes());
|
|
state = Literal;
|
|
}
|
|
},
|
|
Literal => match c {
|
|
'\\' => {
|
|
state = Escape;
|
|
}
|
|
c => {
|
|
bytes.extend(c.to_string().as_bytes());
|
|
}
|
|
},
|
|
}
|
|
}
|
|
match state {
|
|
Escape => bytes.push(b'\\'),
|
|
HexFirst => bytes.extend(b"\\x"),
|
|
HexSecond(c) => bytes.extend(format!("\\x{}", c).into_bytes()),
|
|
Literal => {}
|
|
}
|
|
bytes
|
|
}
|