1use {
2 super::{bracketed, map_err, trim_spaces, OResult, Value, ValueParser},
3 nom::{
4 branch::alt,
5 bytes::complete::{is_not, tag, take},
6 character::complete::{char, space1, u8},
7 combinator::{all_consuming, map, map_parser, map_res, opt, rest},
8 multi::{fold_many0, many0, separated_list0},
9 sequence::{separated_pair, tuple},
10 Finish, IResult,
11 },
12 std::{borrow::Cow, fmt, io, str},
13};
14
15#[derive(Clone, PartialEq, Eq)]
16pub struct VcpValue {
17 pub value: u8,
18 pub sub_values: Option<Vec<u8>>,
19}
20
21impl VcpValue {
22 pub fn new(value: u8) -> Self {
23 VcpValue {
24 value,
25 sub_values: None,
26 }
27 }
28
29 pub fn sub_values(&self) -> &[u8] {
30 self.sub_values.as_ref().map(|v| &v[..]).unwrap_or_default()
31 }
32}
33
34impl fmt::Debug for VcpValue {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 let mut debug = f.debug_tuple("VcpValue");
37 let debug = debug.field(&self.value);
38 match self.sub_values() {
39 &[] => debug.finish(),
40 values => debug.field(&values).finish(),
41 }
42 }
43}
44
45#[derive(Clone, PartialEq, Eq)]
46pub struct Vcp {
47 pub feature: u8,
48 pub values: Option<Vec<VcpValue>>,
49}
50
51impl Vcp {
52 pub fn values(&self) -> &[VcpValue] {
53 self.values.as_ref().map(|v| &v[..]).unwrap_or_default()
54 }
55}
56
57impl fmt::Debug for Vcp {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 let mut debug = f.debug_tuple("Vcp");
60 let debug = debug.field(&self.feature);
61 match self.values() {
62 &[] => debug.finish(),
63 values => debug.field(&values).finish(),
64 }
65 }
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
69pub struct VcpName<'i> {
70 pub feature: u8,
71 pub name: Option<Cow<'i, str>>,
72 pub value_names: Option<Vec<Cow<'i, str>>>,
73}
74
75impl<'i> VcpName<'i> {
76 pub fn value_names(&self) -> &[Cow<'i, str>] {
77 self.value_names.as_ref().map(|v| &v[..]).unwrap_or_default()
78 }
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
83pub enum Cap<'a> {
84 Protocol(&'a str),
85 Type(&'a str),
86 Model(&'a str),
87 Commands(Vec<u8>),
88 Whql(u8),
89 MccsVersion(u8, u8),
90 Vcp(Vec<Vcp>),
91 VcpNames(Vec<VcpName<'a>>),
92 Edid(&'a [u8]),
93 Vdif(&'a [u8]),
94 Unknown(Value<'a>),
95}
96
97impl<'i> Cap<'i> {
98 pub fn parse_entries(entries: ValueParser<'i>) -> impl Iterator<Item = io::Result<Cap<'i>>> + 'i {
99 entries
100 .nom_iter()
101 .map(|e| e.and_then(|e| Self::parse_entry(e)).map_err(map_err))
102 }
103
104 pub fn parse_entry(value: Value<'i>) -> OResult<'i, Cap<'i>> {
105 match value {
106 Value::String { tag, value } => Self::parse_string(tag, value),
107 Value::Binary { tag, data } => Ok(Self::parse_data(tag, data)),
108 }
109 }
110
111 pub fn parse_data(tag: &'i str, i: &'i [u8]) -> Cap<'i> {
112 match tag {
113 "edid" => Cap::Edid(i),
114 "vdif" => Cap::Vdif(i),
115 _ => Cap::Unknown(Value::Binary { tag, data: i }),
116 }
117 }
118
119 pub fn parse_string(tag: &'i str, i: &'i [u8]) -> OResult<'i, Cap<'i>> {
120 match tag {
121 "prot" => all_consuming(map(value, Cap::Protocol))(i),
122 "type" => all_consuming(map(value, Cap::Type))(i),
123 "model" => all_consuming(map(value, Cap::Model))(i),
124 "cmds" => all_consuming(map(hexarray, Cap::Commands))(i),
125 "mswhql" => all_consuming(map(map_parser(take(1usize), u8), Cap::Whql))(i),
126 "mccs_ver" => all_consuming(map(mccs_ver, |(major, minor)| Cap::MccsVersion(major, minor)))(i),
127 "vcp" | "VCP" => all_consuming(map(trim_spaces(many0(vcp)), Cap::Vcp))(i),
129 "vcpname" => all_consuming(map(many0(vcpname), Cap::VcpNames))(i),
130 _ => Ok((Default::default(), Cap::Unknown(Value::String { tag, value: i }))),
131 }
132 .finish()
133 .map(|(_, c)| c)
134 }
135}
136
137fn backslash_escape(i: &[u8]) -> IResult<&[u8], String> {
138 let escaped = |i| {
142 let (i, _) = tag("\\x")(i)?;
143 map_str(take(2usize), |h| u8::from_str_radix(h, 16).map(|v| v as char), i)
144 };
145 fold_many0(
146 alt((
147 escaped,
148 map(take(1usize), |s: &[u8]| s[0] as char), )),
151 || String::new(),
152 |mut s: String, c| {
153 s.push(c);
154 s
155 },
156 )(i)
157}
158
159fn value_escape_nospace(i: &[u8]) -> IResult<&[u8], Cow<str>> {
160 map_parser(
161 is_not(" ()"),
162 alt((
163 all_consuming(map(map_res(is_not("\\"), str::from_utf8), Cow::Borrowed)),
164 map(all_consuming(backslash_escape), Cow::Owned),
165 )),
166 )(i)
167}
168
169fn value(i: &[u8]) -> IResult<&[u8], &str> {
170 map_res(rest, str::from_utf8)(i)
171}
172
173fn hexarray(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
174 many0(trim_spaces(hexvalue))(i)
175}
176
177fn map_str<'i, O, E2, F, G>(mut parser: F, f: G, i: &'i [u8]) -> IResult<&'i [u8], O>
178where
179 F: nom::Parser<&'i [u8], &'i [u8], nom::error::Error<&'i [u8]>>,
180 G: FnMut(&'i str) -> Result<O, E2>,
181{
182 use nom::Parser;
183
184 let mut f = map_res(rest, f);
185 let (i, s) = map_res(|i| parser.parse(i), |i| str::from_utf8(i.into()))(i)?;
186 match f.parse(s) {
187 Ok((_, v)) => Ok((i, v)),
188 Err(e) => Err(e.map(|e: nom::error::Error<_>| nom::error::Error { input: i, code: e.code })),
189 }
190}
191
192fn hexvalue(i: &[u8]) -> IResult<&[u8], u8> {
193 map_str(take(2usize), |s| u8::from_str_radix(s, 16), i)
194}
195
196fn vcp_value(i: &[u8]) -> IResult<&[u8], VcpValue> {
197 map(
198 tuple((trim_spaces(hexvalue), opt(bracketed(many0(trim_spaces(hexvalue)))))),
199 |(value, sub_values)| VcpValue { value, sub_values },
200 )(i)
201}
202
203fn vcp(i: &[u8]) -> IResult<&[u8], Vcp> {
204 let featurevalues = bracketed(many0(trim_spaces(vcp_value)));
205 map(
206 tuple((trim_spaces(hexvalue), opt(featurevalues))),
207 |(feature, values)| Vcp { feature, values },
208 )(i)
209}
210
211fn vcpname(i: &[u8]) -> IResult<&[u8], VcpName> {
212 let (i, feature) = trim_spaces(hexvalue)(i)?;
213 let (i, (name, value_names)) = bracketed(tuple((
214 opt(value_escape_nospace),
215 opt(bracketed(trim_spaces(separated_list0(space1, value_escape_nospace)))),
216 )))(i)?;
217 Ok((i, VcpName {
218 feature,
219 name,
220 value_names,
221 }))
222}
223
224fn mccs_ver(i: &[u8]) -> IResult<&[u8], (u8, u8)> {
225 alt((
226 separated_pair(u8, char('.'), u8),
227 tuple((map_parser(take(2usize), u8), map_parser(take(2usize), u8))),
228 ))(i)
229}
230
231#[test]
232fn vcpname_temp() {
233 let testdata = br"14((9300 6500 5500))44(Rotate)80(Do\x20this(On Off))82(Fixit)";
234 let expected = [
235 VcpName {
236 feature: 0x14,
237 name: None,
238 value_names: Some(vec!["9300".into(), "6500".into(), "5500".into()]),
239 },
240 VcpName {
241 feature: 0x44,
242 name: Some("Rotate".into()),
243 value_names: None,
244 },
245 VcpName {
246 feature: 0x80,
247 name: Some("Do this".into()),
248 value_names: Some(vec!["On".into(), "Off".into()]),
249 },
250 VcpName {
251 feature: 0x82,
252 name: Some("Fixit".into()),
253 value_names: None,
254 },
255 ];
256
257 let (_, vcps) = all_consuming(many0(vcpname))(testdata).finish().unwrap();
258 assert_eq!(vcps.len(), expected.len());
259
260 for (vcp, exp) in vcps.into_iter().zip(expected) {
261 assert_eq!(vcp, exp);
262 }
263}
264
265#[test]
266fn vcpname_brightness() {
267 let testdata = b"10(Brightness)";
268 let expected = VcpName {
269 feature: 0x10,
270 name: Some("Brightness".into()),
271 value_names: None,
272 };
273 let (_, vcp) = all_consuming(vcpname)(testdata).finish().unwrap();
274
275 assert_eq!(vcp, expected);
276}