GPT (GUID) partition table: Nim parsing library

This page hosts a formal specification of GPT (GUID) partition table 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 GPT (GUID) partition table

gpt_partition_table.nim

import kaitai_struct_nim_runtime
import options

type
  GptPartitionTable* = ref object of KaitaiStruct
    `parent`*: KaitaiStruct
    `sectorSizeInst`: int
    `sectorSizeInstFlag`: bool
    `primaryInst`: GptPartitionTable_PartitionHeader
    `primaryInstFlag`: bool
    `backupInst`: GptPartitionTable_PartitionHeader
    `backupInstFlag`: bool
  GptPartitionTable_PartitionEntry* = ref object of KaitaiStruct
    `typeGuid`*: seq[byte]
    `guid`*: seq[byte]
    `firstLba`*: uint64
    `lastLba`*: uint64
    `attributes`*: uint64
    `name`*: string
    `parent`*: GptPartitionTable_PartitionHeader
  GptPartitionTable_PartitionHeader* = ref object of KaitaiStruct
    `signature`*: seq[byte]
    `revision`*: uint32
    `headerSize`*: uint32
    `crc32Header`*: uint32
    `reserved`*: uint32
    `currentLba`*: uint64
    `backupLba`*: uint64
    `firstUsableLba`*: uint64
    `lastUsableLba`*: uint64
    `diskGuid`*: seq[byte]
    `entriesStart`*: uint64
    `entriesCount`*: uint32
    `entriesSize`*: uint32
    `crc32Array`*: uint32
    `parent`*: GptPartitionTable
    `rawEntriesInst`*: seq[seq[byte]]
    `entriesInst`: seq[GptPartitionTable_PartitionEntry]
    `entriesInstFlag`: bool

proc read*(_: typedesc[GptPartitionTable], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): GptPartitionTable
proc read*(_: typedesc[GptPartitionTable_PartitionEntry], io: KaitaiStream, root: KaitaiStruct, parent: GptPartitionTable_PartitionHeader): GptPartitionTable_PartitionEntry
proc read*(_: typedesc[GptPartitionTable_PartitionHeader], io: KaitaiStream, root: KaitaiStruct, parent: GptPartitionTable): GptPartitionTable_PartitionHeader

proc sectorSize*(this: GptPartitionTable): int
proc primary*(this: GptPartitionTable): GptPartitionTable_PartitionHeader
proc backup*(this: GptPartitionTable): GptPartitionTable_PartitionHeader
proc entries*(this: GptPartitionTable_PartitionHeader): seq[GptPartitionTable_PartitionEntry]


##[
@see <a href="https://en.wikipedia.org/wiki/GUID_Partition_Table">Source</a>
]##
proc read*(_: typedesc[GptPartitionTable], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): GptPartitionTable =
  template this: untyped = result
  this = new(GptPartitionTable)
  let root = if root == nil: cast[GptPartitionTable](this) else: cast[GptPartitionTable](root)
  this.io = io
  this.root = root
  this.parent = parent


proc sectorSize(this: GptPartitionTable): int = 
  if this.sectorSizeInstFlag:
    return this.sectorSizeInst
  let sectorSizeInstExpr = int(512)
  this.sectorSizeInst = sectorSizeInstExpr
  this.sectorSizeInstFlag = true
  return this.sectorSizeInst

proc primary(this: GptPartitionTable): GptPartitionTable_PartitionHeader = 
  if this.primaryInstFlag:
    return this.primaryInst
  let io = GptPartitionTable(this.root).io
  let pos = io.pos()
  io.seek(int(GptPartitionTable(this.root).sectorSize))
  let primaryInstExpr = GptPartitionTable_PartitionHeader.read(io, this.root, this)
  this.primaryInst = primaryInstExpr
  io.seek(pos)
  this.primaryInstFlag = true
  return this.primaryInst

proc backup(this: GptPartitionTable): GptPartitionTable_PartitionHeader = 
  if this.backupInstFlag:
    return this.backupInst
  let io = GptPartitionTable(this.root).io
  let pos = io.pos()
  io.seek(int((this.io.size - GptPartitionTable(this.root).sectorSize)))
  let backupInstExpr = GptPartitionTable_PartitionHeader.read(io, this.root, this)
  this.backupInst = backupInstExpr
  io.seek(pos)
  this.backupInstFlag = true
  return this.backupInst

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

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

  let typeGuidExpr = this.io.readBytes(int(16))
  this.typeGuid = typeGuidExpr
  let guidExpr = this.io.readBytes(int(16))
  this.guid = guidExpr
  let firstLbaExpr = this.io.readU8le()
  this.firstLba = firstLbaExpr
  let lastLbaExpr = this.io.readU8le()
  this.lastLba = lastLbaExpr
  let attributesExpr = this.io.readU8le()
  this.attributes = attributesExpr
  let nameExpr = encode(this.io.readBytes(int(72)), "UTF-16LE")
  this.name = nameExpr

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

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

  let signatureExpr = this.io.readBytes(int(8))
  this.signature = signatureExpr
  let revisionExpr = this.io.readU4le()
  this.revision = revisionExpr
  let headerSizeExpr = this.io.readU4le()
  this.headerSize = headerSizeExpr
  let crc32HeaderExpr = this.io.readU4le()
  this.crc32Header = crc32HeaderExpr
  let reservedExpr = this.io.readU4le()
  this.reserved = reservedExpr
  let currentLbaExpr = this.io.readU8le()
  this.currentLba = currentLbaExpr
  let backupLbaExpr = this.io.readU8le()
  this.backupLba = backupLbaExpr
  let firstUsableLbaExpr = this.io.readU8le()
  this.firstUsableLba = firstUsableLbaExpr
  let lastUsableLbaExpr = this.io.readU8le()
  this.lastUsableLba = lastUsableLbaExpr
  let diskGuidExpr = this.io.readBytes(int(16))
  this.diskGuid = diskGuidExpr
  let entriesStartExpr = this.io.readU8le()
  this.entriesStart = entriesStartExpr
  let entriesCountExpr = this.io.readU4le()
  this.entriesCount = entriesCountExpr
  let entriesSizeExpr = this.io.readU4le()
  this.entriesSize = entriesSizeExpr
  let crc32ArrayExpr = this.io.readU4le()
  this.crc32Array = crc32ArrayExpr

proc entries(this: GptPartitionTable_PartitionHeader): seq[GptPartitionTable_PartitionEntry] = 
  if this.entriesInstFlag:
    return this.entriesInst
  let io = GptPartitionTable(this.root).io
  let pos = io.pos()
  io.seek(int((this.entriesStart * GptPartitionTable(this.root).sectorSize)))
  for i in 0 ..< int(this.entriesCount):
    let buf = io.readBytes(int(this.entriesSize))
    this.rawEntriesInst.add(buf)
    let rawEntriesInstIo = newKaitaiStream(buf)
    let it = GptPartitionTable_PartitionEntry.read(rawEntriesInstIo, this.root, this)
    this.entriesInst.add(it)
  io.seek(pos)
  this.entriesInstFlag = true
  return this.entriesInst

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