1use std::io::Cursor;
4
5use winreg_format::cells::{CellOffset, RawKeyValue};
6use winreg_format::flags::ValueType;
7
8use crate::error::Result;
9use crate::hive::Hive;
10
11const BIG_DATA_THRESHOLD: usize = 16344;
14const BIG_DATA_SEGMENT_SIZE: usize = 16344;
16
17pub struct Value<'h> {
19 pub(crate) hive: &'h Hive<Cursor<Vec<u8>>>,
20 pub(crate) vk: RawKeyValue,
21 pub(crate) offset: CellOffset,
22}
23
24impl Value<'_> {
25 pub fn name(&self) -> String {
27 self.vk.value_name()
28 }
29
30 pub fn data_type(&self) -> ValueType {
32 self.vk.data_type
33 }
34
35 pub fn data_size(&self) -> u32 {
37 self.vk.data_size()
38 }
39
40 pub fn is_resident(&self) -> bool {
42 self.vk.is_resident()
43 }
44
45 pub fn offset(&self) -> CellOffset {
47 self.offset
48 }
49
50 pub fn raw_data(&self) -> Result<Vec<u8>> {
52 let size = self.vk.data_size() as usize;
53 if size == 0 {
54 return Ok(Vec::new());
55 }
56
57 if self.vk.is_resident() {
58 return Ok(self.vk.inline_data());
59 }
60
61 let data_offset = self.vk.data_offset();
62
63 if size > BIG_DATA_THRESHOLD {
67 return self.read_big_data(data_offset, size);
68 }
69
70 let (_header, body) = self.hive.read_cell_raw(data_offset)?;
72 Ok(body[..size.min(body.len())].to_vec())
73 }
74
75 fn read_big_data(&self, db_offset: CellOffset, size: usize) -> Result<Vec<u8>> {
77 let (_h, db_body) = self.hive.read_cell_raw(db_offset)?;
78 if db_body.len() < 8 || &db_body[0..2] != b"db" {
80 return Ok(db_body[..size.min(db_body.len())].to_vec());
82 }
83 let segment_count = u16::from_le_bytes([db_body[2], db_body[3]]) as usize;
84 let list_offset = CellOffset(u32::from_le_bytes([
85 db_body[4], db_body[5], db_body[6], db_body[7],
86 ]));
87 let (_h2, list_body) = self.hive.read_cell_raw(list_offset)?;
88
89 let mut out = Vec::with_capacity(size);
90 for i in 0..segment_count {
91 if out.len() >= size {
92 break;
93 }
94 let pos = i * 4;
95 let Some(off_bytes) = list_body.get(pos..pos + 4) else {
96 break;
97 };
98 let seg_off = CellOffset(u32::from_le_bytes([
99 off_bytes[0], off_bytes[1], off_bytes[2], off_bytes[3],
100 ]));
101 let Ok((_h3, seg_body)) = self.hive.read_cell_raw(seg_off) else {
102 break;
103 };
104 let take = (size - out.len()).min(BIG_DATA_SEGMENT_SIZE).min(seg_body.len());
107 out.extend_from_slice(&seg_body[..take]);
108 }
109 Ok(out)
110 }
111
112 pub fn as_string(&self) -> Result<String> {
114 let data = self.raw_data()?;
115 Ok(decode_utf16le(&data))
116 }
117
118 pub fn as_u32(&self) -> Result<u32> {
120 let data = self.raw_data()?;
121 if data.len() < 4 {
122 return Ok(0);
123 }
124 Ok(u32::from_le_bytes([data[0], data[1], data[2], data[3]]))
125 }
126
127 pub fn as_u32_be(&self) -> Result<u32> {
129 let data = self.raw_data()?;
130 if data.len() < 4 {
131 return Ok(0);
132 }
133 Ok(u32::from_be_bytes([data[0], data[1], data[2], data[3]]))
134 }
135
136 pub fn as_u64(&self) -> Result<u64> {
138 let data = self.raw_data()?;
139 if data.len() < 8 {
140 return Ok(0);
141 }
142 Ok(crate::bytes::le_u64(&data, 0))
143 }
144
145 pub fn as_multi_string(&self) -> Result<Vec<String>> {
147 let data = self.raw_data()?;
148 Ok(decode_multi_sz(&data))
149 }
150}
151
152pub fn decode_utf16le(data: &[u8]) -> String {
154 let u16s: Vec<u16> = data
155 .chunks_exact(2)
156 .map(|c| u16::from_le_bytes([c[0], c[1]]))
157 .collect();
158 let trimmed: &[u16] = match u16s.iter().position(|&c| c == 0) {
159 Some(pos) => &u16s[..pos],
160 None => &u16s,
161 };
162 String::from_utf16_lossy(trimmed)
163}
164
165pub fn decode_multi_sz(data: &[u8]) -> Vec<String> {
168 let u16s: Vec<u16> = data
169 .chunks_exact(2)
170 .map(|c| u16::from_le_bytes([c[0], c[1]]))
171 .collect();
172
173 let mut strings = Vec::new();
174 let mut start = 0;
175
176 for (i, &ch) in u16s.iter().enumerate() {
177 if ch == 0 {
178 if i == start {
179 break;
180 }
181 strings.push(String::from_utf16_lossy(&u16s[start..i]));
182 start = i + 1;
183 }
184 }
185
186 if start < u16s.len() {
187 let remaining: Vec<u16> = u16s[start..]
188 .iter()
189 .copied()
190 .take_while(|&c| c != 0)
191 .collect();
192 if !remaining.is_empty() {
193 strings.push(String::from_utf16_lossy(&remaining));
194 }
195 }
196
197 strings
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn decode_utf16le_normal() {
206 let data = b"H\x00e\x00l\x00l\x00o\x00\x00\x00";
207 assert_eq!(decode_utf16le(data), "Hello");
208 }
209
210 #[test]
211 fn decode_utf16le_no_null() {
212 let data = b"H\x00i\x00";
213 assert_eq!(decode_utf16le(data), "Hi");
214 }
215
216 #[test]
217 fn decode_utf16le_empty() {
218 assert_eq!(decode_utf16le(b""), "");
219 }
220
221 #[test]
222 fn decode_multi_sz_normal() {
223 let data = b"f\x00o\x00o\x00\x00\x00b\x00a\x00r\x00\x00\x00\x00\x00";
224 let result = decode_multi_sz(data);
225 assert_eq!(result, vec!["foo", "bar"]);
226 }
227
228 #[test]
229 fn decode_multi_sz_single() {
230 let data = b"o\x00n\x00e\x00\x00\x00\x00\x00";
231 let result = decode_multi_sz(data);
232 assert_eq!(result, vec!["one"]);
233 }
234
235 #[test]
236 fn decode_multi_sz_empty() {
237 let data = b"\x00\x00";
238 let result = decode_multi_sz(data);
239 assert!(result.is_empty());
240 }
241
242 #[test]
243 fn decode_multi_sz_missing_terminator() {
244 let data = b"a\x00b\x00c\x00\x00\x00d\x00e\x00f\x00";
245 let result = decode_multi_sz(data);
246 assert_eq!(result, vec!["abc", "def"]);
247 }
248}