Mifare Classic RFID tag dump: Nim parsing library

You can get a dump for testing from this link: https://github.com/zhovner/mfdread/raw/master/dump.mfd

File extension

mfd

KS implementation details

License: BSD-2-Clause
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of Mifare Classic RFID tag dump 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 Mifare Classic RFID tag dump

mifare_classic.nim

import kaitai_struct_nim_runtime
import options

type
  MifareClassic* = ref object of KaitaiStruct
    `sectors`*: seq[MifareClassic_Sector]
    `parent`*: KaitaiStruct
    `rawSectors`*: seq[seq[byte]]
  MifareClassic_Key* = ref object of KaitaiStruct
    `key`*: seq[byte]
    `parent`*: MifareClassic_Trailer
  MifareClassic_Sector* = ref object of KaitaiStruct
    `manufacturer`*: MifareClassic_Manufacturer
    `dataFiller`*: MifareClassic_Sector_Filler
    `trailer`*: MifareClassic_Trailer
    `hasManufacturer`*: bool
    `parent`*: MifareClassic
    `rawDataFiller`*: seq[byte]
    `blockSizeInst`: int8
    `blockSizeInstFlag`: bool
    `dataInst`: seq[byte]
    `dataInstFlag`: bool
    `blocksInst`: seq[seq[byte]]
    `blocksInstFlag`: bool
    `valuesInst`: MifareClassic_Sector_Values
    `valuesInstFlag`: bool
  MifareClassic_Sector_Values* = ref object of KaitaiStruct
    `values`*: seq[MifareClassic_Sector_Values_ValueBlock]
    `parent`*: MifareClassic_Sector
  MifareClassic_Sector_Values_ValueBlock* = ref object of KaitaiStruct
    `valuez`*: seq[uint32]
    `addrz`*: seq[uint8]
    `parent`*: MifareClassic_Sector_Values
    `addrInst`: uint8
    `addrInstFlag`: bool
    `addrValidInst`: bool
    `addrValidInstFlag`: bool
    `validInst`: bool
    `validInstFlag`: bool
    `valueValidInst`: bool
    `valueValidInstFlag`: bool
    `valueInst`: uint32
    `valueInstFlag`: bool
  MifareClassic_Sector_Filler* = ref object of KaitaiStruct
    `data`*: seq[byte]
    `parent`*: MifareClassic_Sector
  MifareClassic_Manufacturer* = ref object of KaitaiStruct
    `nuid`*: uint32
    `bcc`*: uint8
    `sak`*: uint8
    `atqa`*: uint16
    `manufacturer`*: seq[byte]
    `parent`*: MifareClassic_Sector
  MifareClassic_Trailer* = ref object of KaitaiStruct
    `keyA`*: MifareClassic_Key
    `accessBits`*: MifareClassic_Trailer_AccessConditions
    `userByte`*: uint8
    `keyB`*: MifareClassic_Key
    `parent`*: MifareClassic_Sector
    `rawAccessBits`*: seq[byte]
    `acBitsInst`: int8
    `acBitsInstFlag`: bool
    `acsInSectorInst`: int8
    `acsInSectorInstFlag`: bool
    `acCountOfChunksInst`: int
    `acCountOfChunksInstFlag`: bool
  MifareClassic_Trailer_AccessConditions* = ref object of KaitaiStruct
    `rawChunks`*: seq[uint64]
    `parent`*: MifareClassic_Trailer
    `dataAcsInst`: seq[MifareClassic_Trailer_AccessConditions_DataAc]
    `dataAcsInstFlag`: bool
    `remapsInst`: seq[MifareClassic_Trailer_AccessConditions_ChunkBitRemap]
    `remapsInstFlag`: bool
    `acsRawInst`: seq[MifareClassic_Trailer_AccessConditions_Ac]
    `acsRawInstFlag`: bool
    `trailerAcInst`: MifareClassic_Trailer_AccessConditions_TrailerAc
    `trailerAcInstFlag`: bool
    `chunksInst`: seq[MifareClassic_Trailer_AccessConditions_ValidChunk]
    `chunksInstFlag`: bool
  MifareClassic_Trailer_AccessConditions_TrailerAc* = ref object of KaitaiStruct
    `ac`*: MifareClassic_Trailer_AccessConditions_Ac
    `parent`*: MifareClassic_Trailer_AccessConditions
    `canReadKeyBInst`: bool
    `canReadKeyBInstFlag`: bool
    `canWriteKeysInst`: bool
    `canWriteKeysInstFlag`: bool
    `canWriteAccessBitsInst`: bool
    `canWriteAccessBitsInstFlag`: bool
    `keyBControlsWriteInst`: bool
    `keyBControlsWriteInstFlag`: bool
  MifareClassic_Trailer_AccessConditions_ChunkBitRemap* = ref object of KaitaiStruct
    `bitNo`*: uint8
    `parent`*: MifareClassic_Trailer_AccessConditions
    `shiftValueInst`: int
    `shiftValueInstFlag`: bool
    `chunkNoInst`: int
    `chunkNoInstFlag`: bool
    `invChunkNoInst`: int
    `invChunkNoInstFlag`: bool
  MifareClassic_Trailer_AccessConditions_DataAc* = ref object of KaitaiStruct
    `ac`*: MifareClassic_Trailer_AccessConditions_Ac
    `parent`*: MifareClassic_Trailer_AccessConditions
    `readKeyARequiredInst`: bool
    `readKeyARequiredInstFlag`: bool
    `writeKeyBRequiredInst`: bool
    `writeKeyBRequiredInstFlag`: bool
    `writeKeyARequiredInst`: bool
    `writeKeyARequiredInstFlag`: bool
    `readKeyBRequiredInst`: bool
    `readKeyBRequiredInstFlag`: bool
    `decrementAvailableInst`: bool
    `decrementAvailableInstFlag`: bool
    `incrementAvailableInst`: bool
    `incrementAvailableInstFlag`: bool
  MifareClassic_Trailer_AccessConditions_Ac* = ref object of KaitaiStruct
    `index`*: uint8
    `parent`*: MifareClassic_Trailer_AccessConditions
    `bitsInst`: seq[MifareClassic_Trailer_AccessConditions_Ac_AcBit]
    `bitsInstFlag`: bool
    `valInst`: int
    `valInstFlag`: bool
    `invShiftValInst`: int
    `invShiftValInstFlag`: bool
  MifareClassic_Trailer_AccessConditions_Ac_AcBit* = ref object of KaitaiStruct
    `i`*: uint8
    `chunk`*: uint8
    `parent`*: MifareClassic_Trailer_AccessConditions_Ac
    `nInst`: int
    `nInstFlag`: bool
    `bInst`: bool
    `bInstFlag`: bool
  MifareClassic_Trailer_AccessConditions_ValidChunk* = ref object of KaitaiStruct
    `invChunk`*: uint8
    `chunk`*: uint8
    `parent`*: MifareClassic_Trailer_AccessConditions
    `validInst`: bool
    `validInstFlag`: bool

proc read*(_: typedesc[MifareClassic], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): MifareClassic
proc read*(_: typedesc[MifareClassic_Key], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer): MifareClassic_Key
proc read*(_: typedesc[MifareClassic_Sector], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic, hasManufacturer: any): MifareClassic_Sector
proc read*(_: typedesc[MifareClassic_Sector_Values], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Sector): MifareClassic_Sector_Values
proc read*(_: typedesc[MifareClassic_Sector_Values_ValueBlock], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Sector_Values): MifareClassic_Sector_Values_ValueBlock
proc read*(_: typedesc[MifareClassic_Sector_Filler], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Sector): MifareClassic_Sector_Filler
proc read*(_: typedesc[MifareClassic_Manufacturer], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Sector): MifareClassic_Manufacturer
proc read*(_: typedesc[MifareClassic_Trailer], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Sector): MifareClassic_Trailer
proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer): MifareClassic_Trailer_AccessConditions
proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_TrailerAc], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, ac: any): MifareClassic_Trailer_AccessConditions_TrailerAc
proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_ChunkBitRemap], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, bitNo: any): MifareClassic_Trailer_AccessConditions_ChunkBitRemap
proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_DataAc], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, ac: any): MifareClassic_Trailer_AccessConditions_DataAc
proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_Ac], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, index: any): MifareClassic_Trailer_AccessConditions_Ac
proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_Ac_AcBit], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions_Ac, i: any, chunk: any): MifareClassic_Trailer_AccessConditions_Ac_AcBit
proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_ValidChunk], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, invChunk: any, chunk: any): MifareClassic_Trailer_AccessConditions_ValidChunk

proc blockSize*(this: MifareClassic_Sector): int8
proc data*(this: MifareClassic_Sector): seq[byte]
proc blocks*(this: MifareClassic_Sector): seq[seq[byte]]
proc values*(this: MifareClassic_Sector): MifareClassic_Sector_Values
proc addr*(this: MifareClassic_Sector_Values_ValueBlock): uint8
proc addrValid*(this: MifareClassic_Sector_Values_ValueBlock): bool
proc valid*(this: MifareClassic_Sector_Values_ValueBlock): bool
proc valueValid*(this: MifareClassic_Sector_Values_ValueBlock): bool
proc value*(this: MifareClassic_Sector_Values_ValueBlock): uint32
proc acBits*(this: MifareClassic_Trailer): int8
proc acsInSector*(this: MifareClassic_Trailer): int8
proc acCountOfChunks*(this: MifareClassic_Trailer): int
proc dataAcs*(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_DataAc]
proc remaps*(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_ChunkBitRemap]
proc acsRaw*(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_Ac]
proc trailerAc*(this: MifareClassic_Trailer_AccessConditions): MifareClassic_Trailer_AccessConditions_TrailerAc
proc chunks*(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_ValidChunk]
proc canReadKeyB*(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool
proc canWriteKeys*(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool
proc canWriteAccessBits*(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool
proc keyBControlsWrite*(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool
proc shiftValue*(this: MifareClassic_Trailer_AccessConditions_ChunkBitRemap): int
proc chunkNo*(this: MifareClassic_Trailer_AccessConditions_ChunkBitRemap): int
proc invChunkNo*(this: MifareClassic_Trailer_AccessConditions_ChunkBitRemap): int
proc readKeyARequired*(this: MifareClassic_Trailer_AccessConditions_DataAc): bool
proc writeKeyBRequired*(this: MifareClassic_Trailer_AccessConditions_DataAc): bool
proc writeKeyARequired*(this: MifareClassic_Trailer_AccessConditions_DataAc): bool
proc readKeyBRequired*(this: MifareClassic_Trailer_AccessConditions_DataAc): bool
proc decrementAvailable*(this: MifareClassic_Trailer_AccessConditions_DataAc): bool
proc incrementAvailable*(this: MifareClassic_Trailer_AccessConditions_DataAc): bool
proc bits*(this: MifareClassic_Trailer_AccessConditions_Ac): seq[MifareClassic_Trailer_AccessConditions_Ac_AcBit]
proc val*(this: MifareClassic_Trailer_AccessConditions_Ac): int
proc invShiftVal*(this: MifareClassic_Trailer_AccessConditions_Ac): int
proc n*(this: MifareClassic_Trailer_AccessConditions_Ac_AcBit): int
proc b*(this: MifareClassic_Trailer_AccessConditions_Ac_AcBit): bool
proc valid*(this: MifareClassic_Trailer_AccessConditions_ValidChunk): bool


##[
You can get a dump for testing from this link:
<https://github.com/zhovner/mfdread/raw/master/dump.mfd>

@see <a href="https://github.com/nfc-tools/libnfc
https://www.nxp.com/docs/en/data-sheet/MF1S70YYX_V1.pdf
">Source</a>
]##
proc read*(_: typedesc[MifareClassic], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): MifareClassic =
  template this: untyped = result
  this = new(MifareClassic)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent

  block:
    var i: int
    while not this.io.isEof:
      let buf = this.io.readBytes(int((((if i >= 32: 4 else: 1) * 4) * 16)))
      this.rawSectors.add(buf)
      let rawSectorsIo = newKaitaiStream(buf)
      let it = MifareClassic_Sector.read(rawSectorsIo, this.root, this, i == 0)
      this.sectors.add(it)
      inc i

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

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

  let keyExpr = this.io.readBytes(int(6))
  this.key = keyExpr

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

proc read*(_: typedesc[MifareClassic_Sector], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic, hasManufacturer: any): MifareClassic_Sector =
  template this: untyped = result
  this = new(MifareClassic_Sector)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent
  let hasManufacturerExpr = bool(hasManufacturer)
  this.hasManufacturer = hasManufacturerExpr

  if this.hasManufacturer:
    let manufacturerExpr = MifareClassic_Manufacturer.read(this.io, this.root, this)
    this.manufacturer = manufacturerExpr
  let rawDataFillerExpr = this.io.readBytes(int(((this.io.size - this.io.pos) - 16)))
  this.rawDataFiller = rawDataFillerExpr
  let rawDataFillerIo = newKaitaiStream(rawDataFillerExpr)
  let dataFillerExpr = MifareClassic_Sector_Filler.read(rawDataFillerIo, this.root, this)
  this.dataFiller = dataFillerExpr
  let trailerExpr = MifareClassic_Trailer.read(this.io, this.root, this)
  this.trailer = trailerExpr

proc blockSize(this: MifareClassic_Sector): int8 = 
  if this.blockSizeInstFlag:
    return this.blockSizeInst
  let blockSizeInstExpr = int8(16)
  this.blockSizeInst = blockSizeInstExpr
  this.blockSizeInstFlag = true
  return this.blockSizeInst

proc data(this: MifareClassic_Sector): seq[byte] = 
  if this.dataInstFlag:
    return this.dataInst
  let dataInstExpr = seq[byte](this.dataFiller.data)
  this.dataInst = dataInstExpr
  this.dataInstFlag = true
  return this.dataInst

proc blocks(this: MifareClassic_Sector): seq[seq[byte]] = 
  if this.blocksInstFlag:
    return this.blocksInst
  let io = this.dataFiller.io
  let pos = io.pos()
  io.seek(int(0))
  block:
    var i: int
    while not io.isEof:
      let it = io.readBytes(int(this.blockSize))
      this.blocksInst.add(it)
      inc i
  io.seek(pos)
  this.blocksInstFlag = true
  return this.blocksInst

proc values(this: MifareClassic_Sector): MifareClassic_Sector_Values = 
  if this.valuesInstFlag:
    return this.valuesInst
  let io = this.dataFiller.io
  let pos = io.pos()
  io.seek(int(0))
  let valuesInstExpr = MifareClassic_Sector_Values.read(io, this.root, this)
  this.valuesInst = valuesInstExpr
  io.seek(pos)
  this.valuesInstFlag = true
  return this.valuesInst

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

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

  block:
    var i: int
    while not this.io.isEof:
      let it = MifareClassic_Sector_Values_ValueBlock.read(this.io, this.root, this)
      this.values.add(it)
      inc i

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

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

  for i in 0 ..< int(3):
    let it = this.io.readU4le()
    this.valuez.add(it)
  for i in 0 ..< int(4):
    let it = this.io.readU1()
    this.addrz.add(it)

proc addr(this: MifareClassic_Sector_Values_ValueBlock): uint8 = 
  if this.addrInstFlag:
    return this.addrInst
  if this.valid:
    let addrInstExpr = uint8(this.addrz[0])
    this.addrInst = addrInstExpr
  this.addrInstFlag = true
  return this.addrInst

proc addrValid(this: MifareClassic_Sector_Values_ValueBlock): bool = 
  if this.addrValidInstFlag:
    return this.addrValidInst
  let addrValidInstExpr = bool( ((this.addrz[0] == not(this.addrz[1])) and (this.addrz[0] == this.addrz[2]) and (this.addrz[1] == this.addrz[3])) )
  this.addrValidInst = addrValidInstExpr
  this.addrValidInstFlag = true
  return this.addrValidInst

proc valid(this: MifareClassic_Sector_Values_ValueBlock): bool = 
  if this.validInstFlag:
    return this.validInst
  let validInstExpr = bool( ((this.valueValid) and (this.addrValid)) )
  this.validInst = validInstExpr
  this.validInstFlag = true
  return this.validInst

proc valueValid(this: MifareClassic_Sector_Values_ValueBlock): bool = 
  if this.valueValidInstFlag:
    return this.valueValidInst
  let valueValidInstExpr = bool( ((this.valuez[0] == not(this.valuez[1])) and (this.valuez[0] == this.valuez[2])) )
  this.valueValidInst = valueValidInstExpr
  this.valueValidInstFlag = true
  return this.valueValidInst

proc value(this: MifareClassic_Sector_Values_ValueBlock): uint32 = 
  if this.valueInstFlag:
    return this.valueInst
  if this.valid:
    let valueInstExpr = uint32(this.valuez[0])
    this.valueInst = valueInstExpr
  this.valueInstFlag = true
  return this.valueInst

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


##[
only to create _io
]##
proc read*(_: typedesc[MifareClassic_Sector_Filler], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Sector): MifareClassic_Sector_Filler =
  template this: untyped = result
  this = new(MifareClassic_Sector_Filler)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent

  let dataExpr = this.io.readBytes(int(this.io.size))
  this.data = dataExpr

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

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


  ##[
  beware for 7bytes UID it goes over next fields
  ]##
  let nuidExpr = this.io.readU4le()
  this.nuid = nuidExpr
  let bccExpr = this.io.readU1()
  this.bcc = bccExpr
  let sakExpr = this.io.readU1()
  this.sak = sakExpr
  let atqaExpr = this.io.readU2le()
  this.atqa = atqaExpr

  ##[
  may contain manufacture date as BCD
  ]##
  let manufacturerExpr = this.io.readBytes(int(8))
  this.manufacturer = manufacturerExpr

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

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

  let keyAExpr = MifareClassic_Key.read(this.io, this.root, this)
  this.keyA = keyAExpr
  let rawAccessBitsExpr = this.io.readBytes(int(3))
  this.rawAccessBits = rawAccessBitsExpr
  let rawAccessBitsIo = newKaitaiStream(rawAccessBitsExpr)
  let accessBitsExpr = MifareClassic_Trailer_AccessConditions.read(rawAccessBitsIo, this.root, this)
  this.accessBits = accessBitsExpr
  let userByteExpr = this.io.readU1()
  this.userByte = userByteExpr
  let keyBExpr = MifareClassic_Key.read(this.io, this.root, this)
  this.keyB = keyBExpr

proc acBits(this: MifareClassic_Trailer): int8 = 
  if this.acBitsInstFlag:
    return this.acBitsInst
  let acBitsInstExpr = int8(3)
  this.acBitsInst = acBitsInstExpr
  this.acBitsInstFlag = true
  return this.acBitsInst

proc acsInSector(this: MifareClassic_Trailer): int8 = 
  if this.acsInSectorInstFlag:
    return this.acsInSectorInst
  let acsInSectorInstExpr = int8(4)
  this.acsInSectorInst = acsInSectorInstExpr
  this.acsInSectorInstFlag = true
  return this.acsInSectorInst

proc acCountOfChunks(this: MifareClassic_Trailer): int = 
  if this.acCountOfChunksInstFlag:
    return this.acCountOfChunksInst
  let acCountOfChunksInstExpr = int((this.acBits * 2))
  this.acCountOfChunksInst = acCountOfChunksInstExpr
  this.acCountOfChunksInstFlag = true
  return this.acCountOfChunksInst

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

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

  for i in 0 ..< int(this.parent.acCountOfChunks):
    let it = this.io.readBitsIntBe(4)
    this.rawChunks.add(it)

proc dataAcs(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_DataAc] = 
  if this.dataAcsInstFlag:
    return this.dataAcsInst
  let pos = this.io.pos()
  this.io.seek(int(0))
  for i in 0 ..< int((this.parent.acsInSector - 1)):
    let it = MifareClassic_Trailer_AccessConditions_DataAc.read(this.io, this.root, this, this.acsRaw[i])
    this.dataAcsInst.add(it)
  this.io.seek(pos)
  this.dataAcsInstFlag = true
  return this.dataAcsInst

proc remaps(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_ChunkBitRemap] = 
  if this.remapsInstFlag:
    return this.remapsInst
  let pos = this.io.pos()
  this.io.seek(int(0))
  for i in 0 ..< int(this.parent.acBits):
    let it = MifareClassic_Trailer_AccessConditions_ChunkBitRemap.read(this.io, this.root, this, i)
    this.remapsInst.add(it)
  this.io.seek(pos)
  this.remapsInstFlag = true
  return this.remapsInst

proc acsRaw(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_Ac] = 
  if this.acsRawInstFlag:
    return this.acsRawInst
  let pos = this.io.pos()
  this.io.seek(int(0))
  for i in 0 ..< int(this.parent.acsInSector):
    let it = MifareClassic_Trailer_AccessConditions_Ac.read(this.io, this.root, this, i)
    this.acsRawInst.add(it)
  this.io.seek(pos)
  this.acsRawInstFlag = true
  return this.acsRawInst

proc trailerAc(this: MifareClassic_Trailer_AccessConditions): MifareClassic_Trailer_AccessConditions_TrailerAc = 
  if this.trailerAcInstFlag:
    return this.trailerAcInst
  let pos = this.io.pos()
  this.io.seek(int(0))
  let trailerAcInstExpr = MifareClassic_Trailer_AccessConditions_TrailerAc.read(this.io, this.root, this, this.acsRaw[(this.parent.acsInSector - 1)])
  this.trailerAcInst = trailerAcInstExpr
  this.io.seek(pos)
  this.trailerAcInstFlag = true
  return this.trailerAcInst

proc chunks(this: MifareClassic_Trailer_AccessConditions): seq[MifareClassic_Trailer_AccessConditions_ValidChunk] = 
  if this.chunksInstFlag:
    return this.chunksInst
  let pos = this.io.pos()
  this.io.seek(int(0))
  for i in 0 ..< int(this.parent.acBits):
    let it = MifareClassic_Trailer_AccessConditions_ValidChunk.read(this.io, this.root, this, this.rawChunks[this.remaps[i].invChunkNo], this.rawChunks[this.remaps[i].chunkNo])
    this.chunksInst.add(it)
  this.io.seek(pos)
  this.chunksInstFlag = true
  return this.chunksInst

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

proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_TrailerAc], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, ac: any): MifareClassic_Trailer_AccessConditions_TrailerAc =
  template this: untyped = result
  this = new(MifareClassic_Trailer_AccessConditions_TrailerAc)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent
  let acExpr = MifareClassic_Trailer_AccessConditions_Ac(ac)
  this.ac = acExpr


proc canReadKeyB(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool = 

  ##[
  key A is required
  ]##
  if this.canReadKeyBInstFlag:
    return this.canReadKeyBInst
  let canReadKeyBInstExpr = bool(this.ac.invShiftVal <= 2)
  this.canReadKeyBInst = canReadKeyBInstExpr
  this.canReadKeyBInstFlag = true
  return this.canReadKeyBInst

proc canWriteKeys(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool = 
  if this.canWriteKeysInstFlag:
    return this.canWriteKeysInst
  let canWriteKeysInstExpr = bool( ((((this.ac.invShiftVal + 1) %%% 3) != 0) and (this.ac.invShiftVal < 6)) )
  this.canWriteKeysInst = canWriteKeysInstExpr
  this.canWriteKeysInstFlag = true
  return this.canWriteKeysInst

proc canWriteAccessBits(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool = 
  if this.canWriteAccessBitsInstFlag:
    return this.canWriteAccessBitsInst
  let canWriteAccessBitsInstExpr = bool(this.ac.bits[2].b)
  this.canWriteAccessBitsInst = canWriteAccessBitsInstExpr
  this.canWriteAccessBitsInstFlag = true
  return this.canWriteAccessBitsInst

proc keyBControlsWrite(this: MifareClassic_Trailer_AccessConditions_TrailerAc): bool = 
  if this.keyBControlsWriteInstFlag:
    return this.keyBControlsWriteInst
  let keyBControlsWriteInstExpr = bool(not(this.canReadKeyB))
  this.keyBControlsWriteInst = keyBControlsWriteInstExpr
  this.keyBControlsWriteInstFlag = true
  return this.keyBControlsWriteInst

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

proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_ChunkBitRemap], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, bitNo: any): MifareClassic_Trailer_AccessConditions_ChunkBitRemap =
  template this: untyped = result
  this = new(MifareClassic_Trailer_AccessConditions_ChunkBitRemap)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent
  let bitNoExpr = uint8(bitNo)
  this.bitNo = bitNoExpr


proc shiftValue(this: MifareClassic_Trailer_AccessConditions_ChunkBitRemap): int = 
  if this.shiftValueInstFlag:
    return this.shiftValueInst
  let shiftValueInstExpr = int((if this.bitNo == 1: -1 else: 1))
  this.shiftValueInst = shiftValueInstExpr
  this.shiftValueInstFlag = true
  return this.shiftValueInst

proc chunkNo(this: MifareClassic_Trailer_AccessConditions_ChunkBitRemap): int = 
  if this.chunkNoInstFlag:
    return this.chunkNoInst
  let chunkNoInstExpr = int((((this.invChunkNo + this.shiftValue) + this.parent.parent.acCountOfChunks) %%% this.parent.parent.acCountOfChunks))
  this.chunkNoInst = chunkNoInstExpr
  this.chunkNoInstFlag = true
  return this.chunkNoInst

proc invChunkNo(this: MifareClassic_Trailer_AccessConditions_ChunkBitRemap): int = 
  if this.invChunkNoInstFlag:
    return this.invChunkNoInst
  let invChunkNoInstExpr = int((this.bitNo + this.shiftValue))
  this.invChunkNoInst = invChunkNoInstExpr
  this.invChunkNoInstFlag = true
  return this.invChunkNoInst

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

proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_DataAc], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, ac: any): MifareClassic_Trailer_AccessConditions_DataAc =
  template this: untyped = result
  this = new(MifareClassic_Trailer_AccessConditions_DataAc)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent
  let acExpr = MifareClassic_Trailer_AccessConditions_Ac(ac)
  this.ac = acExpr


proc readKeyARequired(this: MifareClassic_Trailer_AccessConditions_DataAc): bool = 
  if this.readKeyARequiredInstFlag:
    return this.readKeyARequiredInst
  let readKeyARequiredInstExpr = bool(this.ac.val <= 4)
  this.readKeyARequiredInst = readKeyARequiredInstExpr
  this.readKeyARequiredInstFlag = true
  return this.readKeyARequiredInst

proc writeKeyBRequired(this: MifareClassic_Trailer_AccessConditions_DataAc): bool = 
  if this.writeKeyBRequiredInstFlag:
    return this.writeKeyBRequiredInst
  let writeKeyBRequiredInstExpr = bool( (( ((not(this.readKeyARequired)) or (this.readKeyBRequired)) ) and (not(this.ac.bits[0].b))) )
  this.writeKeyBRequiredInst = writeKeyBRequiredInstExpr
  this.writeKeyBRequiredInstFlag = true
  return this.writeKeyBRequiredInst

proc writeKeyARequired(this: MifareClassic_Trailer_AccessConditions_DataAc): bool = 
  if this.writeKeyARequiredInstFlag:
    return this.writeKeyARequiredInst
  let writeKeyARequiredInstExpr = bool(this.ac.val == 0)
  this.writeKeyARequiredInst = writeKeyARequiredInstExpr
  this.writeKeyARequiredInstFlag = true
  return this.writeKeyARequiredInst

proc readKeyBRequired(this: MifareClassic_Trailer_AccessConditions_DataAc): bool = 
  if this.readKeyBRequiredInstFlag:
    return this.readKeyBRequiredInst
  let readKeyBRequiredInstExpr = bool(this.ac.val <= 6)
  this.readKeyBRequiredInst = readKeyBRequiredInstExpr
  this.readKeyBRequiredInstFlag = true
  return this.readKeyBRequiredInst

proc decrementAvailable(this: MifareClassic_Trailer_AccessConditions_DataAc): bool = 
  if this.decrementAvailableInstFlag:
    return this.decrementAvailableInst
  let decrementAvailableInstExpr = bool( (( ((this.ac.bits[1].b) or (not(this.ac.bits[0].b))) ) and (not(this.ac.bits[2].b))) )
  this.decrementAvailableInst = decrementAvailableInstExpr
  this.decrementAvailableInstFlag = true
  return this.decrementAvailableInst

proc incrementAvailable(this: MifareClassic_Trailer_AccessConditions_DataAc): bool = 
  if this.incrementAvailableInstFlag:
    return this.incrementAvailableInst
  let incrementAvailableInstExpr = bool( (( ((not(this.ac.bits[0].b)) and (not(this.readKeyARequired)) and (not(this.readKeyBRequired))) ) or ( ((not(this.ac.bits[0].b)) and (this.readKeyARequired) and (this.readKeyBRequired)) )) )
  this.incrementAvailableInst = incrementAvailableInstExpr
  this.incrementAvailableInstFlag = true
  return this.incrementAvailableInst

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

proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_Ac], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, index: any): MifareClassic_Trailer_AccessConditions_Ac =
  template this: untyped = result
  this = new(MifareClassic_Trailer_AccessConditions_Ac)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent
  let indexExpr = uint8(index)
  this.index = indexExpr


proc bits(this: MifareClassic_Trailer_AccessConditions_Ac): seq[MifareClassic_Trailer_AccessConditions_Ac_AcBit] = 
  if this.bitsInstFlag:
    return this.bitsInst
  let pos = this.io.pos()
  this.io.seek(int(0))
  for i in 0 ..< int(this.parent.parent.acBits):
    let it = MifareClassic_Trailer_AccessConditions_Ac_AcBit.read(this.io, this.root, this, this.index, this.parent.chunks[i].chunk)
    this.bitsInst.add(it)
  this.io.seek(pos)
  this.bitsInstFlag = true
  return this.bitsInst

proc val(this: MifareClassic_Trailer_AccessConditions_Ac): int = 

  ##[
  c3 c2 c1
  ]##
  if this.valInstFlag:
    return this.valInst
  let valInstExpr = int((((this.bits[2].n shl 2) or (this.bits[1].n shl 1)) or this.bits[0].n))
  this.valInst = valInstExpr
  this.valInstFlag = true
  return this.valInst

proc invShiftVal(this: MifareClassic_Trailer_AccessConditions_Ac): int = 
  if this.invShiftValInstFlag:
    return this.invShiftValInst
  let invShiftValInstExpr = int((((this.bits[0].n shl 2) or (this.bits[1].n shl 1)) or this.bits[2].n))
  this.invShiftValInst = invShiftValInstExpr
  this.invShiftValInstFlag = true
  return this.invShiftValInst

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

proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_Ac_AcBit], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions_Ac, i: any, chunk: any): MifareClassic_Trailer_AccessConditions_Ac_AcBit =
  template this: untyped = result
  this = new(MifareClassic_Trailer_AccessConditions_Ac_AcBit)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent
  let iExpr = uint8(i)
  this.i = iExpr
  let chunkExpr = uint8(chunk)
  this.chunk = chunkExpr


proc n(this: MifareClassic_Trailer_AccessConditions_Ac_AcBit): int = 
  if this.nInstFlag:
    return this.nInst
  let nInstExpr = int(((this.chunk shr this.i) and 1))
  this.nInst = nInstExpr
  this.nInstFlag = true
  return this.nInst

proc b(this: MifareClassic_Trailer_AccessConditions_Ac_AcBit): bool = 
  if this.bInstFlag:
    return this.bInst
  let bInstExpr = bool(this.n == 1)
  this.bInst = bInstExpr
  this.bInstFlag = true
  return this.bInst

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

proc read*(_: typedesc[MifareClassic_Trailer_AccessConditions_ValidChunk], io: KaitaiStream, root: KaitaiStruct, parent: MifareClassic_Trailer_AccessConditions, invChunk: any, chunk: any): MifareClassic_Trailer_AccessConditions_ValidChunk =
  template this: untyped = result
  this = new(MifareClassic_Trailer_AccessConditions_ValidChunk)
  let root = if root == nil: cast[MifareClassic](this) else: cast[MifareClassic](root)
  this.io = io
  this.root = root
  this.parent = parent
  let invChunkExpr = uint8(invChunk)
  this.invChunk = invChunkExpr
  let chunkExpr = uint8(chunk)
  this.chunk = chunkExpr


proc valid(this: MifareClassic_Trailer_AccessConditions_ValidChunk): bool = 
  if this.validInstFlag:
    return this.validInst
  let validInstExpr = bool((this.invChunk xor this.chunk) == 15)
  this.validInst = validInstExpr
  this.validInstFlag = true
  return this.validInst

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