| 1 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 2 | enum State { |
| 3 | /// The state after seeing a `\`. |
| 4 | Escape, |
| 5 | /// The state after seeing a `\x`. |
| 6 | HexFirst, |
| 7 | /// The state after seeing a `\x[0-9A-Fa-f]`. |
| 8 | HexSecond(char), |
| 9 | /// Default state. |
| 10 | Literal, |
| 11 | } |
| 12 | |
| 13 | pub fn unescape(s: &str) -> Vec<u8> { |
| 14 | use self::State::*; |
| 15 | |
| 16 | let mut bytes = vec![]; |
| 17 | let mut state = Literal; |
| 18 | for c in s.chars() { |
| 19 | match state { |
| 20 | Escape => match c { |
| 21 | ' \\' => { |
| 22 | bytes.push(b' \\' ); |
| 23 | state = Literal; |
| 24 | } |
| 25 | 'n' => { |
| 26 | bytes.push(b' \n' ); |
| 27 | state = Literal; |
| 28 | } |
| 29 | 'r' => { |
| 30 | bytes.push(b' \r' ); |
| 31 | state = Literal; |
| 32 | } |
| 33 | 't' => { |
| 34 | bytes.push(b' \t' ); |
| 35 | state = Literal; |
| 36 | } |
| 37 | 'x' => { |
| 38 | state = HexFirst; |
| 39 | } |
| 40 | c => { |
| 41 | bytes.extend(format!(r"\{}" , c).into_bytes()); |
| 42 | state = Literal; |
| 43 | } |
| 44 | }, |
| 45 | HexFirst => match c { |
| 46 | '0' ..='9' | 'A' ..='F' | 'a' ..='f' => { |
| 47 | state = HexSecond(c); |
| 48 | } |
| 49 | c => { |
| 50 | bytes.extend(format!(r"\x{}" , c).into_bytes()); |
| 51 | state = Literal; |
| 52 | } |
| 53 | }, |
| 54 | HexSecond(first) => match c { |
| 55 | '0' ..='9' | 'A' ..='F' | 'a' ..='f' => { |
| 56 | let ordinal = format!("{}{}" , first, c); |
| 57 | let byte = u8::from_str_radix(&ordinal, 16).unwrap(); |
| 58 | bytes.push(byte); |
| 59 | state = Literal; |
| 60 | } |
| 61 | c => { |
| 62 | let original = format!(r"\x{}{}" , first, c); |
| 63 | bytes.extend(original.into_bytes()); |
| 64 | state = Literal; |
| 65 | } |
| 66 | }, |
| 67 | Literal => match c { |
| 68 | ' \\' => { |
| 69 | state = Escape; |
| 70 | } |
| 71 | c => { |
| 72 | bytes.extend(c.to_string().as_bytes()); |
| 73 | } |
| 74 | }, |
| 75 | } |
| 76 | } |
| 77 | match state { |
| 78 | Escape => bytes.push(b' \\' ), |
| 79 | HexFirst => bytes.extend(b" \\x" ), |
| 80 | HexSecond(c) => bytes.extend(format!(" \\x{}" , c).into_bytes()), |
| 81 | Literal => {} |
| 82 | } |
| 83 | bytes |
| 84 | } |
| 85 | |