oi4_dnp_encoding/
decode.rs1#[cfg(feature = "strict")]
2use crate::encode::is_unreserved;
3#[cfg(feature = "alloc")]
4use crate::error::{Error, ErrorKind};
5#[cfg(not(feature = "strict"))]
6use crate::hex::hex_val;
7#[cfg(feature = "strict")]
8use crate::hex::{has_lowercase_hex, hex_val};
9#[cfg(feature = "alloc")]
10use alloc::string::String;
11
12#[cfg(feature = "alloc")]
13pub fn decode(input: &str) -> Result<String, Error> {
14 #[cfg(not(feature = "strict"))]
15 {
16 if !input.as_bytes().contains(&b',') {
17 return Ok(String::from(input));
19 }
20 }
21 let mut out = String::with_capacity(input.len());
22 let bytes = input.as_bytes();
23 let mut i = 0usize;
24 while i < bytes.len() {
25 if bytes[i] == b',' {
26 if i + 2 >= bytes.len() {
28 return Err(Error::new(ErrorKind::LoneComma, Some(i)));
29 }
30 let h1 = bytes[i + 1];
31 let h2 = bytes[i + 2];
32 #[cfg(feature = "strict")]
33 {
34 if has_lowercase_hex(h1, h2) {
35 return Err(Error::new(ErrorKind::LowercaseHexInStrict, Some(i)));
36 }
37 }
38 let v1 = hex_val(h1)
39 .ok_or_else(|| Error::new(ErrorKind::InvalidHexDigit(h1 as char), Some(i + 1)))?;
40 let v2 = hex_val(h2)
41 .ok_or_else(|| Error::new(ErrorKind::InvalidHexDigit(h2 as char), Some(i + 2)))?;
42 let val = (v1 << 4) | v2;
43 out.push(val as char);
44 i += 3;
45 } else {
46 let s = &input[i..];
48 let ch = s.chars().next().unwrap();
49 #[cfg(feature = "strict")]
50 {
51 if ch.is_ascii() {
52 let bch = ch as u8;
53 if !is_unreserved(bch) {
54 return Err(Error::new(ErrorKind::UnescapedReservedAscii(ch), Some(i)));
55 }
56 }
57 }
58 out.push(ch);
59 i += ch.len_utf8();
60 }
61 }
62 Ok(out)
63}