use core::iter::FusedIterator;
use core::mem;
use core::ops::Range;
use nt_string::u16strle::U16StrLe;
use zerocopy::{FromBytes, LayoutVerified, LittleEndian, Unaligned, U32};
use crate::error::{NtApiSetError, Result};
#[allow(dead_code)]
#[derive(Debug, FromBytes, Unaligned)]
#[repr(packed)]
pub(crate) struct ApiSetValueEntryHeader {
flags: U32<LittleEndian>,
name_offset: U32<LittleEndian>,
name_length: U32<LittleEndian>,
value_offset: U32<LittleEndian>,
value_length: U32<LittleEndian>,
}
#[derive(Clone, Debug)]
pub struct ApiSetValueEntries<'a> {
section_bytes: &'a [u8],
range: Range<usize>,
}
impl<'a> ApiSetValueEntries<'a> {
pub(crate) const fn new(section_bytes: &'a [u8], range: Range<usize>) -> Self {
Self {
section_bytes,
range,
}
}
}
impl<'a> Iterator for ApiSetValueEntries<'a> {
type Item = ApiSetValueEntry<'a>;
fn next(&mut self) -> Option<Self::Item> {
let (entry_header, _) =
LayoutVerified::<_, ApiSetValueEntryHeader>::new_unaligned_from_prefix(
self.section_bytes.get(self.range.clone())?,
)?;
let entry = ApiSetValueEntry {
section_bytes: self.section_bytes,
position: self.range.start,
header: entry_header,
};
self.range.start += mem::size_of::<ApiSetValueEntryHeader>();
Some(entry)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.range.len() / mem::size_of::<ApiSetValueEntryHeader>();
(size, Some(size))
}
}
impl<'a> ExactSizeIterator for ApiSetValueEntries<'a> {}
impl<'a> FusedIterator for ApiSetValueEntries<'a> {}
#[derive(Debug)]
pub struct ApiSetValueEntry<'a> {
section_bytes: &'a [u8],
position: usize,
header: LayoutVerified<&'a [u8], ApiSetValueEntryHeader>,
}
impl<'a> ApiSetValueEntry<'a> {
pub fn flags(&self) -> u32 {
self.header.flags.get()
}
pub fn name(&self) -> Result<U16StrLe<'a>> {
let start = self.header.name_offset.get() as usize;
let length = self.header.name_length.get() as usize;
let end = start + length;
let range = start..end;
let bytes =
self.section_bytes
.get(range.clone())
.ok_or(NtApiSetError::EntryNameOutOfBounds {
name_range: range,
entry_offset: self.position,
actual: self.section_bytes.len(),
})?;
Ok(U16StrLe(bytes))
}
pub fn value(&self) -> Result<U16StrLe<'a>> {
let start = self.header.value_offset.get() as usize;
let length = self.header.value_length.get() as usize;
let end = start + length;
let range = start..end;
let bytes =
self.section_bytes
.get(range.clone())
.ok_or(NtApiSetError::EntryNameOutOfBounds {
name_range: range,
entry_offset: self.position,
actual: self.section_bytes.len(),
})?;
Ok(U16StrLe(bytes))
}
}