Skip to main content

hid_decode/
item.rs

1//! Decode a single item inside an HID report descriptor.
2
3use hid_types::encoding::{Size, TagTypeSize, TypeBits};
4use hid_types::hid::{CollectionType, InputFlags, IoFlags, OutputFeatureFlags, Unit};
5use hid_types::id::tag::{GlobalItem, LocalItem, MainItem};
6use hid_types::id::usage::UsagePage;
7use hid_types::item::usage::{ExtendedUsage, Usage};
8use hid_types::item::{Global, Item, Local, LongItem, Main};
9use tinyvec::TinyVec;
10
11/// Context that can affect the way the decoder interprets subsequent descriptor items.
12#[derive(Default, Debug, Clone)]
13pub struct DecoderContext {
14    /// The current usage page.
15    usage_page: Option<UsagePage>,
16}
17
18/// A successfully decoded descriptor item.
19pub struct DecodedItem {
20    /// The decoded descriptor item.
21    pub item: Item,
22    /// The bytes this item was decoded from.
23    pub bytes: TinyVec<[u8; 8]>,
24}
25
26impl DecodedItem {
27    // FIXME: rename
28    fn yes<T, E>(item: Item, iter: Recorder<T>) -> Result<Self, E> {
29        Ok(Self {
30            item,
31            bytes: iter.take_bytes(),
32        })
33    }
34}
35
36/// Decode one item from its encoded bytes.
37///
38/// This will consume one or more bytes from the input iterator.
39pub fn decode_one<Iter>(
40    iter: Iter,
41    context: &mut DecoderContext,
42) -> Option<Result<DecodedItem, LengthError>>
43where
44    Iter: Iterator<Item = u8>,
45{
46    let mut iter = Recorder::new(iter);
47
48    let Some(tag) = iter.next() else {
49        // End of input iterator
50        return None;
51    };
52    Some(decode_one_inner(iter, context, tag))
53}
54
55/// Decode one item from its tag and any data bytes that follow.
56///
57/// This will consume zero or more bytes from the input iterator.
58fn decode_one_inner<I>(
59    mut iter: Recorder<I>,
60    context: &mut DecoderContext,
61    tag: u8,
62) -> Result<DecodedItem, LengthError>
63where
64    I: Iterator<Item = u8>,
65{
66    let tag = TagTypeSize::from_bits(tag);
67
68    let more: TinyVec<[u8; 8]> = match tag.size() {
69        Size::Short(size_bytes) => {
70            let iter_remaining = (&mut iter).take(size_bytes);
71            iter_remaining.collect()
72        }
73        Size::Long => {
74            let (Some(size), Some(tag)) = (iter.next(), iter.next()) else {
75                return Err(LengthError::Truncated);
76            };
77            let iter_payload = (&mut iter).take(usize::from(size));
78            let data = iter_payload.collect::<Vec<_>>();
79            let item = Item::Long(LongItem { tag, data });
80            return DecodedItem::yes(item, iter);
81        }
82    };
83
84    match tag.ty() {
85        TypeBits::Main => {
86            let item = MainItem::from(tag.tag());
87            let decoded = match item {
88                MainItem::Input => {
89                    let data = slice_to_u32(&more)?;
90                    let flags = InputFlags(IoFlags::from(data));
91                    Main::Input(flags)
92                }
93                MainItem::Output => {
94                    let data = slice_to_u32(&more)?;
95                    let flags = OutputFeatureFlags(IoFlags::from(data));
96                    Main::Output(flags)
97                }
98                MainItem::Feature => {
99                    let data = slice_to_u32(&more)?;
100                    let flags = OutputFeatureFlags(IoFlags::from(data));
101                    Main::Feature(flags)
102                }
103                MainItem::Collection => {
104                    assert_eq!(more.len(), 1);
105                    let coll_type = CollectionType::from_integer(more[0]);
106                    Main::Collection(coll_type)
107                }
108                MainItem::EndCollection => {
109                    assert!(more.is_empty());
110                    Main::EndCollection
111                }
112                MainItem::Reserved => Main::Reserved(tag.tag()),
113            };
114            DecodedItem::yes(Item::Main(decoded), iter)
115        }
116        TypeBits::Global => {
117            let item = GlobalItem::from(tag.tag());
118            let decoded = match item {
119                GlobalItem::UsagePage => {
120                    let page_number = slice_to_u16(&more)?;
121                    let usage_page = UsagePage::from_integer(page_number);
122                    context.usage_page = Some(usage_page);
123                    Global::UsagePage(usage_page)
124                }
125                GlobalItem::LogicalMinimum => {
126                    let num = slice_to_i32(&more)?;
127                    Global::LogicalMinimum(num)
128                }
129                GlobalItem::LogicalMaximum => {
130                    let num = slice_to_i32(&more)?;
131                    Global::LogicalMaximum(num)
132                }
133                GlobalItem::PhysicalMinimum => {
134                    let num = slice_to_i32(&more)?;
135                    Global::PhysicalMinimum(num)
136                }
137                GlobalItem::PhysicalMaximum => {
138                    let num = slice_to_i32(&more)?;
139                    Global::PhysicalMaximum(num)
140                }
141                GlobalItem::UnitExponent => {
142                    let num = slice_to_i32(&more)?;
143                    Global::UnitExponent(num)
144                }
145                GlobalItem::ReportSize => {
146                    let num = slice_to_u32(&more)?;
147                    Global::ReportSize(num)
148                }
149                GlobalItem::ReportId => {
150                    let num = slice_to_u32(&more)?;
151                    Global::ReportId(num)
152                }
153                GlobalItem::ReportCount => {
154                    let num = slice_to_u32(&more)?;
155                    Global::ReportCount(num)
156                }
157                GlobalItem::Unit => {
158                    let num = slice_to_u32(&more)?;
159                    let unit = Unit::from_integer(num);
160                    Global::Unit(unit)
161                }
162                GlobalItem::Push => Global::Push,
163                GlobalItem::Pop => Global::Pop,
164                GlobalItem::Reserved => Global::Reserved(tag.tag()),
165            };
166            DecodedItem::yes(Item::Global(decoded), iter)
167        }
168        TypeBits::Local => {
169            let item = LocalItem::from(tag.tag());
170            let decoded = match item {
171                LocalItem::Usage => {
172                    // If the payload is 1 or 2 bytes, we use the
173                    // existing page number. If the payload is 4 bytes, it
174                    // contains both the page number and page id.
175                    match slice_to_u16(&more) {
176                        Ok(page_id) => match context.usage_page {
177                            Some(page) => Local::Usage(Usage::new(page, page_id)),
178
179                            None => Local::Usage(Usage::without_page(page_id)),
180                        },
181                        Err(LengthError::DataTooBig) => {
182                            let value = slice_to_u32(&more)?;
183                            Local::ExtendedUsage(ExtendedUsage::from_u32(value))
184                        }
185                        Err(e) => return Err(e),
186                    }
187                }
188                LocalItem::UsageMinimum => {
189                    let num = slice_to_u32(&more)?;
190                    Local::UsageMinimum(num)
191                }
192                LocalItem::UsageMaximum => {
193                    let num = slice_to_u32(&more)?;
194                    Local::UsageMaximum(num)
195                }
196                LocalItem::DesignatorIndex => {
197                    let num = slice_to_u32(&more)?;
198                    Local::DesignatorIndex(num)
199                }
200                LocalItem::DesignatorMinimum => {
201                    let num = slice_to_u32(&more)?;
202                    Local::DesignatorMinimum(num)
203                }
204                LocalItem::DesignatorMaximum => {
205                    let num = slice_to_u32(&more)?;
206                    Local::DesignatorMaximum(num)
207                }
208                LocalItem::StringIndex => {
209                    let num = slice_to_u32(&more)?;
210                    Local::StringIndex(num)
211                }
212                LocalItem::StringMinimum => {
213                    let num = slice_to_u32(&more)?;
214                    Local::StringMinimum(num)
215                }
216                LocalItem::StringMaximum => {
217                    let num = slice_to_u32(&more)?;
218                    Local::StringMaximum(num)
219                }
220                LocalItem::Delimiter => {
221                    let num = slice_to_u8(&more)?;
222                    let param = match num {
223                        0 => false,
224                        1 => true,
225                        _ => return Err(LengthError::DataTooBig),
226                    };
227                    Local::Delimiter(param)
228                }
229                LocalItem::Reserved => Local::Reserved(tag.tag()),
230            };
231            DecodedItem::yes(Item::Local(decoded), iter)
232        }
233        TypeBits::Reserved => {
234            let decoded = Item::Reserved(tag.ty().into_bits());
235            DecodedItem::yes(decoded, iter)
236        }
237    }
238}
239
240/// An iterator that yields values from an inner iterator, but also collects everything that was yielded.
241struct Recorder<Iter> {
242    inner: Iter,
243    bytes: TinyVec<[u8; 8]>,
244}
245
246impl<Iter> Recorder<Iter> {
247    /// Create a new recording iterator.
248    fn new(iter: Iter) -> Self {
249        Self {
250            inner: iter,
251            bytes: TinyVec::new(),
252        }
253    }
254
255    /// Take the recorded bytes, consuming the iterator.
256    fn take_bytes(self) -> TinyVec<[u8; 8]> {
257        self.bytes
258    }
259}
260
261impl<Iter> Iterator for Recorder<Iter>
262where
263    Iter: Iterator<Item = u8>,
264{
265    type Item = u8;
266
267    fn next(&mut self) -> Option<Self::Item> {
268        self.inner.next().inspect(|b| {
269            self.bytes.push(*b);
270        })
271    }
272}
273
274/// An error that resulted from improper item encoding.
275#[derive(Clone, Debug, thiserror::Error)]
276pub enum LengthError {
277    /// The data length was too big for this item.
278    #[error("item data too big")]
279    DataTooBig,
280    /// A data length of zero is not allowed in this item.
281    #[error("missing item data")]
282    ZeroLength,
283    /// Ran out of bytes trying to decode this item.
284    #[error("item data truncated")]
285    Truncated,
286}
287
288fn slice_to_u8(slice: &[u8]) -> Result<u8, LengthError> {
289    match slice.len() {
290        0 => Err(LengthError::ZeroLength),
291        1 => Ok(slice[0]),
292        _ => Err(LengthError::DataTooBig),
293    }
294}
295
296fn slice_to_u16(slice: &[u8]) -> Result<u16, LengthError> {
297    match slice.len() {
298        0 => Err(LengthError::ZeroLength),
299        1 => Ok(slice[0] as u16),
300        2 => {
301            let ar: &[u8; 2] = slice.as_array().unwrap();
302            Ok(u16::from_le_bytes(*ar))
303        }
304        _ => Err(LengthError::DataTooBig),
305    }
306}
307
308fn slice_to_u32(slice: &[u8]) -> Result<u32, LengthError> {
309    match slice.len() {
310        0 => Err(LengthError::ZeroLength),
311        1 => Ok(slice[0] as u32),
312        2 => {
313            let ar: &[u8; 2] = slice.as_array().unwrap();
314            let value = u16::from_le_bytes(*ar);
315            Ok(value as u32)
316        }
317        3 => Err(LengthError::Truncated),
318        4 => {
319            let ar: &[u8; 4] = slice.as_array().unwrap();
320            Ok(u32::from_le_bytes(*ar))
321        }
322        _ => Err(LengthError::DataTooBig),
323    }
324}
325
326fn slice_to_i32(slice: &[u8]) -> Result<i32, LengthError> {
327    match slice.len() {
328        0 => Err(LengthError::ZeroLength),
329        1 => Ok(slice[0] as i8 as i32),
330        2 => {
331            let ar: &[u8; 2] = slice.as_array().unwrap();
332            let value = i16::from_le_bytes(*ar);
333            Ok(value as i32)
334        }
335        3 => Err(LengthError::Truncated),
336        4 => {
337            let ar: &[u8; 4] = slice.as_array().unwrap();
338            Ok(i32::from_le_bytes(*ar))
339        }
340        _ => Err(LengthError::DataTooBig),
341    }
342}
343
344#[cfg(test)]
345mod tests {
346    use super::*;
347
348    #[test]
349    fn _error_traits() {
350        use std::error::Error;
351        use std::fmt::Display;
352        let _err: Box<dyn Error> = Box::new(LengthError::DataTooBig);
353        let _err: Box<dyn Display> = Box::new(LengthError::DataTooBig);
354        assert_eq!(format!("{}", LengthError::Truncated), "item data truncated");
355    }
356
357    #[test]
358    fn test_integer_decoding() {
359        assert_eq!(slice_to_u8(&[0xFF]).unwrap(), 0xFF);
360        slice_to_u8(&[]).unwrap_err();
361        slice_to_u8(&[0xFF, 0xFF]).unwrap_err();
362
363        assert_eq!(slice_to_u16(&[0xFF]).unwrap(), 0xFF);
364        assert_eq!(slice_to_u16(&[0xFF, 0xFF]).unwrap(), 0xFFFF);
365        assert_eq!(slice_to_u16(&[1, 2]).unwrap(), 0x0201);
366        slice_to_u16(&[]).unwrap_err();
367        slice_to_u16(&[0xFF; 3]).unwrap_err();
368        slice_to_u16(&[0xFF; 4]).unwrap_err();
369
370        assert_eq!(slice_to_u32(&[0xFF]).unwrap(), 0xFF);
371        assert_eq!(slice_to_u32(&[0xFF, 0xFF]).unwrap(), 0xFFFF);
372        assert_eq!(slice_to_u32(&[1, 2]).unwrap(), 0x0201);
373        assert_eq!(slice_to_u32(&[0xFF; 4]).unwrap(), 0xFFFFFFFF);
374        assert_eq!(slice_to_u32(&[1, 2, 3, 4]).unwrap(), 0x04030201);
375        slice_to_u32(&[]).unwrap_err();
376        slice_to_u32(&[0xFF; 3]).unwrap_err();
377        slice_to_u32(&[0xFF; 5]).unwrap_err();
378
379        assert_eq!(slice_to_i32(&[0]).unwrap(), 0);
380        assert_eq!(slice_to_i32(&[0, 0]).unwrap(), 0);
381        assert_eq!(slice_to_i32(&[1, 2]).unwrap(), 0x0201);
382        assert_eq!(slice_to_i32(&[0; 4]).unwrap(), 0);
383        assert_eq!(slice_to_i32(&[1, 2, 3, 4]).unwrap(), 0x04030201);
384        assert_eq!(slice_to_i32(&[0xFF]).unwrap(), -1);
385        assert_eq!(slice_to_i32(&[0xFF, 0xFF]).unwrap(), -1);
386        assert_eq!(slice_to_i32(&[0xFF; 4]).unwrap(), -1);
387        slice_to_i32(&[]).unwrap_err();
388        slice_to_i32(&[0xFF; 3]).unwrap_err();
389        slice_to_i32(&[0xFF; 5]).unwrap_err();
390    }
391}