use std::convert::TryInto;
use std::mem;
use uuid::Uuid;
use crate::common::*;
use crate::dbi::HeaderVersion;
use crate::msf::*;
#[derive(Debug)]
pub struct PDBInformation<'s> {
pub version: HeaderVersion,
pub signature: u32,
pub age: u32,
pub guid: Uuid,
pub names_offset: usize,
pub names_size: usize,
stream: Stream<'s>,
}
impl<'s> PDBInformation<'s> {
pub(crate) fn parse(stream: Stream<'s>) -> Result<Self> {
let (version, signature, age, guid, names_size, names_offset) = {
let mut buf = stream.parse_buffer();
let version = From::from(buf.parse_u32()?);
let signature = buf.parse_u32()?;
let age = buf.parse_u32()?;
let guid = Uuid::from_fields(
buf.parse_u32()?,
buf.parse_u16()?,
buf.parse_u16()?,
buf.take(8)?.try_into().unwrap(),
);
let names_size = buf.parse_u32()? as usize;
let names_offset = buf.pos();
(version, signature, age, guid, names_size, names_offset)
};
Ok(PDBInformation {
version,
signature,
age,
guid,
names_size,
names_offset,
stream,
})
}
pub fn stream_names(&self) -> Result<StreamNames<'_>> {
let mut names = vec![];
let mut buf = self.stream.parse_buffer();
buf.take(self.names_offset + self.names_size)?;
let count = buf.parse_u32()?;
let _entries_size = buf.parse_u32()?;
let ok_words = buf.parse_u32()?;
let _ok_bits = buf.take(ok_words as usize * mem::size_of::<u32>())?;
let deleted_words = buf.parse_u32()?;
let _deleted_bits = buf.take(deleted_words as usize * mem::size_of::<u32>())?;
let mut names_reader = self.stream.parse_buffer();
names_reader.take(self.names_offset)?;
let names_buf = names_reader.take(self.names_size)?;
for _ in 0..count {
let name_offset = buf.parse_u32()? as usize;
let stream_id = StreamIndex(buf.parse_u32()? as u16);
let name = ParseBuffer::from(&names_buf[name_offset..]).parse_cstring()?;
names.push(StreamName { name, stream_id });
}
Ok(StreamNames { names })
}
}
#[derive(Debug)]
pub struct StreamName<'n> {
pub name: RawString<'n>,
pub stream_id: StreamIndex,
}
#[derive(Debug)]
pub struct StreamNames<'s> {
names: Vec<StreamName<'s>>,
}
pub type NameIter<'a, 'n> = std::slice::Iter<'a, StreamName<'n>>;
impl<'s> StreamNames<'s> {
#[inline]
pub fn iter(&self) -> NameIter<'_, 's> {
self.names.iter()
}
}
impl<'a, 's> IntoIterator for &'a StreamNames<'s> {
type Item = &'a StreamName<'s>;
type IntoIter = NameIter<'a, 's>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.names.iter()
}
}