1use forensic_rs::{err::ForensicError, prelude::ForensicResult};
2pub const INDEX_LEAF_SIGNATURE: &[u8; 2] = b"li";
3pub const FAST_LEAF_SIGNATURE: &[u8; 2] = b"lf";
4pub const HASH_LEAF_SIGNATURE: &[u8; 2] = b"lh";
5pub const INDEX_ROOT_SIGNATURE: &[u8; 2] = b"ri";
6pub const KEY_NODE_SIGNATURE: &[u8; 2] = b"nk";
7pub const KEY_SECURITY_SIGNATURE: &[u8; 2] = b"sk";
8pub const KEY_VALUE_SIGNATURE: &[u8; 2] = b"vk";
9
10pub const KEY_VOLATILE_FLAG: u16 = 0x0001;
12pub const KEY_HIVE_EXIT_FLAG: u16 = 0x0002;
14pub const KEY_HIVE_ENTRY_FLAG: u16 = 0x0004;
16pub const KEY_NO_DELETE_FLAG: u16 = 0x0008;
18pub const KEY_SYM_LINK_FLAG: u16 = 0x0010;
20pub const KEY_COMP_NAME_FLAG: u16 = 0x0020;
22pub const KEY_PREDEF_HANDLE_FLAG: u16 = 0x0040;
24
25pub const VALUE_COMP_NAME_FLAG: u16 = 0x0001;
27pub const VALUE_IS_TOMBSTONE: u16 = 0x0002;
29
30#[derive(Debug, Clone)]
31pub enum HiveCell {
32 IndexLeaf(IndexLeafCell),
33 FastLeaf(FastLeafCell),
34 HashLeaf(HashLeafCell),
35 IndexRoot(IndexRootCell),
36 KeyNode(KeyNodeCell),
37 KeyValue(KeyValueCell),
38 KeySecurity(KeySecurityCell),
39 BigData(BigDataCell),
40 Unallocated(UnallocatedCell),
41 Invalid(InvalidCell),
42}
43impl HiveCell {
44 pub fn offset(&self) -> u64 {
45 match self {
46 HiveCell::IndexLeaf(v) => v.offset,
47 HiveCell::FastLeaf(v) => v.offset,
48 HiveCell::HashLeaf(v) => v.offset,
49 HiveCell::IndexRoot(v) => v.offset,
50 HiveCell::KeyNode(v) => v.offset,
51 HiveCell::KeyValue(v) => v.offset,
52 HiveCell::KeySecurity(v) => v.offset,
53 HiveCell::BigData(v) => v.offset,
54 HiveCell::Unallocated(v) => v.offset,
55 HiveCell::Invalid(v) => v.offset,
56 }
57 }
58}
59#[derive(Debug, Clone)]
60pub struct UnallocatedCell {
61 pub offset: u64
62}
63
64#[derive(Debug, Clone)]
65pub struct InvalidCell {
66 pub offset: u64,
67 pub content: Vec<u8>,
68}
69
70#[derive(Debug, Clone)]
71pub struct IndexLeafCell {
72 pub elements: Vec<IndexLeafListElements>,
74 pub offset: u64,
75}
76#[derive(Debug, Clone)]
77pub struct IndexLeafListElements {
78 pub offset: u32,
80}
81#[derive(Debug, Clone)]
82pub struct FastLeafCell {
83 pub elements: Vec<FastLeafListElements>,
84 pub offset: u64,
85}
86#[derive(Debug, Clone)]
87pub struct FastLeafListElements {
88 pub offset: u32,
90 pub name_hint: String,
92}
93#[derive(Debug, Clone)]
94pub struct HashLeafCell {
95 pub elements: Vec<HashLeafListElements>,
96 pub offset: u64,
97}
98#[derive(Debug, Clone)]
99pub struct HashLeafListElements {
100 pub offset: u32,
102 pub name_hash: u32,
104}
105
106impl HashLeafCell {
107 pub fn hash_name(name: &str) -> u32 {
108 let mut h: u32 = 0;
109 if name.is_ascii() {
110 for &char in name.as_bytes() {
111 let char = Self::uppercase(char);
112 h = 37u32.wrapping_mul(h).wrapping_add(char);
113 }
114 } else {
115 for char in name.to_ascii_uppercase().encode_utf16() {
116 h = 37u32.wrapping_mul(h).wrapping_add(char as u32);
117 }
118 }
119 h
120 }
121
122 pub fn uppercase(v: u8) -> u32 {
123 if (b'a'..b'z').contains(&v) {
124 (b'A' + (v - b'a')) as u32
125 } else {
126 v as u32
127 }
128 }
129}
130
131#[derive(Debug, Clone)]
135pub struct IndexRootCell {
136 pub elements: Vec<IndexRootSubkeyOffset>,
137 pub offset: u64,
138}
139#[derive(Debug, Clone)]
140pub struct IndexRootSubkeyOffset {
141 pub subkeys_list_offset: u32,
143}
144
145#[derive(Debug, Clone)]
146pub struct KeyNodeCell {
147 pub flags: u16,
149 pub last_written_timestamp: u64,
151 pub access_bits: u32,
153 pub parent: u32,
155 pub number_subkeys: u32,
157 pub number_volatile_subkeys: u32,
159 pub subkeys_list_offset: u32,
161 pub volatile_subkeys_list_offset: u32,
163 pub number_key_values: u32,
165 pub key_values_list_offset: u32,
167 pub key_security_offset: u32,
169 pub class_name_offset: u32,
171 pub largest_subkey_class_name_length: u32,
173 pub largest_subkey_name_length: u16,
176 pub virt_and_user_flags: u8,
178 pub debug: u8,
180 pub largest_value_name_length: u32,
182 pub largest_value_data_size: u32,
184 pub work_var: u32,
186 pub key_name_length: u16,
188 pub class_name_length: u16,
190 pub key_name: String,
192 pub offset: u64,
193}
194
195#[repr(C, packed)]
196pub struct KeyNodeCellPacked {
197 pub signature: u16,
199 pub flags: u16,
201 pub last_written_timestamp: u64,
203 pub access_bits: u32,
205 pub parent: u32,
207 pub number_subkeys: u32,
209 pub number_volatile_subkeys: u32,
211 pub subkeys_list_offset: u32,
213 pub volatile_subkeys_list_offset: u32,
215 pub number_key_values: u32,
217 pub key_values_list_offset: u32,
219 pub key_security_offset: u32,
221 pub class_name_offset: u32,
223 pub largest_subkey_class_name_length: u32,
225 pub largest_subkey_name_length: u16,
228 pub virt_and_user_flags: u8,
230 pub debug: u8,
232 pub largest_value_name_length: u32,
234 pub largest_value_data_size: u32,
236 pub work_var: u32,
238 pub key_name_length: u16,
240 pub class_name_length: u16,
242}
243#[derive(Debug, Clone)]
244pub struct KeyValueCell {
245 pub name_length: u16,
246 pub data_size: u32,
247 pub data_offset: u32,
248 pub data_type: u32,
249 pub flags: u16,
250 pub value_name: String,
251 pub offset: u64,
252}
253#[repr(C, packed)]
254pub struct KeyValueCellPacked {
255 pub signature: u16,
256 pub name_length: u16,
257 pub data_size: u32,
258 pub data_offset: u32,
259 pub data_type: u32,
260 pub flags: u16,
261 pub spare: u16,
262}
263#[derive(Debug, Clone)]
264pub struct KeySecurityCell {
265 pub flink: u32,
266 pub blink: u32,
267 pub ref_count: u32,
268 pub sec_desc_size: u32,
269 pub sec_desc: Vec<u8>,
270 pub offset: u64,
271}
272#[repr(C, packed)]
273pub struct KeySecurityCellPacked {
274 pub signature: u16,
275 pub reserved: u16,
276 pub flink: u32,
277 pub blink: u32,
278 pub ref_count: u32,
279 pub sec_desc_size: u32,
280}
281#[derive(Debug, Clone)]
282pub struct BigDataCell {
283 pub offset: u64,
284}
285
286pub fn peek_cell(data : &[u8]) -> usize {
287 if data.len() < 4 {
288 return 0
289 }
290 let cell_len_i = i32::from_ne_bytes(data[..4].try_into().unwrap_or_default());
291 let cell_len = cell_len_i.unsigned_abs() as usize;
292 cell_len
293}
294
295pub fn read_cell(data: &[u8], offset: u64) -> ForensicResult<HiveCell> {
296 if data.len() < 6 {
297 return Err(ForensicError::bad_format_str("Invalid Cell: too small"))
298 }
299 let cell_len_i = i32::from_ne_bytes(data[..4].try_into().unwrap_or_default());
300 let cell_len = cell_len_i.unsigned_abs() as usize;
301 if cell_len_i >= 0 {
302 return Ok(HiveCell::Unallocated(UnallocatedCell { offset }));
303 }
304 let signature = &data[4..6];
305 if cell_len > data.len() {
306 return Err(ForensicError::bad_format_str("Not enough buffer size"))
307 }
308 let data = &data[4..cell_len];
309 let cell = if signature == INDEX_LEAF_SIGNATURE {
310 let cell = read_index_leaf_cell(data, offset)?;
311 HiveCell::IndexLeaf(cell)
312 } else if signature == FAST_LEAF_SIGNATURE {
313 let cell = read_fast_leaf_cell(data, offset)?;
314 HiveCell::FastLeaf(cell)
315 } else if signature == HASH_LEAF_SIGNATURE {
316 let cell = read_hash_leaf_cell(data, offset)?;
317 HiveCell::HashLeaf(cell)
318 } else if signature == INDEX_ROOT_SIGNATURE {
319 let cell = read_index_root_cell(data, offset)?;
320 HiveCell::IndexRoot(cell)
321 } else if signature == KEY_NODE_SIGNATURE {
322 let cell = read_key_node_cell(data, offset)?;
323 HiveCell::KeyNode(cell)
324 } else if signature == KEY_SECURITY_SIGNATURE {
325 let cell = read_key_security_cell(data, offset)?;
326 HiveCell::KeySecurity(cell)
327 } else if signature == KEY_VALUE_SIGNATURE {
328 let cell = read_key_value_cell(data, offset)?;
329 HiveCell::KeyValue(cell)
330 } else {
331 HiveCell::Invalid(InvalidCell {
332 offset,
333 content: data[..].to_vec(),
334 })
335 };
336 Ok(cell)
337}
338
339pub fn read_index_leaf_cell(data: &[u8], offset: u64) -> ForensicResult<IndexLeafCell> {
340 if data.len() < 4 {
341 return Err(ForensicError::bad_format_str("Invalid IndexLeafCell: too small"))
342 }
343 let signature = &data[0..2];
344 if signature != INDEX_LEAF_SIGNATURE {
345 return Err(ForensicError::bad_format_str("Invalid IndexLeafCell: invalid signature"));
346 }
347 let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
348 let total_size_elements = (n_elements as usize) * 4 + 4;
349 if total_size_elements > data.len() {
350 return Err(ForensicError::bad_format_str("Invalid IndexLeafCell: size larger than buffer"));
351 }
352 let mut offset_list = Vec::with_capacity(n_elements.into());
353 for i in (4..(4 + 4 * n_elements as usize)).step_by(4) {
354 let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
355 offset_list.push(IndexLeafListElements { offset });
356 }
357 Ok(IndexLeafCell {
358 elements: offset_list,
359 offset,
360 })
361}
362
363pub fn read_fast_leaf_cell(data: &[u8], offset: u64) -> ForensicResult<FastLeafCell> {
364 if data.len() < 4 {
365 return Err(ForensicError::bad_format_str("Invalid FastLeafCell: too small"))
366 }
367 let signature = &data[0..2];
368 if signature != FAST_LEAF_SIGNATURE {
369 return Err(ForensicError::bad_format_str("Invalid FastLeafCell: invalid signature"));
370 }
371 let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
372 let total_size_elements = (n_elements as usize) * 8 + 4;
373 if total_size_elements > data.len() {
374 return Err(ForensicError::bad_format_str("Invalid FastLeafCell: size larger than buffer"));
375 }
376 let mut offset_list = Vec::with_capacity(n_elements.into());
377 for i in (4..(4 + 8 * n_elements as usize)).step_by(8) {
378 let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
379 let data_end = match data[i + 4..i + 8].iter().position(|&v| v == 0) {
380 Some(v) => i + 4 + v,
381 None => i + 8,
382 };
383 let txt = String::from_utf8_lossy(&data[i + 4..data_end]).to_string();
384 offset_list.push(FastLeafListElements {
385 offset,
386 name_hint: txt,
387 });
388 }
389 Ok(FastLeafCell {
390 elements: offset_list,
391 offset,
392 })
393}
394
395pub fn read_hash_leaf_cell(data: &[u8], offset: u64) -> ForensicResult<HashLeafCell> {
396 if data.len() < 4 {
397 return Err(ForensicError::bad_format_str("Invalid HashLeafCell: too small"))
398 }
399 let signature = &data[0..2];
400 if signature != HASH_LEAF_SIGNATURE {
401 return Err(ForensicError::bad_format_str("Invalid HashLeafCell: invalid signature"));
402 }
403 let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
404 let total_size_elements = (n_elements as usize) * 8 + 4;
405 if total_size_elements > data.len() {
406 return Err(ForensicError::bad_format_str("Invalid HashLeafCell: size larger than buffer"));
407 }
408 let mut offset_list = Vec::with_capacity(n_elements.into());
409 for i in (4..total_size_elements).step_by(8) {
410 let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
411 let name_hash = u32::from_ne_bytes(data[i + 4..i + 8].try_into().unwrap_or_default());
412 offset_list.push(HashLeafListElements { offset, name_hash });
413 }
414 Ok(HashLeafCell {
415 elements: offset_list,
416 offset,
417 })
418}
419
420pub fn read_index_root_cell(data: &[u8], offset: u64) -> ForensicResult<IndexRootCell> {
421 if data.len() < 4 {
422 return Err(ForensicError::bad_format_str("Invalid IndexRootCell: too small"))
423 }
424 let signature = &data[0..2];
425 if signature != INDEX_ROOT_SIGNATURE {
426 return Err(ForensicError::bad_format_str("Invalid IndexRootCell: invalid signature"));
427 }
428 let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
429 let total_size_elements = (n_elements as usize) * 4 + 4;
430 if total_size_elements > data.len() {
431 return Err(ForensicError::bad_format_str("Invalid IndexRootCell: size larger than buffer"));
432 }
433 let mut offset_list = Vec::with_capacity(n_elements.into());
434 for i in (4..(4 + 4 * n_elements as usize)).step_by(4) {
435 let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
436 offset_list.push(IndexRootSubkeyOffset {
437 subkeys_list_offset: offset,
438 });
439 }
440 Ok(IndexRootCell {
441 elements: offset_list,
442 offset,
443 })
444}
445
446pub fn read_key_node_cell(data: &[u8], offset: u64) -> ForensicResult<KeyNodeCell> {
447 if data.len() < 76 {
448 return Err(ForensicError::bad_format_str("Invalid KeyNode: too small"))
449 }
450 let signature = &data[0..2];
451 if signature != KEY_NODE_SIGNATURE {
452 return Err(ForensicError::bad_format_str("Invalid KeyNode: invalid signature"));
453 }
454 let (head, body, tail) = unsafe { data[0..76].align_to::<KeyNodeCellPacked>() };
455 if !head.is_empty() && !tail.is_empty() {
456 return Err(ForensicError::bad_format_str("Invalid KeyNode: structure not aligned"));
457 }
458 let packed_cell = &body[0];
459 let mut cell: KeyNodeCell = packed_cell.into();
460 cell.offset = offset;
461 if 76 + cell.key_name_length as usize > data.len() {
462 return Err(ForensicError::bad_format_str("Invalid KeyNodeCell: size larger than buffer"));
463 }
464 cell.key_name = if cell.flags & KEY_COMP_NAME_FLAG == 0 {
465 let mut arr = Vec::with_capacity(cell.key_name_length as usize);
466 for i in (76..76 + (cell.key_name_length as usize)).step_by(2) {
467 arr.push(u16::from_ne_bytes([data[i], data[i + 1]]));
468 }
469 String::from_utf16_lossy(&arr).to_string()
470 } else {
471 String::from_utf8_lossy(&data[76..76 + (cell.key_name_length as usize)]).to_string()
472 };
473 Ok(cell)
474}
475
476pub fn read_key_security_cell(data: &[u8], offset: u64) -> ForensicResult<KeySecurityCell> {
477 if data.len() < 76 {
478 return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: too small"))
479 }
480 let signature = &data[0..2];
481 if signature != KEY_SECURITY_SIGNATURE {
482 return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: invalid signature"));
483 }
484 let (head, body, tail) = unsafe { data[0..76].align_to::<KeySecurityCellPacked>() };
485 if !head.is_empty() || !tail.is_empty() {
486 return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: structure not aligned"));
487 }
488 let packed_cell = &body[0];
489 let mut cell: KeySecurityCell = packed_cell.into();
490 cell.offset = offset;
491 let sec_end_pos = 20 + cell.sec_desc_size as usize;
492 if sec_end_pos > data.len() {
493 return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: size larger than buffer"));
494 }
495 for i in 20..sec_end_pos {
496 cell.sec_desc.push(data[i]);
497 }
498 Ok(cell)
499}
500
501pub fn read_key_value_cell(data: &[u8], offset: u64) -> ForensicResult<KeyValueCell> {
502 if data.len() < 20 {
503 return Err(ForensicError::bad_format_str("Invalid KeyValueCell: too small"))
504 }
505 let signature = &data[0..2];
506 if signature != KEY_VALUE_SIGNATURE {
507 return Err(ForensicError::bad_format_str("Invalid KeyValueCell: invalid signature"));
508 }
509 let (head, body, tail) = unsafe { data[0..20].align_to::<KeyValueCellPacked>() };
510 if !head.is_empty() || !tail.is_empty() {
511 return Err(ForensicError::bad_format_str("Invalid KeyValueCell: structure not aligned"));
512 }
513 let packed_cell = &body[0];
514 let mut cell: KeyValueCell = packed_cell.into();
515 cell.offset = offset;
516 let value_name_end = 20 + cell.name_length as usize;
517 if value_name_end > data.len() {
518 return Err(ForensicError::bad_format_str("Invalid KeyValueCell: size larger than buffer"));
519 }
520 if cell.name_length != 0 {
521 cell.value_name = if cell.flags & VALUE_COMP_NAME_FLAG == 0 {
522 let mut arr = Vec::with_capacity(cell.name_length as usize);
523 for i in (20..20 + (cell.name_length as usize)).step_by(2) {
524 arr.push(u16::from_ne_bytes([data[i], data[i + 1]]));
525 }
526 String::from_utf16_lossy(&arr).to_string()
527 } else {
528 String::from_utf8_lossy(&data[20..20 + (cell.name_length as usize)]).to_string()
529 };
530 }
531 Ok(cell)
532}
533
534impl From<KeyNodeCellPacked> for KeyNodeCell {
535 fn from(v: KeyNodeCellPacked) -> Self {
536 KeyNodeCell {
537 flags: v.flags,
538 last_written_timestamp: v.last_written_timestamp,
539 access_bits: v.access_bits,
540 parent: v.parent,
541 number_subkeys: v.number_subkeys,
542 number_volatile_subkeys: v.number_volatile_subkeys,
543 subkeys_list_offset: v.subkeys_list_offset,
544 volatile_subkeys_list_offset: v.volatile_subkeys_list_offset,
545 number_key_values: v.number_key_values,
546 key_values_list_offset: v.key_values_list_offset,
547 key_security_offset: v.key_security_offset,
548 class_name_offset: v.class_name_offset,
549 largest_subkey_class_name_length: v.largest_subkey_class_name_length,
550 largest_subkey_name_length: v.largest_subkey_name_length,
551 debug: v.debug,
552 virt_and_user_flags: v.virt_and_user_flags,
553 largest_value_name_length: v.largest_value_name_length,
554 largest_value_data_size: v.largest_value_data_size,
555 work_var: v.work_var,
556 key_name_length: v.key_name_length,
557 class_name_length: v.class_name_length,
558 key_name: String::new(),
559 offset: 0,
560 }
561 }
562}
563impl From<&KeyNodeCellPacked> for KeyNodeCell {
564 fn from(v: &KeyNodeCellPacked) -> Self {
565 KeyNodeCell {
566 flags: v.flags,
567 last_written_timestamp: v.last_written_timestamp,
568 access_bits: v.access_bits,
569 parent: v.parent,
570 number_subkeys: v.number_subkeys,
571 number_volatile_subkeys: v.number_volatile_subkeys,
572 subkeys_list_offset: v.subkeys_list_offset,
573 volatile_subkeys_list_offset: v.volatile_subkeys_list_offset,
574 number_key_values: v.number_key_values,
575 key_values_list_offset: v.key_values_list_offset,
576 key_security_offset: v.key_security_offset,
577 class_name_offset: v.class_name_offset,
578 largest_subkey_class_name_length: v.largest_subkey_class_name_length,
579 largest_subkey_name_length: v.largest_subkey_name_length,
580 debug: v.debug,
581 virt_and_user_flags: v.virt_and_user_flags,
582 largest_value_name_length: v.largest_value_name_length,
583 largest_value_data_size: v.largest_value_data_size,
584 work_var: v.work_var,
585 key_name_length: v.key_name_length,
586 class_name_length: v.class_name_length,
587 key_name: String::new(),
588 offset: 0,
589 }
590 }
591}
592
593impl From<KeySecurityCellPacked> for KeySecurityCell {
594 fn from(v: KeySecurityCellPacked) -> Self {
595 KeySecurityCell {
596 blink: v.blink,
597 flink: v.flink,
598 ref_count: v.ref_count,
599 sec_desc: Vec::with_capacity(v.sec_desc_size as usize),
600 sec_desc_size: v.sec_desc_size,
601 offset: 0,
602 }
603 }
604}
605impl From<&KeySecurityCellPacked> for KeySecurityCell {
606 fn from(v: &KeySecurityCellPacked) -> Self {
607 KeySecurityCell {
608 blink: v.blink,
609 flink: v.flink,
610 ref_count: v.ref_count,
611 sec_desc: Vec::with_capacity(v.sec_desc_size as usize),
612 sec_desc_size: v.sec_desc_size,
613 offset: 0,
614 }
615 }
616}
617impl From<KeyValueCellPacked> for KeyValueCell {
618 fn from(v: KeyValueCellPacked) -> Self {
619 Self {
620 name_length: v.name_length,
621 data_size: v.data_size,
622 data_offset: v.data_offset,
623 data_type: v.data_type,
624 flags: v.flags,
625 value_name: String::new(),
626 offset: 0,
627 }
628 }
629}
630impl From<&KeyValueCellPacked> for KeyValueCell {
631 fn from(v: &KeyValueCellPacked) -> Self {
632 Self {
633 name_length: v.name_length,
634 data_size: v.data_size,
635 data_offset: v.data_offset,
636 data_type: v.data_type,
637 flags: v.flags,
638 value_name: String::new(),
639 offset: 0,
640 }
641 }
642}
643
644impl InvalidCell {
645 pub fn into_reg_sz_extended(&self) -> String {
646 let s: &[u16] = unsafe {
647 std::slice::from_raw_parts(self.content.as_ptr() as *const _, self.content.len() / 2)
648 };
649 let first_zero = match s.iter().rev().position(|&v| v == 0) {
650 Some(v) => s.len() - v,
651 None => s.len(),
652 };
653 let last_zero = match s[0..first_zero].iter().rev().position(|&v| v != 0) {
654 Some(v) => first_zero - v,
655 None => s.len(),
656 };
657 String::from_utf16_lossy(&s[..last_zero])
658 }
659 pub fn into_reg_sz_ascii(&self) -> String {
660 let first_zero = match self.content.iter().rev().position(|&v| v == 0) {
661 Some(v) => self.content.len() - v,
662 None => self.content.len(),
663 };
664 let last_zero = match self.content[0..first_zero]
665 .iter()
666 .rev()
667 .position(|&v| v != 0)
668 {
669 Some(v) => first_zero - v,
670 None => self.content.len(),
671 };
672 let ret = String::from_utf8_lossy(&self.content[..last_zero]).to_string();
673 ret
674 }
675 pub fn into_dword(&self) -> u32 {
676 if self.content.len() != 4 {
677 return 0;
678 }
679 u32::from_ne_bytes(self.content[0..4].try_into().unwrap_or_default())
680 }
681 pub fn into_dword_le(&self) -> u32 {
682 if self.content.len() != 4 {
683 return 0;
684 }
685 u32::from_le_bytes(self.content[0..4].try_into().unwrap_or_default())
686 }
687 pub fn into_dword_be(&self) -> u32 {
688 if self.content.len() != 4 {
689 return 0;
690 }
691 u32::from_be_bytes(self.content[0..4].try_into().unwrap_or_default())
692 }
693 pub fn into_qword_le(&self) -> u64 {
694 if self.content.len() != 8 {
695 return 0;
696 }
697 u64::from_le_bytes(self.content[0..8].try_into().unwrap_or_default())
698 }
699}
700
701#[cfg(test)]
702mod tst {
703 use crate::cell::HashLeafCell;
704
705 #[test]
706 fn should_hash_sam_name() {
707 assert_eq!(116109, HashLeafCell::hash_name("SAM"));
708 assert_eq!(116109, HashLeafCell::hash_name("sam"));
709 assert_eq!(116109, HashLeafCell::hash_name("SaM"));
710 }
711}