Skip to main content

ms_codeview/types/
iter.rs

1//! Code for iterating through type streams
2
3use super::Leaf;
4use crate::parser::{Parser, ParserError, ParserMut};
5use crate::utils::iter::{HasRestLen, IteratorWithRangesExt};
6use std::mem::take;
7
8/// Parses a type record stream and iterates `TypeRecord` values.
9#[derive(Clone)]
10pub struct TypesIter<'a> {
11    buffer: &'a [u8],
12}
13
14impl<'a> TypesIter<'a> {
15    /// Starts a new iterator.
16    pub fn new(buffer: &'a [u8]) -> Self {
17        Self { buffer }
18    }
19
20    /// Returns the "rest" of the data that has not been parsed.
21    pub fn rest(&self) -> &'a [u8] {
22        self.buffer
23    }
24}
25
26impl<'a> HasRestLen for TypesIter<'a> {
27    fn rest_len(&self) -> usize {
28        self.buffer.len()
29    }
30}
31
32impl<'a> Iterator for TypesIter<'a> {
33    type Item = TypeRecord<'a>;
34
35    /// Finds the next type record
36    ///
37    /// This implementation makes an important guarantee: If it cannot decode the next record,
38    /// it _will not_ change `self.buffer`. This is important because it allows an application
39    /// to detect the exact length and contents of an unparseable record.
40    fn next(&mut self) -> Option<TypeRecord<'a>> {
41        if self.buffer.is_empty() {
42            return None;
43        }
44
45        let mut p = Parser::new(self.buffer);
46
47        let record_len = p.u16().ok()?;
48        if record_len < 2 {
49            // Type record has length that is too short to be valid
50            return None;
51        }
52
53        let type_kind = p.u16().ok()?;
54
55        let Ok(record_data) = p.bytes(record_len as usize - 2) else {
56            // Type record is too short to be valid.
57            return None;
58        };
59
60        self.buffer = p.into_rest();
61
62        Some(TypeRecord {
63            data: record_data,
64            kind: Leaf(type_kind),
65        })
66    }
67}
68
69/// Represents a record that was enumerated within a type record stream (the TPI or IPI).
70#[derive(Clone)]
71pub struct TypeRecord<'a> {
72    /// Indicates how to interpret the payload (the `data` field).
73    pub kind: Leaf,
74    /// Record data. This does NOT include `kind` and the record data length.
75    pub data: &'a [u8],
76}
77
78impl<'a> TypeRecord<'a> {
79    /// Parses the payload of this type record.
80    pub fn parse(&self) -> Result<crate::types::TypeData<'a>, ParserError> {
81        crate::types::TypeData::parse(self.kind, &mut Parser::new(self.data))
82    }
83}
84
85/// Builds a "starts" table that gives the starting location of each type record.
86pub fn build_types_starts(num_records_expected: usize, type_records: &[u8]) -> Vec<u32> {
87    let mut starts: Vec<u32> = Vec::with_capacity(num_records_expected + 1);
88    let mut iter = TypesIter::new(type_records).with_ranges();
89
90    // This loop pushes a byte offset (pos) for the start of every record, plus 1 additional
91    // value at the end of the sequence.  This will correctly handle the case where the last
92    // record has some undecodable garbage at the end.
93    loop {
94        let pos = iter.pos();
95        starts.push(pos as u32);
96
97        if iter.next().is_none() {
98            break;
99        }
100    }
101
102    starts.shrink_to_fit();
103    starts
104}
105
106/// Parses a type record stream and iterates `TypeRecord` values.
107pub struct TypesIterMut<'a> {
108    buffer: &'a mut [u8],
109}
110
111impl<'a> TypesIterMut<'a> {
112    /// Starts a new iterator.
113    pub fn new(buffer: &'a mut [u8]) -> Self {
114        Self { buffer }
115    }
116}
117
118impl<'a> HasRestLen for TypesIterMut<'a> {
119    fn rest_len(&self) -> usize {
120        self.buffer.len()
121    }
122}
123
124impl<'a> Iterator for TypesIterMut<'a> {
125    type Item = TypeRecordMut<'a>;
126
127    fn next(&mut self) -> Option<TypeRecordMut<'a>> {
128        if self.buffer.is_empty() {
129            return None;
130        }
131
132        let mut parser = ParserMut::new(take(&mut self.buffer));
133
134        let record_len = parser.u16().ok()?;
135        if record_len < 2 {
136            // Type record has length that is too short to be valid
137            return None;
138        }
139
140        let type_kind = parser.u16().ok()?;
141
142        let Ok(record_data) = parser.bytes_mut(record_len as usize - 2) else {
143            // Type record is too short to be valid.
144            return None;
145        };
146
147        self.buffer = parser.into_rest();
148
149        Some(TypeRecordMut {
150            data: record_data,
151            kind: Leaf(type_kind),
152        })
153    }
154}
155
156/// Represents a record that was enumerated within a type record stream (the TPI or IPI).
157/// Allows mutable access.
158pub struct TypeRecordMut<'a> {
159    /// Indicates how to interpret the payload (the `data` field).
160    pub kind: Leaf,
161    /// Record data. This does NOT include `kind` and the record data length.
162    pub data: &'a mut [u8],
163}