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