1pub mod consts;
2pub mod v1;
3pub use v1::*;
4pub mod emu_buxn;
5pub mod emu_cuxn;
6pub mod emu_uxn;
7
8pub fn percent_decode_or_original(s: &str) -> String {
16 if !s.as_bytes().contains(&b'%') {
18 return s.to_string();
19 }
20
21 let mut out = Vec::with_capacity(s.len());
23 let bytes = s.as_bytes();
24 let mut i = 0;
25 while i < bytes.len() {
26 if bytes[i] == b'%' && i + 2 < bytes.len() {
27 if let (Some(h), Some(l)) = (hex_val(bytes[i + 1]), hex_val(bytes[i + 2])) {
28 out.push((h << 4) | l);
29 i += 3;
30 continue;
31 }
32 out.push(b'%');
34 i += 1;
35 } else {
36 out.push(bytes[i]);
37 i += 1;
38 }
39 }
40
41 match std::str::from_utf8(&out) {
43 Ok(decoded) => decoded.to_string(),
44 Err(_) => s.to_string(),
45 }
46}
47
48fn hex_val(b: u8) -> Option<u8> {
49 match b {
50 b'0'..=b'9' => Some(b - b'0'),
51 b'a'..=b'f' => Some(b - b'a' + 10),
52 b'A'..=b'F' => Some(b - b'A' + 10),
53 _ => None,
54 }
55}