Jakub Kotur | 3bceaeb | 2020-12-21 17:28:16 +0100 | [diff] [blame] | 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 | } |