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],
}