1#![warn(clippy::print_stderr, clippy::print_stdout, clippy::dbg_macro)]
38#![warn(clippy::todo)]
39#![warn(missing_docs)]
40
41use std::io::Write;
42
43use hid_types::encoding::{Size, TagTypeSize, TypeBits};
44use hid_types::hid::{CollectionType, InputFlags, IoFlags, OutputFeatureFlags, Unit};
45use hid_types::id::tag::{GlobalItem, LocalItem, MainItem};
46use hid_types::id::usage::UsagePage;
47use hid_types::item::usage::{ExtendedUsage, Usage};
48use hid_types::item::{Global, Item, Local, LongItem, Main};
49
50pub fn decode<W, I>(writer: W, bytes: I) -> std::io::Result<()>
54where
55 W: Write,
56 I: IntoIterator<Item = u8>,
57{
58 decode_with_options(writer, bytes, Verbosity::default())
59}
60
61pub fn decode_with_options<W, I>(
66 mut writer: W,
67 bytes: I,
68 verbosity: Verbosity,
69) -> std::io::Result<()>
70where
71 W: Write,
72 I: IntoIterator<Item = u8>,
73{
74 let mut iter = bytes.into_iter();
75 let mut decoder = DecoderContext::new(verbosity);
76 loop {
77 match decoder.decode_one(&mut iter) {
78 Ok(Some(item)) => {
79 if decoder.verbosity.display_tag_type {
80 write!(writer, "{:9}", item.type_note())?;
81 }
82 writeln!(writer, "{item}")?;
83 }
84 Ok(None) => break,
85 Err(_e) => return Err(std::io::Error::other("decoding failed")),
86 }
87 }
88 Ok(())
89}
90
91#[derive(Clone, Default)]
93pub struct Verbosity {
94 pub display_tag_type: bool,
96}
97
98#[derive(Default)]
100pub struct DecoderContext {
101 verbosity: Verbosity,
103 usage_page: Option<UsagePage>,
105}
106
107impl DecoderContext {
108 fn new(verbosity: Verbosity) -> Self {
109 Self {
110 verbosity,
111 ..Default::default()
112 }
113 }
114
115 pub fn decode_one<Iter>(&mut self, iter: &mut Iter) -> Result<Option<Item>, LengthError>
119 where
120 Iter: Iterator<Item = u8>,
121 {
122 let Some(tag) = iter.next() else {
123 return Ok(None);
125 };
126 let tag = TagTypeSize::from_bits(tag);
127
128 let more = match tag.size() {
129 Size::Short(size_bytes) => {
130 let iter_remaining = iter.take(size_bytes);
131 iter_remaining.collect::<Vec<_>>()
132 }
133 Size::Long => {
134 let (Some(size), Some(tag)) = (iter.next(), iter.next()) else {
135 return Err(LengthError::Truncated);
136 };
137 let iter_payload = iter.take(usize::from(size));
138 let data = iter_payload.collect::<Vec<_>>();
139 let item = Item::Long(LongItem { tag, data });
140 return Ok(Some(item));
141 }
142 };
143
144 match tag.ty() {
145 TypeBits::Main => {
146 let item = MainItem::from(tag.tag());
147 let decoded = match item {
148 MainItem::Input => {
149 let data = slice_to_u32(&more)?;
150 let flags = InputFlags(IoFlags::from(data));
151 Main::Input(flags)
152 }
153 MainItem::Output => {
154 let data = slice_to_u32(&more)?;
155 let flags = OutputFeatureFlags(IoFlags::from(data));
156 Main::Output(flags)
157 }
158 MainItem::Feature => {
159 let data = slice_to_u32(&more)?;
160 let flags = OutputFeatureFlags(IoFlags::from(data));
161 Main::Feature(flags)
162 }
163 MainItem::Collection => {
164 assert_eq!(more.len(), 1);
165 let coll_type = CollectionType::from_integer(more[0]);
166 Main::Collection(coll_type)
167 }
168 MainItem::EndCollection => {
169 assert!(more.is_empty());
170 Main::EndCollection
171 }
172 MainItem::Reserved => Main::Reserved(tag.tag()),
173 };
174 Ok(Some(Item::Main(decoded)))
175 }
176 TypeBits::Global => {
177 let item = GlobalItem::from(tag.tag());
178 let decoded = match item {
179 GlobalItem::UsagePage => {
180 let page_number = slice_to_u16(&more)?;
181 let usage_page = UsagePage::from_integer(page_number);
182 self.usage_page = Some(usage_page);
183 Global::UsagePage(usage_page)
184 }
185 GlobalItem::LogicalMinimum => {
186 let num = slice_to_i32(&more)?;
187 Global::LogicalMinimum(num)
188 }
189 GlobalItem::LogicalMaximum => {
190 let num = slice_to_i32(&more)?;
191 Global::LogicalMaximum(num)
192 }
193 GlobalItem::PhysicalMinimum => {
194 let num = slice_to_i32(&more)?;
195 Global::PhysicalMinimum(num)
196 }
197 GlobalItem::PhysicalMaximum => {
198 let num = slice_to_i32(&more)?;
199 Global::PhysicalMaximum(num)
200 }
201 GlobalItem::UnitExponent => {
202 let num = slice_to_i32(&more)?;
203 Global::UnitExponent(num)
204 }
205 GlobalItem::ReportSize => {
206 let num = slice_to_u32(&more)?;
207 Global::ReportSize(num)
208 }
209 GlobalItem::ReportId => {
210 let num = slice_to_u32(&more)?;
211 Global::ReportId(num)
212 }
213 GlobalItem::ReportCount => {
214 let num = slice_to_u32(&more)?;
215 Global::ReportCount(num)
216 }
217 GlobalItem::Unit => {
218 let num = slice_to_u32(&more)?;
219 let unit = Unit::from_integer(num);
220 Global::Unit(unit)
221 }
222 GlobalItem::Push => Global::Push,
223 GlobalItem::Pop => Global::Pop,
224 GlobalItem::Reserved => Global::Reserved(tag.tag()),
225 };
226 Ok(Some(Item::Global(decoded)))
227 }
228 TypeBits::Local => {
229 let item = LocalItem::from(tag.tag());
230 let decoded = match item {
231 LocalItem::Usage => {
232 match slice_to_u16(&more) {
236 Ok(page_id) => match self.usage_page {
237 Some(page) => Local::Usage(Usage::new(page, page_id)),
238
239 None => Local::Usage(Usage::without_page(page_id)),
240 },
241 Err(LengthError::DataTooBig) => {
242 let value = slice_to_u32(&more)?;
243 Local::ExtendedUsage(ExtendedUsage::from_u32(value))
244 }
245 Err(e) => return Err(e),
246 }
247 }
248 LocalItem::UsageMinimum => {
249 let num = slice_to_u32(&more)?;
250 Local::UsageMinimum(num)
251 }
252 LocalItem::UsageMaximum => {
253 let num = slice_to_u32(&more)?;
254 Local::UsageMaximum(num)
255 }
256 LocalItem::DesignatorIndex => {
257 let num = slice_to_u32(&more)?;
258 Local::DesignatorIndex(num)
259 }
260 LocalItem::DesignatorMinimum => {
261 let num = slice_to_u32(&more)?;
262 Local::DesignatorMinimum(num)
263 }
264 LocalItem::DesignatorMaximum => {
265 let num = slice_to_u32(&more)?;
266 Local::DesignatorMaximum(num)
267 }
268 LocalItem::StringIndex => {
269 let num = slice_to_u32(&more)?;
270 Local::StringIndex(num)
271 }
272 LocalItem::StringMinimum => {
273 let num = slice_to_u32(&more)?;
274 Local::StringMinimum(num)
275 }
276 LocalItem::StringMaximum => {
277 let num = slice_to_u32(&more)?;
278 Local::StringMaximum(num)
279 }
280 LocalItem::Delimiter => {
281 let num = slice_to_u8(&more)?;
282 let param = match num {
283 0 => false,
284 1 => true,
285 _ => return Err(LengthError::DataTooBig),
286 };
287 Local::Delimiter(param)
288 }
289 LocalItem::Reserved => Local::Reserved(tag.tag()),
290 };
291 Ok(Some(Item::Local(decoded)))
292 }
293 TypeBits::Reserved => {
294 let decoded = Item::Reserved(tag.ty().into_bits());
295 Ok(Some(decoded))
296 }
297 }
298 }
299}
300
301#[derive(Clone, Debug)]
303pub enum LengthError {
304 DataTooBig,
306 ZeroLength,
308 Truncated,
310}
311
312fn slice_to_u8(slice: &[u8]) -> Result<u8, LengthError> {
313 match slice.len() {
314 0 => Err(LengthError::ZeroLength),
315 1 => Ok(slice[0]),
316 _ => Err(LengthError::DataTooBig),
317 }
318}
319
320fn slice_to_u16(slice: &[u8]) -> Result<u16, LengthError> {
321 match slice.len() {
322 0 => Err(LengthError::ZeroLength),
323 1 => Ok(slice[0] as u16),
324 2 => {
325 let ar: &[u8; 2] = slice.as_array().unwrap();
326 Ok(u16::from_le_bytes(*ar))
327 }
328 _ => Err(LengthError::DataTooBig),
329 }
330}
331
332fn slice_to_u32(slice: &[u8]) -> Result<u32, LengthError> {
333 match slice.len() {
334 0 => Err(LengthError::ZeroLength),
335 1 => Ok(slice[0] as u32),
336 2 => {
337 let ar: &[u8; 2] = slice.as_array().unwrap();
338 let value = u16::from_le_bytes(*ar);
339 Ok(value as u32)
340 }
341 3 => Err(LengthError::Truncated),
342 4 => {
343 let ar: &[u8; 4] = slice.as_array().unwrap();
344 Ok(u32::from_le_bytes(*ar))
345 }
346 _ => Err(LengthError::DataTooBig),
347 }
348}
349
350fn slice_to_i32(slice: &[u8]) -> Result<i32, LengthError> {
351 match slice.len() {
352 0 => Err(LengthError::ZeroLength),
353 1 => Ok(slice[0] as i8 as i32),
354 2 => {
355 let ar: &[u8; 2] = slice.as_array().unwrap();
356 let value = i16::from_le_bytes(*ar);
357 Ok(value as i32)
358 }
359 3 => Err(LengthError::Truncated),
360 4 => {
361 let ar: &[u8; 4] = slice.as_array().unwrap();
362 Ok(i32::from_le_bytes(*ar))
363 }
364 _ => Err(LengthError::DataTooBig),
365 }
366}
367
368#[cfg(test)]
369mod tests {
370 use super::*;
371
372 #[test]
373 fn test_integer_decoding() {
374 assert_eq!(slice_to_u8(&[0xFF]).unwrap(), 0xFF);
375 slice_to_u8(&[]).unwrap_err();
376 slice_to_u8(&[0xFF, 0xFF]).unwrap_err();
377
378 assert_eq!(slice_to_u16(&[0xFF]).unwrap(), 0xFF);
379 assert_eq!(slice_to_u16(&[0xFF, 0xFF]).unwrap(), 0xFFFF);
380 assert_eq!(slice_to_u16(&[1, 2]).unwrap(), 0x0201);
381 slice_to_u16(&[]).unwrap_err();
382 slice_to_u16(&[0xFF; 3]).unwrap_err();
383 slice_to_u16(&[0xFF; 4]).unwrap_err();
384
385 assert_eq!(slice_to_u32(&[0xFF]).unwrap(), 0xFF);
386 assert_eq!(slice_to_u32(&[0xFF, 0xFF]).unwrap(), 0xFFFF);
387 assert_eq!(slice_to_u32(&[1, 2]).unwrap(), 0x0201);
388 assert_eq!(slice_to_u32(&[0xFF; 4]).unwrap(), 0xFFFFFFFF);
389 assert_eq!(slice_to_u32(&[1, 2, 3, 4]).unwrap(), 0x04030201);
390 slice_to_u32(&[]).unwrap_err();
391 slice_to_u32(&[0xFF; 3]).unwrap_err();
392 slice_to_u32(&[0xFF; 5]).unwrap_err();
393
394 assert_eq!(slice_to_i32(&[0]).unwrap(), 0);
395 assert_eq!(slice_to_i32(&[0, 0]).unwrap(), 0);
396 assert_eq!(slice_to_i32(&[1, 2]).unwrap(), 0x0201);
397 assert_eq!(slice_to_i32(&[0; 4]).unwrap(), 0);
398 assert_eq!(slice_to_i32(&[1, 2, 3, 4]).unwrap(), 0x04030201);
399 assert_eq!(slice_to_i32(&[0xFF]).unwrap(), -1);
400 assert_eq!(slice_to_i32(&[0xFF, 0xFF]).unwrap(), -1);
401 assert_eq!(slice_to_i32(&[0xFF; 4]).unwrap(), -1);
402 slice_to_i32(&[]).unwrap_err();
403 slice_to_i32(&[0xFF; 3]).unwrap_err();
404 slice_to_i32(&[0xFF; 5]).unwrap_err();
405 }
406}