mccs_caps/
entries.rs

1use {
2    super::{bracketed, map_err, trim_spaces, OResult, OResultI, Value},
3    nom::{
4        branch::alt,
5        bytes::complete::{tag, take, take_while1, take_while_m_n},
6        character::{
7            complete::{alphanumeric1, char, space0, u32},
8            is_alphanumeric,
9        },
10        combinator::{complete, fail, map, map_res, not, peek},
11        error::{self, ErrorKind},
12        sequence::{preceded, tuple},
13        IResult, Parser,
14    },
15    std::{io, str},
16};
17
18#[derive(Clone, Default, Debug, PartialEq, Eq)]
19pub struct ValueParser<'i> {
20    pub input: &'i [u8],
21    pub brackets: Option<usize>,
22    previous_tag: Option<&'i str>,
23}
24
25impl<'i> Iterator for ValueParser<'i> {
26    type Item = io::Result<Value<'i>>;
27
28    fn next(&mut self) -> Option<Self::Item> {
29        if self.input.is_empty() {
30            return None
31        }
32
33        Some(self.nom_result().map_err(map_err))
34    }
35}
36
37impl<'i> ValueParser<'i> {
38    pub fn new(capability_string: &'i [u8]) -> ValueParser<'i> {
39        Self {
40            input: capability_string,
41            brackets: None,
42            previous_tag: None,
43        }
44    }
45
46    pub fn nom_iter(mut self) -> impl Iterator<Item = OResult<'i, Value<'i>>> + 'i {
47        std::iter::from_fn(move || match self.input.is_empty() {
48            true => None,
49            false => Some(self.nom_result()),
50        })
51    }
52
53    pub fn nom_result(&mut self) -> OResult<'i, Value<'i>> {
54        match self.nom() {
55            Ok(o) => Ok(o),
56            Err(nom::Err::Error(e) | nom::Err::Failure(e)) => Err(e),
57            Err(nom::Err::Incomplete(_)) => Err(error::Error::new(self.input, ErrorKind::Eof)),
58        }
59    }
60
61    pub fn nom(&mut self) -> OResultI<'i, Value<'i>> {
62        self.parse(self.input).map(|(_, e)| e)
63    }
64}
65
66impl<'i> Parser<&'i [u8], Value<'i>, error::Error<&'i [u8]>> for ValueParser<'i> {
67    fn parse(&mut self, input: &'i [u8]) -> IResult<&'i [u8], Value<'i>> {
68        let (input, mut brackets) = match self.brackets {
69            None => {
70                let (input, brackets) = caps_prefix(input)?;
71                self.input = input;
72                self.brackets = Some(brackets);
73                (input, brackets)
74            },
75            Some(brackets) => (input, brackets),
76        };
77
78        let (input, e) = Value::parse_nom(input, self.previous_tag)?;
79        self.previous_tag = Some(e.tag());
80        self.input = input;
81
82        let input = match caps_suffix(brackets, input) {
83            Ok((rest, _)) if rest == input => input,
84            Ok((input, brackets_consumed)) => {
85                brackets -= brackets_consumed;
86                self.input = input;
87                self.brackets = Some(brackets);
88                input
89            },
90            Err(_) => unreachable!(),
91        };
92
93        Ok((input, e))
94    }
95}
96
97fn caps_prefix(i: &[u8]) -> IResult<&[u8], usize> {
98    // hack around Apple Cinema Display and other displays without any surrounding brackets
99    // and displays with too many brackets
100    let (i, brackets) = take_while_m_n(0, 2, |c| c == b'(')(i)?;
101    Ok((i, brackets.len()))
102}
103
104fn caps_suffix(mut brackets: usize, mut i: &[u8]) -> IResult<&[u8], usize> {
105    let mut bracket_count = 0;
106    loop {
107        i = match i.split_first() {
108            Some((&b')', i)) => match brackets.checked_sub(1) {
109                Some(b) => {
110                    brackets = b;
111                    bracket_count += 1;
112                    i
113                },
114                None => break,
115            },
116            Some((&0 | &b' ', i)) => i,
117            _ => break,
118        };
119    }
120    Ok((i, bracket_count))
121}
122
123impl<'i> Value<'i> {
124    pub fn parse_nom(input: &'i [u8], previous_tag: Option<&'i str>) -> IResult<&'i [u8], Self> {
125        let (i, _) = space0(input)?;
126        let (i, id) = alt((
127            map(
128                preceded(tuple((tag("model"), peek(not(char('('))))), modelhack),
129                |value| Err(Value::String { tag: "model", value }),
130            ),
131            map(
132                |i| {
133                    if previous_tag == Some("type") {
134                        modelhack(i)
135                    } else {
136                        fail(i)
137                    }
138                },
139                |value| Err(Value::String { tag: "model", value }),
140            ),
141            map(ident, Ok),
142        ))(i)?;
143        let (i, cap) = match id {
144            Ok(id) => alt((
145                map(preceded(tag(" bin"), bracketed(binary)), |data| Value::Binary {
146                    tag: id,
147                    data,
148                }),
149                map(bracketed(balancedparens), |value| Value::String { tag: id, value }),
150            ))(i),
151            Err(corrupted_model) => Ok((i, corrupted_model)),
152        }?;
153        let (i, _) = space0(i)?;
154        Ok((i, cap))
155    }
156
157    pub fn nom_parser() -> ValueParser<'i> {
158        Default::default()
159    }
160}
161
162fn binary(i: &[u8]) -> IResult<&[u8], &[u8]> {
163    let (i, count) = trim_spaces(u32)(i)?;
164    bracketed(take(count))(i)
165}
166
167fn modelhack(i: &[u8]) -> IResult<&[u8], &[u8]> {
168    let cmds = b"cmds";
169    let (rest, model) = alphanumeric1(i)?;
170    if !model.ends_with(cmds) || model == cmds {
171        let (_, ()) = fail(i)?;
172    }
173    let _ = peek(char('('))(rest)?;
174    let model = &model[..model.len() - 4];
175    Ok((&i[model.len()..], model))
176}
177
178fn ident(i: &[u8]) -> IResult<&[u8], &str> {
179    map_res(take_while1(|c| is_alphanumeric(c) || c == b'_'), str::from_utf8)(i)
180}
181
182fn balancedparens(i: &[u8]) -> IResult<&[u8], &[u8]> {
183    complete(balancedparens_incomplete)(i)
184}
185
186fn balancedparens_incomplete(i: &[u8]) -> IResult<&[u8], &[u8]> {
187    use nom::InputTake;
188
189    let mut depth = 0usize;
190    for (x, &c) in i.iter().enumerate() {
191        match c {
192            b')' => match depth.checked_sub(1) {
193                Some(v) => depth = v,
194                None => return Ok(i.take_split(x)),
195            },
196            b'(' => {
197                depth += 1;
198            },
199            _ => (),
200        }
201    }
202    match depth {
203        0 => Ok((i, Default::default())),
204        depth => Err(nom::Err::Incomplete(nom::Needed::new(depth))),
205    }
206}
207
208#[test]
209fn model_hacks() {
210    let testdata = [
211        (
212            &[
213                &b"type(lcd)ABCdcmds()"[..],
214                &b"type(lcd)modelABCdcmds()"[..],
215                &b"type(lcd)model(ABCd)cmds()"[..],
216            ][..],
217            &[
218                Value::String {
219                    tag: "type",
220                    value: b"lcd",
221                },
222                Value::String {
223                    tag: "model",
224                    value: b"ABCd",
225                },
226                Value::String {
227                    tag: "cmds",
228                    value: b"",
229                },
230            ][..],
231        ),
232        (
233            &[&b"type(lcd)cmds()model(ABCd)"[..]][..],
234            &[
235                Value::String {
236                    tag: "type",
237                    value: b"lcd",
238                },
239                Value::String {
240                    tag: "cmds",
241                    value: b"",
242                },
243                Value::String {
244                    tag: "model",
245                    value: b"ABCd",
246                },
247            ][..],
248        ),
249    ];
250
251    for (testdatas, expected) in testdata {
252        for testdata in testdatas {
253            let testdata: Result<Vec<_>, _> = ValueParser::new(testdata).collect();
254            assert_eq!(testdata.unwrap(), expected);
255        }
256    }
257}
258
259#[test]
260fn bin_entries() {
261    let testdata = b"edid bin(3(\xff) ))vdif bin(3 (abc))unknown bin(2(ab))";
262    let expected = [
263        Value::Binary {
264            tag: "edid",
265            data: b"\xff) ",
266        },
267        Value::Binary {
268            tag: "vdif",
269            data: b"abc",
270        },
271        Value::Binary {
272            tag: "unknown",
273            data: b"ab",
274        },
275    ];
276
277    let entries: Result<Vec<_>, _> = ValueParser::new(testdata).collect();
278    assert_eq!(entries.unwrap(), expected);
279}