///|
/// Flag bit marking a key name stored as single-byte characters.
let key_flag_compressed_name : UInt32 = 0x0020
// Offsets inside an nk record, relative to its two signature bytes.
///|
let nk_flags : Int32 = 2
///|
let nk_last_written : Int32 = 4
///|
let nk_access_bits : Int32 = 12
///|
let nk_parent : Int32 = 16
///|
let nk_subkey_count : Int32 = 20
///|
let nk_volatile_subkey_count : Int32 = 24
///|
let nk_subkey_list : Int32 = 28
///|
let nk_volatile_subkey_list : Int32 = 32
///|
let nk_value_count : Int32 = 36
///|
let nk_value_list : Int32 = 40
///|
let nk_security : Int32 = 44
///|
let nk_class_name : Int32 = 48
///|
let nk_name_length : Int32 = 72
///|
let nk_class_name_length : Int32 = 74
///|
let nk_name : Int32 = 76
///|
let nk_min_size : Int32 = 76
///|
/// A key node (nk) record: one registry key and the offsets of its children.
pub(all) struct HiveKeyNode {
offset : UInt32
flags : UInt32
last_written_high : UInt32
last_written_low : UInt32
access_bits : UInt32
parent_offset : UInt32
subkey_count : UInt32
volatile_subkey_count : UInt32
subkey_list_offset : UInt32
volatile_subkey_list_offset : UInt32
value_count : UInt32
value_list_offset : UInt32
security_offset : UInt32
class_name_offset : UInt32
name_length : UInt32
class_name_length : UInt32
name : String
}
///|
/// Parses the key node stored in the cell at offset.
pub fn parse_key_node(
bytes : Bytes,
offset : UInt32,
) -> Result[HiveKeyNode, RegfError] {
match read_cell(bytes, offset) {
Err(error) => Err(error)
Ok(cell) => parse_key_payload(bytes, cell)
}
}
///|
/// True when the two bytes at start are the ASCII signature of an nk record.
fn key_signature_matches(bytes : Bytes, start : Int32) -> Bool {
bytes[start].to_int() == 0x6E && bytes[start + 1].to_int() == 0x6B
}
///|
/// Parses the nk payload of an already validated cell.
fn parse_key_payload(
bytes : Bytes,
cell : HiveCell,
) -> Result[HiveKeyNode, RegfError] {
let relative = cell.offset.reinterpret_as_int()
let start = hive_bins_base + relative + 4
if cell.payload_size < nk_min_size {
return Err(BadKeyNode(relative))
}
if !key_signature_matches(bytes, start) {
return Err(BadKeyNode(relative))
}
let flags = read_u16_le(bytes, start + nk_flags)
let name_length = read_u16_le(bytes, start + nk_name_length)
let class_name_length = read_u16_le(bytes, start + nk_class_name_length)
let name_len = name_length.reinterpret_as_int()
if nk_name + name_len > cell.payload_size {
return Err(BadKeyNode(relative))
}
let name = if (flags & key_flag_compressed_name) != 0 {
decode_single_byte(bytes, start + nk_name, name_len)
} else {
decode_utf16le(bytes, start + nk_name, name_len / 2)
}
let key : HiveKeyNode = {
offset: cell.offset,
flags,
last_written_high: read_u32_le(bytes, start + nk_last_written),
last_written_low: read_u32_le(bytes, start + nk_last_written + 4),
access_bits: read_u32_le(bytes, start + nk_access_bits),
parent_offset: read_u32_le(bytes, start + nk_parent),
subkey_count: read_u32_le(bytes, start + nk_subkey_count),
volatile_subkey_count: read_u32_le(bytes, start + nk_volatile_subkey_count),
subkey_list_offset: read_u32_le(bytes, start + nk_subkey_list),
volatile_subkey_list_offset: read_u32_le(
bytes,
start + nk_volatile_subkey_list,
),
value_count: read_u32_le(bytes, start + nk_value_count),
value_list_offset: read_u32_le(bytes, start + nk_value_list),
security_offset: read_u32_le(bytes, start + nk_security),
class_name_offset: read_u32_le(bytes, start + nk_class_name),
name_length,
class_name_length,
name,
}
Ok(key)
}