Variable length quantity, unsigned integer, base128, big-endian: Go parsing library

A variable-length unsigned integer using base128 encoding. 1-byte groups consist of 1-bit flag of continuation and 7-bit value chunk, and are ordered "most significant group first", i.e. in "big-endian" manner.

This particular encoding is specified and used in:

  • Standard MIDI file format
  • ASN.1 BER encoding
  • RAR 5.0 file format

More information on this encoding is available at https://en.wikipedia.org/wiki/Variable-length_quantity

This particular implementation supports serialized values to up 8 bytes long.

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of Variable length quantity, unsigned integer, base128, big-endian using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse Variable length quantity, unsigned integer, base128, big-endian

vlq_base128_be.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import "github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"


/**
 * A variable-length unsigned integer using base128 encoding. 1-byte groups
 * consist of 1-bit flag of continuation and 7-bit value chunk, and are ordered
 * "most significant group first", i.e. in "big-endian" manner.
 * 
 * This particular encoding is specified and used in:
 * 
 * * Standard MIDI file format
 * * ASN.1 BER encoding
 * * RAR 5.0 file format
 * 
 * More information on this encoding is available at
 * <https://en.wikipedia.org/wiki/Variable-length_quantity>
 * 
 * This particular implementation supports serialized values to up 8 bytes long.
 */
type VlqBase128Be struct {
	Groups []*VlqBase128Be_Group
	_io *kaitai.Stream
	_root *VlqBase128Be
	_parent kaitai.Struct
	_f_last bool
	last int
	_f_value bool
	value uint64
}
func NewVlqBase128Be() *VlqBase128Be {
	return &VlqBase128Be{
	}
}

func (this VlqBase128Be) IO_() *kaitai.Stream {
	return this._io
}

func (this *VlqBase128Be) Read(io *kaitai.Stream, parent kaitai.Struct, root *VlqBase128Be) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 1;; i++ {
		tmp1 := NewVlqBase128Be_Group()
		err = tmp1.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		_it := tmp1
		this.Groups = append(this.Groups, _it)
		if !(_it.HasNext) {
			break
		}
	}
	return err
}
func (this *VlqBase128Be) Last() (v int, err error) {
	if (this._f_last) {
		return this.last, nil
	}
	this._f_last = true
	this.last = int(len(this.Groups) - 1)
	return this.last, nil
}

/**
 * Resulting value as normal integer
 */
func (this *VlqBase128Be) Value() (v uint64, err error) {
	if (this._f_value) {
		return this.value, nil
	}
	this._f_value = true
	tmp2, err := this.Last()
	if err != nil {
		return 0, err
	}
	var tmp3 int;
	tmp4, err := this.Last()
	if err != nil {
		return 0, err
	}
	if (tmp4 >= 1) {
		tmp5, err := this.Last()
		if err != nil {
			return 0, err
		}
		tmp3 = this.Groups[tmp5 - 1].Value << 7
	} else {
		tmp3 = 0
	}
	var tmp6 int;
	tmp7, err := this.Last()
	if err != nil {
		return 0, err
	}
	if (tmp7 >= 2) {
		tmp8, err := this.Last()
		if err != nil {
			return 0, err
		}
		tmp6 = this.Groups[tmp8 - 2].Value << 14
	} else {
		tmp6 = 0
	}
	var tmp9 int;
	tmp10, err := this.Last()
	if err != nil {
		return 0, err
	}
	if (tmp10 >= 3) {
		tmp11, err := this.Last()
		if err != nil {
			return 0, err
		}
		tmp9 = this.Groups[tmp11 - 3].Value << 21
	} else {
		tmp9 = 0
	}
	var tmp12 int;
	tmp13, err := this.Last()
	if err != nil {
		return 0, err
	}
	if (tmp13 >= 4) {
		tmp14, err := this.Last()
		if err != nil {
			return 0, err
		}
		tmp12 = this.Groups[tmp14 - 4].Value << 28
	} else {
		tmp12 = 0
	}
	var tmp15 int;
	tmp16, err := this.Last()
	if err != nil {
		return 0, err
	}
	if (tmp16 >= 5) {
		tmp17, err := this.Last()
		if err != nil {
			return 0, err
		}
		tmp15 = this.Groups[tmp17 - 5].Value << 35
	} else {
		tmp15 = 0
	}
	var tmp18 int;
	tmp19, err := this.Last()
	if err != nil {
		return 0, err
	}
	if (tmp19 >= 6) {
		tmp20, err := this.Last()
		if err != nil {
			return 0, err
		}
		tmp18 = this.Groups[tmp20 - 6].Value << 42
	} else {
		tmp18 = 0
	}
	var tmp21 int;
	tmp22, err := this.Last()
	if err != nil {
		return 0, err
	}
	if (tmp22 >= 7) {
		tmp23, err := this.Last()
		if err != nil {
			return 0, err
		}
		tmp21 = this.Groups[tmp23 - 7].Value << 49
	} else {
		tmp21 = 0
	}
	this.value = uint64(uint64(((((((this.Groups[tmp2].Value + tmp3) + tmp6) + tmp9) + tmp12) + tmp15) + tmp18) + tmp21))
	return this.value, nil
}

/**
 * One byte group, clearly divided into 7-bit "value" chunk and 1-bit "continuation" flag.
 */
type VlqBase128Be_Group struct {
	HasNext bool
	Value uint64
	_io *kaitai.Stream
	_root *VlqBase128Be
	_parent *VlqBase128Be
}
func NewVlqBase128Be_Group() *VlqBase128Be_Group {
	return &VlqBase128Be_Group{
	}
}

func (this VlqBase128Be_Group) IO_() *kaitai.Stream {
	return this._io
}

func (this *VlqBase128Be_Group) Read(io *kaitai.Stream, parent *VlqBase128Be, root *VlqBase128Be) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp24, err := this._io.ReadBitsIntBe(1)
	if err != nil {
		return err
	}
	this.HasNext = tmp24 != 0
	tmp25, err := this._io.ReadBitsIntBe(7)
	if err != nil {
		return err
	}
	this.Value = tmp25
	return err
}

/**
 * If true, then we have more bytes to read
 */

/**
 * The 7-bit (base128) numeric value chunk of this group
 */