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