GRUB 2 font: Go parsing library

Bitmap font format for the GRUB 2 bootloader.

Application

GRUB 2

File extension

pf2

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of GRUB 2 font 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 GRUB 2 font

grub2_font.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"
	"bytes"
	"io"
)


/**
 * Bitmap font format for the GRUB 2 bootloader.
 * @see <a href="https://grub.gibibit.com/New_font_format">Source</a>
 */
type Grub2Font struct {
	Magic []byte
	Sections []*Grub2Font_Section
	_io *kaitai.Stream
	_root *Grub2Font
	_parent interface{}
}
func NewGrub2Font() *Grub2Font {
	return &Grub2Font{
	}
}

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

	tmp1, err := this._io.ReadBytes(int(12))
	if err != nil {
		return err
	}
	tmp1 = tmp1
	this.Magic = tmp1
	if !(bytes.Equal(this.Magic, []uint8{70, 73, 76, 69, 0, 0, 0, 4, 80, 70, 70, 50})) {
		return kaitai.NewValidationNotEqualError([]uint8{70, 73, 76, 69, 0, 0, 0, 4, 80, 70, 70, 50}, this.Magic, this._io, "/seq/0")
	}
	for i := 1;; i++ {
		tmp2 := NewGrub2Font_Section()
		err = tmp2.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		_it := tmp2
		this.Sections = append(this.Sections, _it)
		if _it.SectionType == "DATA" {
			break
		}
	}
	return err
}

/**
 * The "DATA" section acts as a terminator. The documentation says:
 * "A marker that indicates the remainder of the file is data accessed
 * via the character index (CHIX) section. When reading this font file,
 * the rest of the file can be ignored when scanning the sections."
 */
type Grub2Font_PtszSection struct {
	FontPointSize uint16
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_PtszSection() *Grub2Font_PtszSection {
	return &Grub2Font_PtszSection{
	}
}

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

	tmp3, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.FontPointSize = uint16(tmp3)
	return err
}
type Grub2Font_FamiSection struct {
	FontFamilyName string
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_FamiSection() *Grub2Font_FamiSection {
	return &Grub2Font_FamiSection{
	}
}

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

	tmp4, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.FontFamilyName = string(tmp4)
	return err
}
type Grub2Font_WeigSection struct {
	FontWeight string
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_WeigSection() *Grub2Font_WeigSection {
	return &Grub2Font_WeigSection{
	}
}

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

	tmp5, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.FontWeight = string(tmp5)
	return err
}
type Grub2Font_MaxwSection struct {
	MaximumCharacterWidth uint16
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_MaxwSection() *Grub2Font_MaxwSection {
	return &Grub2Font_MaxwSection{
	}
}

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

	tmp6, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.MaximumCharacterWidth = uint16(tmp6)
	return err
}
type Grub2Font_DescSection struct {
	DescentInPixels uint16
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_DescSection() *Grub2Font_DescSection {
	return &Grub2Font_DescSection{
	}
}

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

	tmp7, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.DescentInPixels = uint16(tmp7)
	return err
}
type Grub2Font_Section struct {
	SectionType string
	LenBody uint32
	Body interface{}
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font
	_raw_Body []byte
}
func NewGrub2Font_Section() *Grub2Font_Section {
	return &Grub2Font_Section{
	}
}

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

	tmp8, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp8 = tmp8
	this.SectionType = string(tmp8)
	tmp9, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenBody = uint32(tmp9)
	if (this.SectionType != "DATA") {
		switch (this.SectionType) {
		case "MAXH":
			tmp10, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp10 = tmp10
			this._raw_Body = tmp10
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp11 := NewGrub2Font_MaxhSection()
			err = tmp11.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp11
		case "FAMI":
			tmp12, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp12 = tmp12
			this._raw_Body = tmp12
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp13 := NewGrub2Font_FamiSection()
			err = tmp13.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp13
		case "PTSZ":
			tmp14, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp14 = tmp14
			this._raw_Body = tmp14
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp15 := NewGrub2Font_PtszSection()
			err = tmp15.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp15
		case "MAXW":
			tmp16, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp16 = tmp16
			this._raw_Body = tmp16
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp17 := NewGrub2Font_MaxwSection()
			err = tmp17.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp17
		case "SLAN":
			tmp18, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp18 = tmp18
			this._raw_Body = tmp18
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp19 := NewGrub2Font_SlanSection()
			err = tmp19.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp19
		case "WEIG":
			tmp20, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp20 = tmp20
			this._raw_Body = tmp20
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp21 := NewGrub2Font_WeigSection()
			err = tmp21.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp21
		case "CHIX":
			tmp22, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp22 = tmp22
			this._raw_Body = tmp22
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp23 := NewGrub2Font_ChixSection()
			err = tmp23.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp23
		case "DESC":
			tmp24, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp24 = tmp24
			this._raw_Body = tmp24
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp25 := NewGrub2Font_DescSection()
			err = tmp25.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp25
		case "NAME":
			tmp26, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp26 = tmp26
			this._raw_Body = tmp26
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp27 := NewGrub2Font_NameSection()
			err = tmp27.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp27
		case "ASCE":
			tmp28, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp28 = tmp28
			this._raw_Body = tmp28
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp29 := NewGrub2Font_AsceSection()
			err = tmp29.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp29
		default:
			tmp30, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp30 = tmp30
			this._raw_Body = tmp30
		}
	}
	return err
}

/**
 * Should be set to `0xFFFF_FFFF` for `section_type != "DATA"`
 */
type Grub2Font_AsceSection struct {
	AscentInPixels uint16
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_AsceSection() *Grub2Font_AsceSection {
	return &Grub2Font_AsceSection{
	}
}

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

	tmp31, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.AscentInPixels = uint16(tmp31)
	return err
}
type Grub2Font_ChixSection struct {
	Characters []*Grub2Font_ChixSection_Character
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_ChixSection() *Grub2Font_ChixSection {
	return &Grub2Font_ChixSection{
	}
}

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

	for i := 1;; i++ {
		tmp32, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp32 {
			break
		}
		tmp33 := NewGrub2Font_ChixSection_Character()
		err = tmp33.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Characters = append(this.Characters, tmp33)
	}
	return err
}
type Grub2Font_ChixSection_Character struct {
	CodePoint uint32
	Flags uint8
	OfsDefinition uint32
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_ChixSection
	_f_definition bool
	definition *Grub2Font_ChixSection_CharacterDefinition
}
func NewGrub2Font_ChixSection_Character() *Grub2Font_ChixSection_Character {
	return &Grub2Font_ChixSection_Character{
	}
}

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

	tmp34, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.CodePoint = uint32(tmp34)
	tmp35, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Flags = tmp35
	tmp36, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsDefinition = uint32(tmp36)
	return err
}
func (this *Grub2Font_ChixSection_Character) Definition() (v *Grub2Font_ChixSection_CharacterDefinition, err error) {
	if (this._f_definition) {
		return this.definition, nil
	}
	thisIo := this._root._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(this.OfsDefinition), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp37 := NewGrub2Font_ChixSection_CharacterDefinition()
	err = tmp37.Read(thisIo, this, this._root)
	if err != nil {
		return nil, err
	}
	this.definition = tmp37
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_definition = true
	this._f_definition = true
	return this.definition, nil
}

/**
 * Unicode code point
 */
type Grub2Font_ChixSection_CharacterDefinition struct {
	Width uint16
	Height uint16
	XOffset int16
	YOffset int16
	DeviceWidth int16
	BitmapData []byte
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_ChixSection_Character
}
func NewGrub2Font_ChixSection_CharacterDefinition() *Grub2Font_ChixSection_CharacterDefinition {
	return &Grub2Font_ChixSection_CharacterDefinition{
	}
}

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

	tmp38, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Width = uint16(tmp38)
	tmp39, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Height = uint16(tmp39)
	tmp40, err := this._io.ReadS2be()
	if err != nil {
		return err
	}
	this.XOffset = int16(tmp40)
	tmp41, err := this._io.ReadS2be()
	if err != nil {
		return err
	}
	this.YOffset = int16(tmp41)
	tmp42, err := this._io.ReadS2be()
	if err != nil {
		return err
	}
	this.DeviceWidth = int16(tmp42)
	tmp43, err := this._io.ReadBytes(int((((this.Width * this.Height) + 7) / 8)))
	if err != nil {
		return err
	}
	tmp43 = tmp43
	this.BitmapData = tmp43
	return err
}

/**
 * A two-dimensional bitmap, one bit per pixel. It is organized as
 * row-major, top-down, left-to-right. The most significant bit of
 * each byte corresponds to the leftmost or uppermost pixel from all
 * bits of the byte. If a bit is set (1, `true`), the pixel is set to
 * the font color, if a bit is clear (0, `false`), the pixel is
 * transparent.
 * 
 * Rows are **not** padded to byte boundaries (i.e., a
 * single byte may contain bits belonging to multiple rows). The last
 * byte of the bitmap _is_ padded with zero bits at all unused least
 * significant bit positions so that the bitmap ends on a byte
 * boundary.
 */
type Grub2Font_MaxhSection struct {
	MaximumCharacterHeight uint16
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_MaxhSection() *Grub2Font_MaxhSection {
	return &Grub2Font_MaxhSection{
	}
}

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

	tmp44, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.MaximumCharacterHeight = uint16(tmp44)
	return err
}
type Grub2Font_NameSection struct {
	FontName string
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_NameSection() *Grub2Font_NameSection {
	return &Grub2Font_NameSection{
	}
}

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

	tmp45, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.FontName = string(tmp45)
	return err
}
type Grub2Font_SlanSection struct {
	FontSlant string
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_SlanSection() *Grub2Font_SlanSection {
	return &Grub2Font_SlanSection{
	}
}

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

	tmp46, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.FontSlant = string(tmp46)
	return err
}