nt_hive/
key_values_list.rs

1// Copyright 2020-2025 Colin Finck <colin@reactos.org>
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4use core::iter::FusedIterator;
5use core::mem;
6use core::ops::{Deref, Range};
7
8use zerocopy::byteorder::LittleEndian;
9use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned, U32};
10
11use crate::error::{NtHiveError, Result};
12use crate::helpers::byte_subrange;
13use crate::hive::Hive;
14use crate::key_value::KeyValue;
15
16/// On-Disk Structure of a Key Values List item.
17#[allow(dead_code)]
18#[derive(FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned)]
19#[repr(packed)]
20struct KeyValuesListItem {
21    key_value_offset: U32<LittleEndian>,
22}
23
24/// Byte range of a single Key Values list item returned by [`KeyValuesListItemRanges`].
25struct KeyValuesListItemRange(Range<usize>);
26
27impl KeyValuesListItemRange {
28    fn key_value_offset<B>(&self, hive: &Hive<B>) -> u32
29    where
30        B: SplitByteSlice,
31    {
32        let item = Ref::<&[u8], KeyValuesListItem>::from_bytes(&hive.data[self.0.clone()]).unwrap();
33        item.key_value_offset.get()
34    }
35}
36
37impl Deref for KeyValuesListItemRange {
38    type Target = Range<usize>;
39
40    fn deref(&self) -> &Self::Target {
41        &self.0
42    }
43}
44
45/// Iterator over
46///   a contiguous range of data bytes containing Key Value items,
47///   returning a [`KeyValuesListItemRange`] for each item.
48///
49/// On-Disk Signature: `vk`
50#[derive(Clone)]
51struct KeyValuesListItemRanges {
52    items_range: Range<usize>,
53}
54
55impl KeyValuesListItemRanges {
56    pub(crate) fn new(
57        count: u32,
58        count_field_offset: usize,
59        cell_range: Range<usize>,
60    ) -> Result<Self> {
61        let byte_count = count as usize * mem::size_of::<KeyValuesListItem>();
62
63        let items_range = byte_subrange(&cell_range, byte_count).ok_or_else(|| {
64            NtHiveError::InvalidSizeField {
65                offset: count_field_offset,
66                expected: byte_count,
67                actual: cell_range.len(),
68            }
69        })?;
70
71        Ok(Self { items_range })
72    }
73}
74
75impl Iterator for KeyValuesListItemRanges {
76    type Item = KeyValuesListItemRange;
77
78    fn next(&mut self) -> Option<Self::Item> {
79        let item_range = byte_subrange(&self.items_range, mem::size_of::<KeyValuesListItem>())?;
80        self.items_range.start += mem::size_of::<KeyValuesListItem>();
81
82        Some(KeyValuesListItemRange(item_range))
83    }
84
85    fn count(self) -> usize {
86        let (size, _) = self.size_hint();
87        size
88    }
89
90    fn last(mut self) -> Option<Self::Item> {
91        let (size, _) = self.size_hint();
92        if size == 0 {
93            return None;
94        }
95
96        self.nth(size - 1)
97    }
98
99    fn nth(&mut self, n: usize) -> Option<Self::Item> {
100        // `n` is arbitrary and usize, so we may hit boundaries here. Check that!
101        let bytes_to_skip = n.checked_mul(mem::size_of::<KeyValuesListItem>())?;
102        self.items_range.start = self.items_range.start.checked_add(bytes_to_skip)?;
103        self.next()
104    }
105
106    fn size_hint(&self) -> (usize, Option<usize>) {
107        let size = self.items_range.len() / mem::size_of::<KeyValuesListItem>();
108        (size, Some(size))
109    }
110}
111
112impl ExactSizeIterator for KeyValuesListItemRanges {}
113impl FusedIterator for KeyValuesListItemRanges {}
114
115/// Iterator over
116///   a contiguous range of data bytes containing Key Value items,
117///   returning a constant [`KeyValue`] for each item.
118///
119/// On-Disk Signature: `vk`
120#[derive(Clone)]
121pub struct KeyValues<'h, B: SplitByteSlice> {
122    hive: &'h Hive<B>,
123    key_values_list_item_ranges: KeyValuesListItemRanges,
124}
125
126impl<'h, B> KeyValues<'h, B>
127where
128    B: SplitByteSlice,
129{
130    pub(crate) fn new(
131        hive: &'h Hive<B>,
132        count: u32,
133        count_field_offset: usize,
134        cell_range: Range<usize>,
135    ) -> Result<Self> {
136        let key_values_list_item_ranges =
137            KeyValuesListItemRanges::new(count, count_field_offset, cell_range)?;
138
139        Ok(Self {
140            hive,
141            key_values_list_item_ranges,
142        })
143    }
144}
145
146impl<'h, B> Iterator for KeyValues<'h, B>
147where
148    B: SplitByteSlice,
149{
150    type Item = Result<KeyValue<'h, B>>;
151
152    fn next(&mut self) -> Option<Self::Item> {
153        let key_values_list_item_range = self.key_values_list_item_ranges.next()?;
154        let key_value_offset = key_values_list_item_range.key_value_offset(self.hive);
155        let cell_range = iter_try!(self.hive.cell_range_from_data_offset(key_value_offset));
156        let key_value = iter_try!(KeyValue::new(self.hive, cell_range));
157        Some(Ok(key_value))
158    }
159
160    fn count(self) -> usize {
161        self.key_values_list_item_ranges.count()
162    }
163
164    fn last(mut self) -> Option<Self::Item> {
165        let (size, _) = self.size_hint();
166        if size == 0 {
167            return None;
168        }
169
170        self.nth(size - 1)
171    }
172
173    fn nth(&mut self, n: usize) -> Option<Self::Item> {
174        // `n` is arbitrary and usize, so we may hit boundaries here. Check that!
175        let bytes_to_skip = n.checked_mul(mem::size_of::<KeyValuesListItem>())?;
176        self.key_values_list_item_ranges.items_range.start = self
177            .key_values_list_item_ranges
178            .items_range
179            .start
180            .checked_add(bytes_to_skip)?;
181        self.next()
182    }
183
184    fn size_hint(&self) -> (usize, Option<usize>) {
185        self.key_values_list_item_ranges.size_hint()
186    }
187}
188
189impl<B> ExactSizeIterator for KeyValues<'_, B> where B: SplitByteSlice {}
190impl<B> FusedIterator for KeyValues<'_, B> where B: SplitByteSlice {}