use crate::errors::FileParseError;
use crate::field::{ByteOrder, Field};
pub struct VersionSymbol {
pub ndx: Field<u16>,
}
pub struct VersionSymbolTable {
pub entries: Vec<VersionSymbol>,
}
impl VersionSymbolTable {
pub fn parse(
buffer: &[u8],
offset: usize,
size: usize,
order: ByteOrder,
) -> Result<Self, FileParseError> {
let mut entries = Vec::with_capacity(size / 2);
let mut cursor = offset;
let end = offset
.checked_add(size)
.ok_or(FileParseError::BufferOverflow)?;
while cursor + 2 <= end {
entries.push(VersionSymbol {
ndx: Field::new(order.read_u16(buffer, cursor)?, cursor, 2),
});
cursor += 2;
}
Ok(Self { entries })
}
}
pub struct VersionNeed {
pub vn_version: Field<u16>,
pub vn_cnt: Field<u16>,
pub vn_file: Field<u32>,
pub vn_aux: Field<u32>,
pub vn_next: Field<u32>,
pub aux: Vec<VersionNeedAux>,
}
pub struct VersionNeedAux {
pub vna_hash: Field<u32>,
pub vna_flags: Field<u16>,
pub vna_other: Field<u16>,
pub vna_name: Field<u32>,
pub vna_next: Field<u32>,
}
pub struct VersionNeedTable {
pub entries: Vec<VersionNeed>,
}
impl VersionNeedTable {
pub fn parse(
buffer: &[u8],
offset: usize,
size: usize,
order: ByteOrder,
) -> Result<Self, FileParseError> {
let end = offset
.checked_add(size)
.ok_or(FileParseError::BufferOverflow)?;
let mut entries = Vec::new();
let mut base = offset;
while base + 16 <= end {
let vn_cnt = Field::new(order.read_u16(buffer, base + 2)?, base + 2, 2);
let vn_aux = Field::new(order.read_u32(buffer, base + 8)?, base + 8, 4);
let vn_next = Field::new(order.read_u32(buffer, base + 12)?, base + 12, 4);
let mut aux = Vec::with_capacity(vn_cnt.value as usize);
let mut aux_base = base + vn_aux.value as usize;
for _ in 0..vn_cnt.value {
if aux_base + 16 > end {
return Err(FileParseError::BufferOverflow);
}
let vna_next = Field::new(order.read_u32(buffer, aux_base + 12)?, aux_base + 12, 4);
aux.push(VersionNeedAux {
vna_hash: Field::new(order.read_u32(buffer, aux_base)?, aux_base, 4),
vna_flags: Field::new(order.read_u16(buffer, aux_base + 4)?, aux_base + 4, 2),
vna_other: Field::new(order.read_u16(buffer, aux_base + 6)?, aux_base + 6, 2),
vna_name: Field::new(order.read_u32(buffer, aux_base + 8)?, aux_base + 8, 4),
vna_next: vna_next.clone(),
});
if vna_next.value == 0 {
break;
}
aux_base += vna_next.value as usize;
}
entries.push(VersionNeed {
vn_version: Field::new(order.read_u16(buffer, base)?, base, 2),
vn_cnt,
vn_file: Field::new(order.read_u32(buffer, base + 4)?, base + 4, 4),
vn_aux,
vn_next: vn_next.clone(),
aux,
});
if vn_next.value == 0 {
break;
}
base += vn_next.value as usize;
}
Ok(Self { entries })
}
}
pub struct VersionDef {
pub vd_version: Field<u16>,
pub vd_flags: Field<u16>,
pub vd_ndx: Field<u16>,
pub vd_cnt: Field<u16>,
pub vd_hash: Field<u32>,
pub vd_aux: Field<u32>,
pub vd_next: Field<u32>,
}
pub struct VersionDefTable {
pub entries: Vec<VersionDef>,
}
impl VersionDefTable {
pub fn parse(
buffer: &[u8],
offset: usize,
size: usize,
order: ByteOrder,
) -> Result<Self, FileParseError> {
let end = offset
.checked_add(size)
.ok_or(FileParseError::BufferOverflow)?;
let mut entries = Vec::new();
let mut base = offset;
while base + 20 <= end {
let vd_next = Field::new(order.read_u32(buffer, base + 16)?, base + 16, 4);
entries.push(VersionDef {
vd_version: Field::new(order.read_u16(buffer, base)?, base, 2),
vd_flags: Field::new(order.read_u16(buffer, base + 2)?, base + 2, 2),
vd_ndx: Field::new(order.read_u16(buffer, base + 4)?, base + 4, 2),
vd_cnt: Field::new(order.read_u16(buffer, base + 6)?, base + 6, 2),
vd_hash: Field::new(order.read_u32(buffer, base + 8)?, base + 8, 4),
vd_aux: Field::new(order.read_u32(buffer, base + 12)?, base + 12, 4),
vd_next: vd_next.clone(),
});
if vd_next.value == 0 {
break;
}
base += vd_next.value as usize;
}
Ok(Self { entries })
}
}