ms_pdb/types/
iter.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Code for iterating through type streams

use super::Leaf;
use crate::parser::{Parser, ParserError, ParserMut};
use crate::utils::iter::{HasRestLen, IteratorWithRangesExt};
use std::mem::take;

/// Parses a type record stream and iterates `TypeRecord` values.
#[derive(Clone)]
pub struct TypesIter<'a> {
    buffer: &'a [u8],
}

impl<'a> TypesIter<'a> {
    /// Starts a new iterator.
    pub fn new(buffer: &'a [u8]) -> Self {
        Self { buffer }
    }
}

impl<'a> HasRestLen for TypesIter<'a> {
    fn rest_len(&self) -> usize {
        self.buffer.len()
    }
}

impl<'a> Iterator for TypesIter<'a> {
    type Item = TypeRecord<'a>;

    fn next(&mut self) -> Option<TypeRecord<'a>> {
        if self.buffer.is_empty() {
            return None;
        }

        let mut p = Parser::new(self.buffer);

        let record_len = p.u16().ok()?;
        if record_len < 2 {
            // Type record has length that is too short to be valid
            return None;
        }

        let type_kind = p.u16().ok()?;

        let Ok(record_data) = p.bytes(record_len as usize - 2) else {
            // Type record is too short to be valid.
            return None;
        };

        self.buffer = p.into_rest();

        Some(TypeRecord {
            data: record_data,
            kind: Leaf(type_kind),
        })
    }
}

/// Represents a record that was enumerated within a type record stream (the TPI or IPI).
#[derive(Clone)]
pub struct TypeRecord<'a> {
    /// Indicates how to interpret the payload (the `data` field).
    pub kind: Leaf,
    /// Record data. This does NOT include `kind` and the record data length.
    pub data: &'a [u8],
}

impl<'a> TypeRecord<'a> {
    /// Parses the payload of this type record.
    pub fn parse(&self) -> Result<crate::types::TypeData<'a>, ParserError> {
        crate::types::TypeData::parse(self.kind, &mut Parser::new(self.data))
    }
}

/// Builds a "starts" table that gives the starting location of each type record.
pub fn build_types_starts(num_records_expected: usize, type_records: &[u8]) -> Vec<u32> {
    let mut starts: Vec<u32> = Vec::with_capacity(num_records_expected + 1);
    let mut iter = TypesIter::new(type_records).with_ranges();

    // This loop pushes a byte offset (pos) for the start of every record, plus 1 additional
    // value at the end of the sequence.  This will correctly handle the case where the last
    // record has some undecodable garbage at the end.
    loop {
        let pos = iter.pos();
        starts.push(pos as u32);

        if iter.next().is_none() {
            break;
        }
    }

    starts.shrink_to_fit();
    starts
}

/// Parses a type record stream and iterates `TypeRecord` values.
pub struct TypesIterMut<'a> {
    buffer: &'a mut [u8],
}

impl<'a> TypesIterMut<'a> {
    /// Starts a new iterator.
    pub fn new(buffer: &'a mut [u8]) -> Self {
        Self { buffer }
    }
}

impl<'a> HasRestLen for TypesIterMut<'a> {
    fn rest_len(&self) -> usize {
        self.buffer.len()
    }
}

impl<'a> Iterator for TypesIterMut<'a> {
    type Item = TypeRecordMut<'a>;

    fn next(&mut self) -> Option<TypeRecordMut<'a>> {
        if self.buffer.is_empty() {
            return None;
        }

        let mut parser = ParserMut::new(take(&mut self.buffer));

        let record_len = parser.u16().ok()?;
        if record_len < 2 {
            // Type record has length that is too short to be valid
            return None;
        }

        let type_kind = parser.u16().ok()?;

        let Ok(record_data) = parser.bytes_mut(record_len as usize - 2) else {
            // Type record is too short to be valid.
            return None;
        };

        self.buffer = parser.into_rest();

        Some(TypeRecordMut {
            data: record_data,
            kind: Leaf(type_kind),
        })
    }
}

/// Represents a record that was enumerated within a type record stream (the TPI or IPI).
/// Allows mutable access.
pub struct TypeRecordMut<'a> {
    /// Indicates how to interpret the payload (the `data` field).
    pub kind: Leaf,
    /// Record data. This does NOT include `kind` and the record data length.
    pub data: &'a mut [u8],
}