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 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}