Windows registry database: Nim parsing library

This spec allows to parse files used by Microsoft Windows family of operating systems to store parts of its "registry". "Registry" is a hierarchical database that is used to store system settings (global configuration, per-user, per-application configuration, etc).

Typically, registry files are stored in:

  • System-wide: several files in %SystemRoot%\System32\Config\
  • User-wide:
    • %USERPROFILE%\Ntuser.dat
    • %USERPROFILE%\Local Settings\Application Data\Microsoft\Windows\Usrclass.dat (localized, Windows 2000, Server 2003 and Windows XP)
    • %USERPROFILE%\AppData\Local\Microsoft\Windows\Usrclass.dat (non-localized, Windows Vista and later)

Note that one typically can't access files directly on a mounted filesystem with a running Windows OS.

Application

Windows NT and later

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of Windows registry database using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Nim source code to parse Windows registry database

regf.nim

import kaitai_struct_nim_runtime
import options

type
  Regf* = ref object of KaitaiStruct
    `header`*: Regf_FileHeader
    `hiveBins`*: seq[Regf_HiveBin]
    `parent`*: KaitaiStruct
    `rawHiveBins`*: seq[seq[byte]]
  Regf_Filetime* = ref object of KaitaiStruct
    `value`*: uint64
    `parent`*: KaitaiStruct
  Regf_HiveBin* = ref object of KaitaiStruct
    `header`*: Regf_HiveBinHeader
    `cells`*: seq[Regf_HiveBinCell]
    `parent`*: Regf
  Regf_HiveBinHeader* = ref object of KaitaiStruct
    `signature`*: seq[byte]
    `offset`*: uint32
    `size`*: uint32
    `unknown1`*: uint32
    `unknown2`*: uint32
    `timestamp`*: Regf_Filetime
    `unknown4`*: uint32
    `parent`*: Regf_HiveBin
  Regf_HiveBinCell* = ref object of KaitaiStruct
    `cellSizeRaw`*: int32
    `identifier`*: string
    `data`*: KaitaiStruct
    `parent`*: Regf_HiveBin
    `rawData`*: seq[byte]
    `cellSizeInst`*: int
    `isAllocatedInst`*: bool
  Regf_HiveBinCell_SubKeyListVk* = ref object of KaitaiStruct
    `valueNameSize`*: uint16
    `dataSize`*: uint32
    `dataOffset`*: uint32
    `dataType`*: Regf_HiveBinCell_SubKeyListVk_DataTypeEnum
    `flags`*: Regf_HiveBinCell_SubKeyListVk_VkFlags
    `padding`*: uint16
    `valueName`*: string
    `parent`*: Regf_HiveBinCell
  Regf_HiveBinCell_SubKeyListVk_DataTypeEnum* = enum
    reg_none = 0
    reg_sz = 1
    reg_expand_sz = 2
    reg_binary = 3
    reg_dword = 4
    reg_dword_big_endian = 5
    reg_link = 6
    reg_multi_sz = 7
    reg_resource_list = 8
    reg_full_resource_descriptor = 9
    reg_resource_requirements_list = 10
    reg_qword = 11
  Regf_HiveBinCell_SubKeyListVk_VkFlags* = enum
    value_comp_name = 1
  Regf_HiveBinCell_SubKeyListLhLf* = ref object of KaitaiStruct
    `count`*: uint16
    `items`*: seq[Regf_HiveBinCell_SubKeyListLhLf_Item]
    `parent`*: Regf_HiveBinCell
  Regf_HiveBinCell_SubKeyListLhLf_Item* = ref object of KaitaiStruct
    `namedKeyOffset`*: uint32
    `hashValue`*: uint32
    `parent`*: Regf_HiveBinCell_SubKeyListLhLf
  Regf_HiveBinCell_SubKeyListSk* = ref object of KaitaiStruct
    `unknown1`*: uint16
    `previousSecurityKeyOffset`*: uint32
    `nextSecurityKeyOffset`*: uint32
    `referenceCount`*: uint32
    `parent`*: Regf_HiveBinCell
  Regf_HiveBinCell_SubKeyListLi* = ref object of KaitaiStruct
    `count`*: uint16
    `items`*: seq[Regf_HiveBinCell_SubKeyListLi_Item]
    `parent`*: Regf_HiveBinCell
  Regf_HiveBinCell_SubKeyListLi_Item* = ref object of KaitaiStruct
    `namedKeyOffset`*: uint32
    `parent`*: Regf_HiveBinCell_SubKeyListLi
  Regf_HiveBinCell_NamedKey* = ref object of KaitaiStruct
    `flags`*: Regf_HiveBinCell_NamedKey_NkFlags
    `lastKeyWrittenDateAndTime`*: Regf_Filetime
    `unknown1`*: uint32
    `parentKeyOffset`*: uint32
    `numberOfSubKeys`*: uint32
    `numberOfVolatileSubKeys`*: uint32
    `subKeysListOffset`*: uint32
    `numberOfValues`*: uint32
    `valuesListOffset`*: uint32
    `securityKeyOffset`*: uint32
    `classNameOffset`*: uint32
    `largestSubKeyNameSize`*: uint32
    `largestSubKeyClassNameSize`*: uint32
    `largestValueNameSize`*: uint32
    `largestValueDataSize`*: uint32
    `unknown2`*: uint32
    `keyNameSize`*: uint16
    `classNameSize`*: uint16
    `unknownStringSize`*: uint32
    `unknownString`*: string
    `parent`*: Regf_HiveBinCell
  Regf_HiveBinCell_NamedKey_NkFlags* = enum
    key_is_volatile = 1
    key_hive_exit = 2
    key_hive_entry = 4
    key_no_delete = 8
    key_sym_link = 16
    key_comp_name = 32
    key_prefef_handle = 64
    key_virt_mirrored = 128
    key_virt_target = 256
    key_virtual_store = 512
    unknown1 = 4096
    unknown2 = 16384
  Regf_HiveBinCell_SubKeyListRi* = ref object of KaitaiStruct
    `count`*: uint16
    `items`*: seq[Regf_HiveBinCell_SubKeyListRi_Item]
    `parent`*: Regf_HiveBinCell
  Regf_HiveBinCell_SubKeyListRi_Item* = ref object of KaitaiStruct
    `subKeyListOffset`*: uint32
    `parent`*: Regf_HiveBinCell_SubKeyListRi
  Regf_FileHeader* = ref object of KaitaiStruct
    `signature`*: seq[byte]
    `primarySequenceNumber`*: uint32
    `secondarySequenceNumber`*: uint32
    `lastModificationDateAndTime`*: Regf_Filetime
    `majorVersion`*: uint32
    `minorVersion`*: uint32
    `type`*: Regf_FileHeader_FileType
    `format`*: Regf_FileHeader_FileFormat
    `rootKeyOffset`*: uint32
    `hiveBinsDataSize`*: uint32
    `clusteringFactor`*: uint32
    `unknown1`*: seq[byte]
    `unknown2`*: seq[byte]
    `checksum`*: uint32
    `reserved`*: seq[byte]
    `bootType`*: uint32
    `bootRecover`*: uint32
    `parent`*: Regf
  Regf_FileHeader_FileType* = enum
    normal = 0
    transaction_log = 1
  Regf_FileHeader_FileFormat* = enum
    direct_memory_load = 1

proc read*(_: typedesc[Regf], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): Regf
proc read*(_: typedesc[Regf_Filetime], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): Regf_Filetime
proc read*(_: typedesc[Regf_HiveBin], io: KaitaiStream, root: KaitaiStruct, parent: Regf): Regf_HiveBin
proc read*(_: typedesc[Regf_HiveBinHeader], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBin): Regf_HiveBinHeader
proc read*(_: typedesc[Regf_HiveBinCell], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBin): Regf_HiveBinCell
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListVk], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListVk
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLhLf], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListLhLf
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLhLf_Item], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell_SubKeyListLhLf): Regf_HiveBinCell_SubKeyListLhLf_Item
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListSk], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListSk
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLi], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListLi
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLi_Item], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell_SubKeyListLi): Regf_HiveBinCell_SubKeyListLi_Item
proc read*(_: typedesc[Regf_HiveBinCell_NamedKey], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_NamedKey
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListRi], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListRi
proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListRi_Item], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell_SubKeyListRi): Regf_HiveBinCell_SubKeyListRi_Item
proc read*(_: typedesc[Regf_FileHeader], io: KaitaiStream, root: KaitaiStruct, parent: Regf): Regf_FileHeader

proc cellSize*(this: Regf_HiveBinCell): int
proc isAllocated*(this: Regf_HiveBinCell): bool


##[
This spec allows to parse files used by Microsoft Windows family of
operating systems to store parts of its "registry". "Registry" is a
hierarchical database that is used to store system settings (global
configuration, per-user, per-application configuration, etc).

Typically, registry files are stored in:

* System-wide: several files in `%SystemRoot%\System32\Config\`
* User-wide:
  * `%USERPROFILE%\Ntuser.dat`
  * `%USERPROFILE%\Local Settings\Application Data\Microsoft\Windows\Usrclass.dat` (localized, Windows 2000, Server 2003 and Windows XP)
  * `%USERPROFILE%\AppData\Local\Microsoft\Windows\Usrclass.dat` (non-localized, Windows Vista and later)

Note that one typically can't access files directly on a mounted
filesystem with a running Windows OS.

@see <a href="https://github.com/libyal/libregf/blob/master/documentation/Windows%20NT%20Registry%20File%20(REGF)%20format.asciidoc">Source</a>
]##
proc read*(_: typedesc[Regf], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): Regf =
  template this: untyped = result
  this = new(Regf)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let headerExpr = Regf_FileHeader.read(this.io, this.root, this)
  this.header = headerExpr
  block:
    var i: int
    while not this.io.isEof:
      let buf = this.io.readBytes(int(4096))
      this.rawHiveBins.add(buf)
      let rawHiveBinsIo = newKaitaiStream(buf)
      let it = Regf_HiveBin.read(rawHiveBinsIo, this.root, this)
      this.hiveBins.add(it)
      inc i

proc fromFile*(_: typedesc[Regf], filename: string): Regf =
  Regf.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_Filetime], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): Regf_Filetime =
  template this: untyped = result
  this = new(Regf_Filetime)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let valueExpr = this.io.readU8le()
  this.value = valueExpr

proc fromFile*(_: typedesc[Regf_Filetime], filename: string): Regf_Filetime =
  Regf_Filetime.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBin], io: KaitaiStream, root: KaitaiStruct, parent: Regf): Regf_HiveBin =
  template this: untyped = result
  this = new(Regf_HiveBin)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let headerExpr = Regf_HiveBinHeader.read(this.io, this.root, this)
  this.header = headerExpr
  block:
    var i: int
    while not this.io.isEof:
      let it = Regf_HiveBinCell.read(this.io, this.root, this)
      this.cells.add(it)
      inc i

proc fromFile*(_: typedesc[Regf_HiveBin], filename: string): Regf_HiveBin =
  Regf_HiveBin.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinHeader], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBin): Regf_HiveBinHeader =
  template this: untyped = result
  this = new(Regf_HiveBinHeader)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let signatureExpr = this.io.readBytes(int(4))
  this.signature = signatureExpr

  ##[
  The offset of the hive bin, Value in bytes and relative from
the start of the hive bin data

  ]##
  let offsetExpr = this.io.readU4le()
  this.offset = offsetExpr

  ##[
  Size of the hive bin
  ]##
  let sizeExpr = this.io.readU4le()
  this.size = sizeExpr

  ##[
  0 most of the time, can contain remnant data
  ]##
  let unknown1Expr = this.io.readU4le()
  this.unknown1 = unknown1Expr

  ##[
  0 most of the time, can contain remnant data
  ]##
  let unknown2Expr = this.io.readU4le()
  this.unknown2 = unknown2Expr

  ##[
  Only the root (first) hive bin seems to contain a valid FILETIME
  ]##
  let timestampExpr = Regf_Filetime.read(this.io, this.root, this)
  this.timestamp = timestampExpr

  ##[
  Contains number of bytes
  ]##
  let unknown4Expr = this.io.readU4le()
  this.unknown4 = unknown4Expr

proc fromFile*(_: typedesc[Regf_HiveBinHeader], filename: string): Regf_HiveBinHeader =
  Regf_HiveBinHeader.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBin): Regf_HiveBinCell =
  template this: untyped = result
  this = new(Regf_HiveBinCell)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let cellSizeRawExpr = this.io.readS4le()
  this.cellSizeRaw = cellSizeRawExpr
  let identifierExpr = encode(this.io.readBytes(int(2)), "ascii")
  this.identifier = identifierExpr
  block:
    let on = this.identifier
    if on == "li":
      let rawDataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.rawData = rawDataExpr
      let rawDataIo = newKaitaiStream(rawDataExpr)
      let dataExpr = Regf_HiveBinCell_SubKeyListLi.read(rawDataIo, this.root, this)
      this.data = dataExpr
    elif on == "vk":
      let rawDataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.rawData = rawDataExpr
      let rawDataIo = newKaitaiStream(rawDataExpr)
      let dataExpr = Regf_HiveBinCell_SubKeyListVk.read(rawDataIo, this.root, this)
      this.data = dataExpr
    elif on == "lf":
      let rawDataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.rawData = rawDataExpr
      let rawDataIo = newKaitaiStream(rawDataExpr)
      let dataExpr = Regf_HiveBinCell_SubKeyListLhLf.read(rawDataIo, this.root, this)
      this.data = dataExpr
    elif on == "ri":
      let rawDataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.rawData = rawDataExpr
      let rawDataIo = newKaitaiStream(rawDataExpr)
      let dataExpr = Regf_HiveBinCell_SubKeyListRi.read(rawDataIo, this.root, this)
      this.data = dataExpr
    elif on == "lh":
      let rawDataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.rawData = rawDataExpr
      let rawDataIo = newKaitaiStream(rawDataExpr)
      let dataExpr = Regf_HiveBinCell_SubKeyListLhLf.read(rawDataIo, this.root, this)
      this.data = dataExpr
    elif on == "nk":
      let rawDataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.rawData = rawDataExpr
      let rawDataIo = newKaitaiStream(rawDataExpr)
      let dataExpr = Regf_HiveBinCell_NamedKey.read(rawDataIo, this.root, this)
      this.data = dataExpr
    elif on == "sk":
      let rawDataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.rawData = rawDataExpr
      let rawDataIo = newKaitaiStream(rawDataExpr)
      let dataExpr = Regf_HiveBinCell_SubKeyListSk.read(rawDataIo, this.root, this)
      this.data = dataExpr
    else:
      let dataExpr = this.io.readBytes(int(((this.cellSize - 2) - 4)))
      this.data = dataExpr

proc cellSize(this: Regf_HiveBinCell): int = 
  if this.cellSizeInst != nil:
    return this.cellSizeInst
  let cellSizeInstExpr = int(((if this.cellSizeRaw < 0: -1 else: 1) * this.cellSizeRaw))
  this.cellSizeInst = cellSizeInstExpr
  if this.cellSizeInst != nil:
    return this.cellSizeInst

proc isAllocated(this: Regf_HiveBinCell): bool = 
  if this.isAllocatedInst != nil:
    return this.isAllocatedInst
  let isAllocatedInstExpr = bool(this.cellSizeRaw < 0)
  this.isAllocatedInst = isAllocatedInstExpr
  if this.isAllocatedInst != nil:
    return this.isAllocatedInst

proc fromFile*(_: typedesc[Regf_HiveBinCell], filename: string): Regf_HiveBinCell =
  Regf_HiveBinCell.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListVk], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListVk =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListVk)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let valueNameSizeExpr = this.io.readU2le()
  this.valueNameSize = valueNameSizeExpr
  let dataSizeExpr = this.io.readU4le()
  this.dataSize = dataSizeExpr
  let dataOffsetExpr = this.io.readU4le()
  this.dataOffset = dataOffsetExpr
  let dataTypeExpr = Regf_HiveBinCell_SubKeyListVk_DataTypeEnum(this.io.readU4le())
  this.dataType = dataTypeExpr
  let flagsExpr = Regf_HiveBinCell_SubKeyListVk_VkFlags(this.io.readU2le())
  this.flags = flagsExpr
  let paddingExpr = this.io.readU2le()
  this.padding = paddingExpr
  if this.flags == regf.value_comp_name:
    let valueNameExpr = encode(this.io.readBytes(int(this.valueNameSize)), "ascii")
    this.valueName = valueNameExpr

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListVk], filename: string): Regf_HiveBinCell_SubKeyListVk =
  Regf_HiveBinCell_SubKeyListVk.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLhLf], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListLhLf =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListLhLf)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let countExpr = this.io.readU2le()
  this.count = countExpr
  for i in 0 ..< int(this.count):
    let it = Regf_HiveBinCell_SubKeyListLhLf_Item.read(this.io, this.root, this)
    this.items.add(it)

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListLhLf], filename: string): Regf_HiveBinCell_SubKeyListLhLf =
  Regf_HiveBinCell_SubKeyListLhLf.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLhLf_Item], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell_SubKeyListLhLf): Regf_HiveBinCell_SubKeyListLhLf_Item =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListLhLf_Item)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let namedKeyOffsetExpr = this.io.readU4le()
  this.namedKeyOffset = namedKeyOffsetExpr
  let hashValueExpr = this.io.readU4le()
  this.hashValue = hashValueExpr

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListLhLf_Item], filename: string): Regf_HiveBinCell_SubKeyListLhLf_Item =
  Regf_HiveBinCell_SubKeyListLhLf_Item.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListSk], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListSk =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListSk)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let unknown1Expr = this.io.readU2le()
  this.unknown1 = unknown1Expr
  let previousSecurityKeyOffsetExpr = this.io.readU4le()
  this.previousSecurityKeyOffset = previousSecurityKeyOffsetExpr
  let nextSecurityKeyOffsetExpr = this.io.readU4le()
  this.nextSecurityKeyOffset = nextSecurityKeyOffsetExpr
  let referenceCountExpr = this.io.readU4le()
  this.referenceCount = referenceCountExpr

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListSk], filename: string): Regf_HiveBinCell_SubKeyListSk =
  Regf_HiveBinCell_SubKeyListSk.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLi], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListLi =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListLi)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let countExpr = this.io.readU2le()
  this.count = countExpr
  for i in 0 ..< int(this.count):
    let it = Regf_HiveBinCell_SubKeyListLi_Item.read(this.io, this.root, this)
    this.items.add(it)

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListLi], filename: string): Regf_HiveBinCell_SubKeyListLi =
  Regf_HiveBinCell_SubKeyListLi.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListLi_Item], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell_SubKeyListLi): Regf_HiveBinCell_SubKeyListLi_Item =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListLi_Item)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let namedKeyOffsetExpr = this.io.readU4le()
  this.namedKeyOffset = namedKeyOffsetExpr

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListLi_Item], filename: string): Regf_HiveBinCell_SubKeyListLi_Item =
  Regf_HiveBinCell_SubKeyListLi_Item.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_NamedKey], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_NamedKey =
  template this: untyped = result
  this = new(Regf_HiveBinCell_NamedKey)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let flagsExpr = Regf_HiveBinCell_NamedKey_NkFlags(this.io.readU2le())
  this.flags = flagsExpr
  let lastKeyWrittenDateAndTimeExpr = Regf_Filetime.read(this.io, this.root, this)
  this.lastKeyWrittenDateAndTime = lastKeyWrittenDateAndTimeExpr
  let unknown1Expr = this.io.readU4le()
  this.unknown1 = unknown1Expr
  let parentKeyOffsetExpr = this.io.readU4le()
  this.parentKeyOffset = parentKeyOffsetExpr
  let numberOfSubKeysExpr = this.io.readU4le()
  this.numberOfSubKeys = numberOfSubKeysExpr
  let numberOfVolatileSubKeysExpr = this.io.readU4le()
  this.numberOfVolatileSubKeys = numberOfVolatileSubKeysExpr
  let subKeysListOffsetExpr = this.io.readU4le()
  this.subKeysListOffset = subKeysListOffsetExpr
  let numberOfValuesExpr = this.io.readU4le()
  this.numberOfValues = numberOfValuesExpr
  let valuesListOffsetExpr = this.io.readU4le()
  this.valuesListOffset = valuesListOffsetExpr
  let securityKeyOffsetExpr = this.io.readU4le()
  this.securityKeyOffset = securityKeyOffsetExpr
  let classNameOffsetExpr = this.io.readU4le()
  this.classNameOffset = classNameOffsetExpr
  let largestSubKeyNameSizeExpr = this.io.readU4le()
  this.largestSubKeyNameSize = largestSubKeyNameSizeExpr
  let largestSubKeyClassNameSizeExpr = this.io.readU4le()
  this.largestSubKeyClassNameSize = largestSubKeyClassNameSizeExpr
  let largestValueNameSizeExpr = this.io.readU4le()
  this.largestValueNameSize = largestValueNameSizeExpr
  let largestValueDataSizeExpr = this.io.readU4le()
  this.largestValueDataSize = largestValueDataSizeExpr
  let unknown2Expr = this.io.readU4le()
  this.unknown2 = unknown2Expr
  let keyNameSizeExpr = this.io.readU2le()
  this.keyNameSize = keyNameSizeExpr
  let classNameSizeExpr = this.io.readU2le()
  this.classNameSize = classNameSizeExpr
  let unknownStringSizeExpr = this.io.readU4le()
  this.unknownStringSize = unknownStringSizeExpr
  let unknownStringExpr = encode(this.io.readBytes(int(this.unknownStringSize)), "ascii")
  this.unknownString = unknownStringExpr

proc fromFile*(_: typedesc[Regf_HiveBinCell_NamedKey], filename: string): Regf_HiveBinCell_NamedKey =
  Regf_HiveBinCell_NamedKey.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListRi], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell): Regf_HiveBinCell_SubKeyListRi =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListRi)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let countExpr = this.io.readU2le()
  this.count = countExpr
  for i in 0 ..< int(this.count):
    let it = Regf_HiveBinCell_SubKeyListRi_Item.read(this.io, this.root, this)
    this.items.add(it)

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListRi], filename: string): Regf_HiveBinCell_SubKeyListRi =
  Regf_HiveBinCell_SubKeyListRi.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_HiveBinCell_SubKeyListRi_Item], io: KaitaiStream, root: KaitaiStruct, parent: Regf_HiveBinCell_SubKeyListRi): Regf_HiveBinCell_SubKeyListRi_Item =
  template this: untyped = result
  this = new(Regf_HiveBinCell_SubKeyListRi_Item)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let subKeyListOffsetExpr = this.io.readU4le()
  this.subKeyListOffset = subKeyListOffsetExpr

proc fromFile*(_: typedesc[Regf_HiveBinCell_SubKeyListRi_Item], filename: string): Regf_HiveBinCell_SubKeyListRi_Item =
  Regf_HiveBinCell_SubKeyListRi_Item.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[Regf_FileHeader], io: KaitaiStream, root: KaitaiStruct, parent: Regf): Regf_FileHeader =
  template this: untyped = result
  this = new(Regf_FileHeader)
  let root = if root == nil: cast[Regf](this) else: cast[Regf](root)
  this.io = io
  this.root = root
  this.parent = parent

  let signatureExpr = this.io.readBytes(int(4))
  this.signature = signatureExpr
  let primarySequenceNumberExpr = this.io.readU4le()
  this.primarySequenceNumber = primarySequenceNumberExpr
  let secondarySequenceNumberExpr = this.io.readU4le()
  this.secondarySequenceNumber = secondarySequenceNumberExpr
  let lastModificationDateAndTimeExpr = Regf_Filetime.read(this.io, this.root, this)
  this.lastModificationDateAndTime = lastModificationDateAndTimeExpr
  let majorVersionExpr = this.io.readU4le()
  this.majorVersion = majorVersionExpr
  let minorVersionExpr = this.io.readU4le()
  this.minorVersion = minorVersionExpr
  let typeExpr = Regf_FileHeader_FileType(this.io.readU4le())
  this.type = typeExpr
  let formatExpr = Regf_FileHeader_FileFormat(this.io.readU4le())
  this.format = formatExpr
  let rootKeyOffsetExpr = this.io.readU4le()
  this.rootKeyOffset = rootKeyOffsetExpr
  let hiveBinsDataSizeExpr = this.io.readU4le()
  this.hiveBinsDataSize = hiveBinsDataSizeExpr
  let clusteringFactorExpr = this.io.readU4le()
  this.clusteringFactor = clusteringFactorExpr
  let unknown1Expr = this.io.readBytes(int(64))
  this.unknown1 = unknown1Expr
  let unknown2Expr = this.io.readBytes(int(396))
  this.unknown2 = unknown2Expr
  let checksumExpr = this.io.readU4le()
  this.checksum = checksumExpr
  let reservedExpr = this.io.readBytes(int(3576))
  this.reserved = reservedExpr
  let bootTypeExpr = this.io.readU4le()
  this.bootType = bootTypeExpr
  let bootRecoverExpr = this.io.readU4le()
  this.bootRecover = bootRecoverExpr

proc fromFile*(_: typedesc[Regf_FileHeader], filename: string): Regf_FileHeader =
  Regf_FileHeader.read(newKaitaiFileStream(filename), nil, nil)