use std::iter::FusedIterator;
use vmi_core::{Va, VmiError, VmiState, driver::VmiRead};
use crate::{
ArchAdapter, WindowsError, WindowsHive, WindowsHiveCellIndex, WindowsKeyValue, WindowsOs,
comps::hive::HCELL_INDEX_SIZE,
};
pub struct KeyValueIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
vmi: VmiState<'a, WindowsOs<Driver>>,
hive_va: Va,
list_va: Va,
count: u32,
position: u32,
}
impl<'a, Driver> KeyValueIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, hive_va: Va, list_va: Va, count: u32) -> Self {
Self {
vmi,
hive_va,
list_va,
count,
position: 0,
}
}
pub fn empty(vmi: VmiState<'a, WindowsOs<Driver>>, hive_va: Va) -> Self {
Self {
vmi,
hive_va,
list_va: Va(0),
count: 0,
position: 0,
}
}
fn walk_next(&mut self) -> Result<Option<WindowsKeyValue<'a, Driver>>, VmiError> {
if self.position >= self.count {
return Ok(None);
}
let entry_va = self.list_va + (self.position as u64) * HCELL_INDEX_SIZE;
self.position += 1;
let hcell = self.vmi.read_u32(entry_va)?;
let hive = WindowsHive::new(self.vmi, self.hive_va);
match hive.cell(WindowsHiveCellIndex::new(hcell))? {
Some(va) => Ok(Some(WindowsKeyValue::new(self.vmi, self.hive_va, va))),
None => Err(WindowsError::CorruptedStruct("CM_KEY_VALUE_LIST.List[]").into()),
}
}
}
impl<'a, Driver> Iterator for KeyValueIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
type Item = Result<WindowsKeyValue<'a, Driver>, VmiError>;
fn next(&mut self) -> Option<Self::Item> {
self.walk_next().transpose()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = (self.count - self.position) as usize;
(n, Some(n))
}
}
impl<Driver> FusedIterator for KeyValueIterator<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
}
impl<Driver> ExactSizeIterator for KeyValueIterator<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
}