use crate::errors::FileParseError;
use crate::field::{ByteOrder, Field};
pub struct SysvHashTable {
pub nbucket: Field<u32>,
pub nchain: Field<u32>,
pub buckets: Vec<Field<u32>>,
pub chains: Vec<Field<u32>>,
}
impl SysvHashTable {
pub fn parse(buffer: &[u8], offset: usize, order: ByteOrder) -> Result<Self, FileParseError> {
let nbucket = Field::new(order.read_u32(buffer, offset)?, offset, 4);
let nchain = Field::new(order.read_u32(buffer, offset + 4)?, offset + 4, 4);
let mut cursor = offset + 8;
let mut buckets = Vec::with_capacity(nbucket.value as usize);
for _ in 0..nbucket.value {
buckets.push(Field::new(order.read_u32(buffer, cursor)?, cursor, 4));
cursor += 4;
}
let mut chains = Vec::with_capacity(nchain.value as usize);
for _ in 0..nchain.value {
chains.push(Field::new(order.read_u32(buffer, cursor)?, cursor, 4));
cursor += 4;
}
Ok(Self {
nbucket,
nchain,
buckets,
chains,
})
}
}
pub struct GnuHashTable {
pub nbuckets: Field<u32>,
pub symoffset: Field<u32>,
pub bloom_size: Field<u32>,
pub bloom_shift: Field<u32>,
pub bloom: Vec<Field<u64>>,
pub buckets: Vec<Field<u32>>,
pub chains: Vec<Field<u32>>,
}
impl GnuHashTable {
pub fn parse(
buffer: &[u8],
offset: usize,
size: usize,
word_size: usize,
order: ByteOrder,
) -> Result<Self, FileParseError> {
if word_size != 4 && word_size != 8 {
return Err(FileParseError::InvalidFileFormat);
}
let end = offset
.checked_add(size)
.ok_or(FileParseError::BufferOverflow)?;
let nbuckets = Field::new(order.read_u32(buffer, offset)?, offset, 4);
let symoffset = Field::new(order.read_u32(buffer, offset + 4)?, offset + 4, 4);
let bloom_size = Field::new(order.read_u32(buffer, offset + 8)?, offset + 8, 4);
let bloom_shift = Field::new(order.read_u32(buffer, offset + 12)?, offset + 12, 4);
let mut cursor = offset + 16;
let mut bloom = Vec::with_capacity(bloom_size.value as usize);
for _ in 0..bloom_size.value {
let value = if word_size == 4 {
order.read_u32(buffer, cursor)? as u64
} else {
order.read_u64(buffer, cursor)?
};
bloom.push(Field::new(value, cursor, word_size));
cursor += word_size;
}
let mut buckets = Vec::with_capacity(nbuckets.value as usize);
for _ in 0..nbuckets.value {
buckets.push(Field::new(order.read_u32(buffer, cursor)?, cursor, 4));
cursor += 4;
}
let mut chains = Vec::new();
while cursor + 4 <= end {
chains.push(Field::new(order.read_u32(buffer, cursor)?, cursor, 4));
cursor += 4;
}
Ok(Self {
nbuckets,
symoffset,
bloom_size,
bloom_shift,
bloom,
buckets,
chains,
})
}
}