1pub mod hash;
40
41use super::*;
42use crate::parser::Parser;
43use crate::types::fields::{Field, IterFields};
44use crate::types::{build_types_starts, TypeData, TypeIndex, TypeIndexLe, TypeRecord, TypesIter};
45use anyhow::bail;
46use std::fmt::Debug;
47use std::mem::size_of;
48use std::ops::Range;
49use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned, I32, LE, U32};
50
51#[allow(missing_docs)]
53#[derive(Clone, Eq, PartialEq, IntoBytes, FromBytes, KnownLayout, Immutable, Unaligned, Debug)]
54#[repr(C)]
55pub struct TypeStreamHeader {
56 pub version: U32<LE>,
57 pub header_size: U32<LE>,
58 pub type_index_begin: TypeIndexLe,
59 pub type_index_end: TypeIndexLe,
60 pub type_record_bytes: U32<LE>,
62
63 pub hash_stream_index: StreamIndexU16,
64 pub hash_aux_stream_index: StreamIndexU16,
65
66 pub hash_key_size: U32<LE>,
69 pub num_hash_buckets: U32<LE>,
75 pub hash_value_buffer_offset: I32<LE>,
76 pub hash_value_buffer_length: U32<LE>,
77
78 pub index_offset_buffer_offset: I32<LE>,
79 pub index_offset_buffer_length: U32<LE>,
80
81 pub hash_adj_buffer_offset: I32<LE>,
82 pub hash_adj_buffer_length: U32<LE>,
83}
84
85impl TypeStreamHeader {
86 pub fn empty() -> Self {
88 Self {
89 version: Default::default(),
90 header_size: U32::new(size_of::<TypeStreamHeader>() as u32),
91 type_index_begin: TypeIndexLe(U32::new(TypeIndex::MIN_BEGIN.0)),
92 type_index_end: TypeIndexLe(U32::new(TypeIndex::MIN_BEGIN.0)),
93 type_record_bytes: Default::default(),
94 hash_stream_index: StreamIndexU16::NIL,
95 hash_aux_stream_index: StreamIndexU16::NIL,
96 hash_key_size: Default::default(),
97 num_hash_buckets: Default::default(),
98 hash_value_buffer_offset: Default::default(),
99 hash_value_buffer_length: Default::default(),
100 index_offset_buffer_offset: Default::default(),
101 index_offset_buffer_length: Default::default(),
102 hash_adj_buffer_offset: Default::default(),
103 hash_adj_buffer_length: Default::default(),
104 }
105 }
106}
107
108pub const TPI_STREAM_HEADER_LEN: usize = size_of::<TypeStreamHeader>();
110
111pub const TYPE_STREAM_VERSION_2004: u32 = 20040203;
113
114pub struct TypeStream<StreamData>
116where
117 StreamData: AsRef<[u8]>,
118{
119 pub stream_data: StreamData,
121
122 type_index_begin: TypeIndex,
123 type_index_end: TypeIndex,
124
125 record_starts: OnceCell<Vec<u32>>,
128}
129
130#[derive(Copy, Clone, Eq, PartialEq, Debug)]
132pub enum TypeStreamKind {
133 TPI,
135 IPI,
137}
138
139impl TypeStreamKind {
140 pub fn stream(self) -> Stream {
142 match self {
143 Self::IPI => Stream::IPI,
144 Self::TPI => Stream::TPI,
145 }
146 }
147}
148
149#[repr(C)]
151#[derive(IntoBytes, FromBytes, KnownLayout, Immutable, Unaligned, Debug)]
152pub struct HashIndexPair {
153 pub type_index: TypeIndexLe,
155 pub offset: U32<LE>,
158}
159
160impl<StreamData> TypeStream<StreamData>
161where
162 StreamData: AsRef<[u8]>,
163{
164 pub fn header(&self) -> Option<&TypeStreamHeader> {
166 let stream_data: &[u8] = self.stream_data.as_ref();
167 let (header, _) = TypeStreamHeader::ref_from_prefix(stream_data).ok()?;
168 Some(header)
169 }
170
171 pub fn version(&self) -> u32 {
173 if let Some(header) = self.header() {
174 header.version.get()
175 } else {
176 TYPE_STREAM_VERSION_2004
177 }
178 }
179
180 pub fn hash_stream(&self) -> Option<u32> {
182 self.header()?.hash_stream_index.get()
183 }
184
185 pub fn is_empty(&self) -> bool {
187 self.stream_data.as_ref().is_empty()
188 }
189
190 pub fn header_mut(&mut self) -> Option<&mut TypeStreamHeader>
192 where
193 StreamData: AsMut<[u8]>,
194 {
195 let (header, _) = TypeStreamHeader::mut_from_prefix(self.stream_data.as_mut()).ok()?;
196 Some(header)
197 }
198
199 pub fn type_index_begin(&self) -> TypeIndex {
201 self.type_index_begin
202 }
203
204 pub fn type_index_end(&self) -> TypeIndex {
206 self.type_index_end
207 }
208
209 pub fn num_types(&self) -> u32 {
211 self.type_index_end.0 - self.type_index_begin.0
212 }
213
214 pub fn records_offset(&self) -> usize {
216 if let Some(header) = self.header() {
217 header.header_size.get() as usize
218 } else {
219 0
220 }
221 }
222
223 pub fn type_records_bytes(&self) -> &[u8] {
229 let records_range = self.type_records_range();
230 if records_range.is_empty() {
231 &[]
232 } else {
233 &self.stream_data.as_ref()[records_range]
234 }
235 }
236
237 pub fn type_records_bytes_mut(&mut self) -> &mut [u8]
239 where
240 StreamData: AsMut<[u8]>,
241 {
242 let records_range = self.type_records_range();
243 if records_range.is_empty() {
244 &mut []
245 } else {
246 &mut self.stream_data.as_mut()[records_range]
247 }
248 }
249
250 pub fn type_records_range(&self) -> std::ops::Range<usize> {
252 if let Some(header) = self.header() {
253 let size = header.type_record_bytes.get();
254 if size == 0 {
255 return 0..0;
256 }
257 let type_records_start = header.header_size.get();
258 let type_records_end = type_records_start + size;
259 type_records_start as usize..type_records_end as usize
260 } else {
261 0..0
262 }
263 }
264
265 pub fn iter_type_records(&self) -> TypesIter<'_> {
267 TypesIter::new(self.type_records_bytes())
268 }
269
270 pub fn parse(stream_index: Stream, stream_data: StreamData) -> anyhow::Result<Self> {
272 let stream_bytes: &[u8] = stream_data.as_ref();
273
274 if stream_bytes.is_empty() {
275 return Ok(Self {
276 stream_data,
277 type_index_begin: TypeIndex::MIN_BEGIN,
278 type_index_end: TypeIndex::MIN_BEGIN,
279 record_starts: OnceCell::new(),
280 });
281 }
282
283 let mut p = Parser::new(stream_bytes);
284 let tpi_stream_header: TypeStreamHeader = p.copy()?;
285
286 let type_index_begin = tpi_stream_header.type_index_begin.get();
287 let type_index_end = tpi_stream_header.type_index_end.get();
288 if type_index_end < type_index_begin {
289 bail!(
290 "Type stream (stream {stream_index}) has invalid values in header. \
291 The type_index_begin field is greater than the type_index_end field."
292 );
293 }
294
295 if type_index_begin < TypeIndex::MIN_BEGIN {
296 bail!(
297 "The Type Stream has an invalid value for type_index_begin ({type_index_begin:?}). \
298 It is less than the minimum required value ({}).",
299 TypeIndex::MIN_BEGIN.0
300 );
301 }
302
303 let type_data_start = tpi_stream_header.header_size.get();
304 if type_data_start < TPI_STREAM_HEADER_LEN as u32 {
305 bail!(
306 "Type stream (stream {stream_index}) has invalid values in header. \
307 The header_size field is smaller than the definition of the actual header."
308 );
309 }
310
311 let type_data_end = type_data_start + tpi_stream_header.type_record_bytes.get();
312 if type_data_end > stream_bytes.len() as u32 {
313 bail!(
314 "Type stream (stream {stream_index}) has invalid values in header. \
315 The header_size and type_record_bytes fields exceed the size of the stream."
316 );
317 }
318
319 Ok(TypeStream {
320 stream_data,
321 type_index_begin,
322 type_index_end,
323 record_starts: OnceCell::new(),
324 })
325 }
326
327 pub fn build_types_starts(&self) -> TypeIndexMap {
329 let starts =
330 crate::types::build_types_starts(self.num_types() as usize, self.type_records_bytes());
331
332 TypeIndexMap {
333 type_index_begin: self.type_index_begin,
334 type_index_end: self.type_index_end,
335 starts,
336 }
337 }
338
339 pub fn to_ref(&self) -> TypeStream<&[u8]> {
343 TypeStream {
344 stream_data: self.stream_data.as_ref(),
345 type_index_begin: self.type_index_begin,
346 type_index_end: self.type_index_end,
347 record_starts: OnceCell::new(),
348 }
349 }
350
351 pub fn record_starts(&self) -> &[u32] {
355 self.record_starts.get_or_init(|| {
356 let type_records = self.type_records_bytes();
357 build_types_starts(self.num_types() as usize, type_records)
358 })
359 }
360
361 pub fn is_primitive(&self, type_index: TypeIndex) -> bool {
363 type_index < self.type_index_begin
364 }
365
366 pub fn record(&self, type_index: TypeIndex) -> anyhow::Result<TypeRecord<'_>> {
371 let Some(relative_type_index) = type_index.0.checked_sub(self.type_index_begin.0) else {
372 bail!("The given TypeIndex is a primitive type index, not a type record.");
373 };
374
375 let starts = self.record_starts();
376 let Some(&record_start) = starts.get(relative_type_index as usize) else {
377 bail!("The given TypeIndex is out of bounds (exceeds maximum allowed TypeIndex)");
378 };
379
380 let all_type_records = self.type_records_bytes();
381 let Some(this_type_record_slice) = all_type_records.get(record_start as usize..) else {
382 bail!("Internal error: record offset is out of range.");
384 };
385
386 let mut iter = TypesIter::new(this_type_record_slice);
387 if let Some(record) = iter.next() {
388 Ok(record)
389 } else {
390 bail!("Failed to decode type record");
391 }
392 }
393
394 pub fn iter_fields(&self, field_list: TypeIndex) -> IterFieldChain<'_, StreamData> {
397 IterFieldChain {
400 type_stream: self,
401 next_field_list: if field_list.0 != 0 {
402 Some(field_list)
403 } else {
404 None
405 },
406 fields: IterFields { bytes: &[] },
407 }
408 }
409}
410
411pub struct IterFieldChain<'a, StreamData>
413where
414 StreamData: AsRef<[u8]>,
415{
416 fields: IterFields<'a>,
418
419 type_stream: &'a TypeStream<StreamData>,
421
422 next_field_list: Option<TypeIndex>,
424}
425
426impl<'a, StreamData> Iterator for IterFieldChain<'a, StreamData>
427where
428 StreamData: AsRef<[u8]>,
429{
430 type Item = Field<'a>;
431
432 fn next(&mut self) -> Option<Self::Item> {
433 loop {
434 if let Some(field) = self.fields.next() {
435 if let Field::Index(index) = &field {
436 self.next_field_list = Some(*index);
439 continue;
440 }
441
442 return Some(field);
443 }
444
445 let next_field_list = self.next_field_list.take()?;
448 let next_record = self.type_stream.record(next_field_list).ok()?;
449 match next_record.parse().ok()? {
450 TypeData::FieldList(fl) => {
451 self.fields = fl.iter();
453 }
454 _ => {
455 return None;
457 }
458 }
459 }
460 }
461}
462
463impl<F: ReadAt> crate::Pdb<F> {
464 pub fn read_type_stream(&self) -> anyhow::Result<TypeStream<Vec<u8>>> {
466 self.read_tpi_or_ipi_stream(Stream::TPI)
467 }
468
469 pub fn read_ipi_stream(&self) -> anyhow::Result<TypeStream<Vec<u8>>> {
471 self.read_tpi_or_ipi_stream(Stream::IPI)
472 }
473
474 pub fn read_tpi_or_ipi_stream(
476 &self,
477 stream_index: Stream,
478 ) -> anyhow::Result<TypeStream<Vec<u8>>> {
479 let stream_data = self.read_stream_to_vec(stream_index.into())?;
480 TypeStream::parse(stream_index, stream_data)
481 }
482}
483
484pub struct TypeIndexMap {
486 pub type_index_begin: TypeIndex,
488
489 pub type_index_end: TypeIndex,
491
492 pub starts: Vec<u32>,
497}
498
499impl TypeIndexMap {
500 pub fn is_primitive(&self, ti: TypeIndex) -> bool {
502 ti < self.type_index_begin
503 }
504
505 pub fn record_range(&self, ti: TypeIndex) -> anyhow::Result<Range<usize>> {
511 let Some(i) = ti.0.checked_sub(self.type_index_begin.0) else {
512 bail!("The TypeIndex is a primitive type, not a type record.");
513 };
514
515 if let Some(w) = self.starts.get(i as usize..i as usize + 2) {
516 Ok(w[0] as usize..w[1] as usize)
517 } else {
518 bail!("The TypeIndex is out of range.");
519 }
520 }
521}
522
523pub struct CachedTypeStreamHeader {
525 pub(crate) header: Option<TypeStreamHeader>,
526}
527
528impl CachedTypeStreamHeader {
529 pub fn header(&self) -> Option<&TypeStreamHeader> {
531 self.header.as_ref()
532 }
533
534 pub fn type_index_begin(&self) -> TypeIndex {
537 if let Some(h) = &self.header {
538 h.type_index_begin.get()
539 } else {
540 TypeIndex::MIN_BEGIN
541 }
542 }
543
544 pub fn type_index_end(&self) -> TypeIndex {
547 if let Some(h) = &self.header {
548 h.type_index_end.get()
549 } else {
550 TypeIndex::MIN_BEGIN
551 }
552 }
553}