BCD (Binary Coded Decimals) is a common way to encode integer numbers in a way that makes human-readable output somewhat simpler. In this encoding scheme, every decimal digit is encoded as either a single byte (8 bits), or a nibble (half of a byte, 4 bits). This obviously wastes a lot of bits, but it makes translation into human-readable string much easier than traditional binary-to-decimal conversion process, which includes lots of divisions by 10.
For example, encoding integer 31337 in 8-digit, 8 bits per digit, big endian order of digits BCD format yields
00 00 00 03 01 03 03 07
Encoding the same integer as 8-digit, 4 bits per digit, little endian order BCD format would yield:
73 31 30 00
Using this type of encoding in Kaitai Struct is pretty
straightforward: one calls for this type, specifying desired
encoding parameters, and gets result using either as_int
or
as_str
attributes.
This page hosts a formal specification of BCD (Binary Coded Decimals) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import "github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
/**
* BCD (Binary Coded Decimals) is a common way to encode integer
* numbers in a way that makes human-readable output somewhat
* simpler. In this encoding scheme, every decimal digit is encoded as
* either a single byte (8 bits), or a nibble (half of a byte, 4
* bits). This obviously wastes a lot of bits, but it makes translation
* into human-readable string much easier than traditional
* binary-to-decimal conversion process, which includes lots of
* divisions by 10.
*
* For example, encoding integer 31337 in 8-digit, 8 bits per digit,
* big endian order of digits BCD format yields
*
* ```
* 00 00 00 03 01 03 03 07
* ```
*
* Encoding the same integer as 8-digit, 4 bits per digit, little
* endian order BCD format would yield:
*
* ```
* 73 31 30 00
* ```
*
* Using this type of encoding in Kaitai Struct is pretty
* straightforward: one calls for this type, specifying desired
* encoding parameters, and gets result using either `as_int` or
* `as_str` attributes.
*/
type Bcd struct {
Digits []int
NumDigits uint8
BitsPerDigit uint8
IsLe bool
_io *kaitai.Stream
_root *Bcd
_parent kaitai.Struct
_f_asInt bool
asInt int
_f_asIntBe bool
asIntBe int
_f_asIntLe bool
asIntLe int
_f_lastIdx bool
lastIdx int
}
func NewBcd(numDigits uint8, bitsPerDigit uint8, isLe bool) *Bcd {
return &Bcd{
NumDigits: numDigits,
BitsPerDigit: bitsPerDigit,
IsLe: isLe,
}
}
func (this Bcd) IO_() *kaitai.Stream {
return this._io
}
func (this *Bcd) Read(io *kaitai.Stream, parent kaitai.Struct, root *Bcd) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 0; i < int(this.NumDigits); i++ {
_ = i
switch (this.BitsPerDigit) {
case 4:
tmp1, err := this._io.ReadBitsIntBe(4)
if err != nil {
return err
}
this.Digits = append(this.Digits, tmp1)
case 8:
tmp2, err := this._io.ReadU1()
if err != nil {
return err
}
this.Digits = append(this.Digits, tmp2)
}
}
return err
}
/**
* Value of this BCD number as integer. Endianness would be selected based on `is_le` parameter given.
*/
func (this *Bcd) AsInt() (v int, err error) {
if (this._f_asInt) {
return this.asInt, nil
}
this._f_asInt = true
var tmp3 int;
if (this.IsLe) {
tmp4, err := this.AsIntLe()
if err != nil {
return 0, err
}
tmp3 = tmp4
} else {
tmp5, err := this.AsIntBe()
if err != nil {
return 0, err
}
tmp3 = tmp5
}
this.asInt = int(tmp3)
return this.asInt, nil
}
/**
* Value of this BCD number as integer (treating digit order as big-endian).
*/
func (this *Bcd) AsIntBe() (v int, err error) {
if (this._f_asIntBe) {
return this.asIntBe, nil
}
this._f_asIntBe = true
tmp6, err := this.LastIdx()
if err != nil {
return 0, err
}
var tmp7 int8;
if (this.NumDigits < 2) {
tmp7 = 0
} else {
tmp8, err := this.LastIdx()
if err != nil {
return 0, err
}
var tmp9 int8;
if (this.NumDigits < 3) {
tmp9 = 0
} else {
tmp10, err := this.LastIdx()
if err != nil {
return 0, err
}
var tmp11 int8;
if (this.NumDigits < 4) {
tmp11 = 0
} else {
tmp12, err := this.LastIdx()
if err != nil {
return 0, err
}
var tmp13 int8;
if (this.NumDigits < 5) {
tmp13 = 0
} else {
tmp14, err := this.LastIdx()
if err != nil {
return 0, err
}
var tmp15 int8;
if (this.NumDigits < 6) {
tmp15 = 0
} else {
tmp16, err := this.LastIdx()
if err != nil {
return 0, err
}
var tmp17 int8;
if (this.NumDigits < 7) {
tmp17 = 0
} else {
tmp18, err := this.LastIdx()
if err != nil {
return 0, err
}
var tmp19 int8;
if (this.NumDigits < 8) {
tmp19 = 0
} else {
tmp20, err := this.LastIdx()
if err != nil {
return 0, err
}
tmp19 = this.Digits[tmp20 - 7] * 10000000
}
tmp17 = this.Digits[tmp18 - 6] * 1000000 + tmp19
}
tmp15 = this.Digits[tmp16 - 5] * 100000 + tmp17
}
tmp13 = this.Digits[tmp14 - 4] * 10000 + tmp15
}
tmp11 = this.Digits[tmp12 - 3] * 1000 + tmp13
}
tmp9 = this.Digits[tmp10 - 2] * 100 + tmp11
}
tmp7 = this.Digits[tmp8 - 1] * 10 + tmp9
}
this.asIntBe = int(this.Digits[tmp6] + tmp7)
return this.asIntBe, nil
}
/**
* Value of this BCD number as integer (treating digit order as little-endian).
*/
func (this *Bcd) AsIntLe() (v int, err error) {
if (this._f_asIntLe) {
return this.asIntLe, nil
}
this._f_asIntLe = true
var tmp21 int8;
if (this.NumDigits < 2) {
tmp21 = 0
} else {
var tmp22 int8;
if (this.NumDigits < 3) {
tmp22 = 0
} else {
var tmp23 int8;
if (this.NumDigits < 4) {
tmp23 = 0
} else {
var tmp24 int8;
if (this.NumDigits < 5) {
tmp24 = 0
} else {
var tmp25 int8;
if (this.NumDigits < 6) {
tmp25 = 0
} else {
var tmp26 int8;
if (this.NumDigits < 7) {
tmp26 = 0
} else {
var tmp27 int8;
if (this.NumDigits < 8) {
tmp27 = 0
} else {
tmp27 = this.Digits[7] * 10000000
}
tmp26 = this.Digits[6] * 1000000 + tmp27
}
tmp25 = this.Digits[5] * 100000 + tmp26
}
tmp24 = this.Digits[4] * 10000 + tmp25
}
tmp23 = this.Digits[3] * 1000 + tmp24
}
tmp22 = this.Digits[2] * 100 + tmp23
}
tmp21 = this.Digits[1] * 10 + tmp22
}
this.asIntLe = int(this.Digits[0] + tmp21)
return this.asIntLe, nil
}
/**
* Index of last digit (0-based).
*/
func (this *Bcd) LastIdx() (v int, err error) {
if (this._f_lastIdx) {
return this.lastIdx, nil
}
this._f_lastIdx = true
this.lastIdx = int(this.NumDigits - 1)
return this.lastIdx, nil
}