use core::iter::FusedIterator;
use core::mem;
use core::ops::Range;
use zerocopy::byteorder::LittleEndian;
use zerocopy::{
FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut,
Unaligned, U16,
};
use crate::error::{NtHiveError, Result};
use crate::helpers::byte_subrange;
use crate::hive::Hive;
use crate::index_root::{IndexRootKeyNodes, IndexRootKeyNodesMut};
use crate::key_node::{KeyNode, KeyNodeMut};
use crate::leaf::{LeafKeyNodes, LeafKeyNodesMut, LeafType};
#[derive(FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned)]
#[repr(packed)]
pub(crate) struct SubkeysListHeader {
pub(crate) signature: [u8; 2],
pub(crate) count: U16<LittleEndian>,
}
pub(crate) struct SubkeysList<'h, B: SplitByteSlice> {
hive: &'h Hive<B>,
header_range: Range<usize>,
pub(crate) data_range: Range<usize>,
}
impl<'h, B> SubkeysList<'h, B>
where
B: SplitByteSlice,
{
pub(crate) fn new(hive: &'h Hive<B>, cell_range: Range<usize>) -> Result<Self> {
Self::new_internal(hive, cell_range, true)
}
pub(crate) fn new_without_index_root(
hive: &'h Hive<B>,
cell_range: Range<usize>,
) -> Result<Self> {
Self::new_internal(hive, cell_range, false)
}
fn new_internal(
hive: &'h Hive<B>,
cell_range: Range<usize>,
index_root_supported: bool,
) -> Result<Self> {
let header_range = byte_subrange(&cell_range, mem::size_of::<SubkeysListHeader>())
.ok_or_else(|| NtHiveError::InvalidHeaderSize {
offset: hive.offset_of_data_offset(cell_range.start),
expected: mem::size_of::<SubkeysListHeader>(),
actual: cell_range.len(),
})?;
let data_range = header_range.end..cell_range.end;
let subkeys_list = Self {
hive,
header_range,
data_range,
};
subkeys_list.validate_signature(index_root_supported)?;
Ok(subkeys_list)
}
pub(crate) fn header(&self) -> Ref<&[u8], SubkeysListHeader> {
Ref::from_bytes(&self.hive.data[self.header_range.clone()]).unwrap()
}
fn validate_signature(&self, index_root_supported: bool) -> Result<()> {
let header = self.header();
match &header.signature {
b"lf" | b"lh" | b"li" => return Ok(()),
b"ri" => {
if index_root_supported {
return Ok(());
}
}
_ => (),
}
let expected_signature: &[u8] = if index_root_supported {
b"lf|lh|li|ri"
} else {
b"lf|lh|li"
};
Err(NtHiveError::InvalidTwoByteSignature {
offset: self.hive.offset_of_field(&header.signature),
expected: expected_signature,
actual: header.signature,
})
}
}
#[derive(Clone)]
pub enum SubKeyNodes<'h, B: SplitByteSlice> {
IndexRoot(IndexRootKeyNodes<'h, B>),
Leaf(LeafKeyNodes<'h, B>),
}
impl<'h, B> SubKeyNodes<'h, B>
where
B: SplitByteSlice,
{
pub(crate) fn new(hive: &'h Hive<B>, cell_range: Range<usize>) -> Result<Self> {
let subkeys_list = SubkeysList::new(hive, cell_range)?;
let header = subkeys_list.header();
let signature = header.signature;
let count = header.count.get();
let count_field_offset = subkeys_list.hive.offset_of_field(&header.count);
let data_range = subkeys_list.data_range;
match &signature {
b"lf" | b"lh" | b"li" => {
let leaf_type = LeafType::from_signature(&signature).unwrap();
let iter =
LeafKeyNodes::new(hive, count, count_field_offset, data_range, leaf_type)?;
Ok(Self::Leaf(iter))
}
b"ri" => {
let iter = IndexRootKeyNodes::new(hive, count, count_field_offset, data_range)?;
Ok(Self::IndexRoot(iter))
}
_ => unreachable!(),
}
}
}
impl<'h, B> Iterator for SubKeyNodes<'h, B>
where
B: SplitByteSlice,
{
type Item = Result<KeyNode<'h, B>>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::IndexRoot(iter) => iter.next(),
Self::Leaf(iter) => iter.next(),
}
}
fn count(self) -> usize {
match self {
Self::IndexRoot(iter) => iter.count(),
Self::Leaf(iter) => iter.count(),
}
}
fn last(self) -> Option<Self::Item> {
match self {
Self::IndexRoot(iter) => iter.last(),
Self::Leaf(iter) => iter.last(),
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
match self {
Self::IndexRoot(iter) => iter.nth(n),
Self::Leaf(iter) => iter.nth(n),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::IndexRoot(iter) => iter.size_hint(),
Self::Leaf(iter) => iter.size_hint(),
}
}
}
impl<B> FusedIterator for SubKeyNodes<'_, B> where B: SplitByteSlice {}
pub(crate) enum SubKeyNodesMut<'h, B: SplitByteSliceMut> {
IndexRoot(IndexRootKeyNodesMut<'h, B>),
Leaf(LeafKeyNodesMut<'h, B>),
}
impl<'h, B> SubKeyNodesMut<'h, B>
where
B: SplitByteSliceMut,
{
pub(crate) fn new(hive: &'h mut Hive<B>, cell_range: Range<usize>) -> Result<Self> {
let subkeys_list = SubkeysList::new(&*hive, cell_range)?;
let header = subkeys_list.header();
let signature = header.signature;
let count = header.count.get();
let count_field_offset = subkeys_list.hive.offset_of_field(&header.count);
let data_range = subkeys_list.data_range;
match &signature {
b"lf" | b"lh" | b"li" => {
let leaf_type = LeafType::from_signature(&signature).unwrap();
let iter =
LeafKeyNodesMut::new(hive, count, count_field_offset, data_range, leaf_type)?;
Ok(Self::Leaf(iter))
}
b"ri" => {
let iter = IndexRootKeyNodesMut::new(hive, count, count_field_offset, data_range)?;
Ok(Self::IndexRoot(iter))
}
_ => unreachable!(),
}
}
pub fn next(&mut self) -> Option<Result<KeyNodeMut<B>>> {
match self {
Self::IndexRoot(iter) => iter.next(),
Self::Leaf(iter) => iter.next(),
}
}
}