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 kaitai.Struct
}
func NewGrub2Font() *Grub2Font {
	return &Grub2Font{
	}
}

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

func (this *Grub2Font) Read(io *kaitai.Stream, parent kaitai.Struct, 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_AsceSection struct {
	AscentInPixels uint16
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_AsceSection() *Grub2Font_AsceSection {
	return &Grub2Font_AsceSection{
	}
}

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

func (this *Grub2Font_AsceSection) 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.AscentInPixels = uint16(tmp3)
	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) IO_() *kaitai.Stream {
	return this._io
}

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 := 0;; i++ {
		tmp4, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp4 {
			break
		}
		tmp5 := NewGrub2Font_ChixSection_Character()
		err = tmp5.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Characters = append(this.Characters, tmp5)
	}
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp6, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.CodePoint = uint32(tmp6)
	tmp7, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Flags = tmp7
	tmp8, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsDefinition = uint32(tmp8)
	return err
}
func (this *Grub2Font_ChixSection_Character) Definition() (v *Grub2Font_ChixSection_CharacterDefinition, err error) {
	if (this._f_definition) {
		return this.definition, nil
	}
	this._f_definition = true
	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
	}
	tmp9 := NewGrub2Font_ChixSection_CharacterDefinition()
	err = tmp9.Read(thisIo, this, this._root)
	if err != nil {
		return nil, err
	}
	this.definition = tmp9
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp10, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Width = uint16(tmp10)
	tmp11, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Height = uint16(tmp11)
	tmp12, err := this._io.ReadS2be()
	if err != nil {
		return err
	}
	this.XOffset = int16(tmp12)
	tmp13, err := this._io.ReadS2be()
	if err != nil {
		return err
	}
	this.YOffset = int16(tmp13)
	tmp14, err := this._io.ReadS2be()
	if err != nil {
		return err
	}
	this.DeviceWidth = int16(tmp14)
	tmp15, err := this._io.ReadBytes(int((this.Width * this.Height + 7) / 8))
	if err != nil {
		return err
	}
	tmp15 = tmp15
	this.BitmapData = tmp15
	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_DescSection struct {
	DescentInPixels uint16
	_io *kaitai.Stream
	_root *Grub2Font
	_parent *Grub2Font_Section
}
func NewGrub2Font_DescSection() *Grub2Font_DescSection {
	return &Grub2Font_DescSection{
	}
}

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

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

	tmp16, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.DescentInPixels = uint16(tmp16)
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp17, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.FontFamilyName = string(tmp17)
	return err
}
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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp18, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.MaximumCharacterHeight = uint16(tmp18)
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp19, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.MaximumCharacterWidth = uint16(tmp19)
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp20, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.FontName = string(tmp20)
	return err
}
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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp21, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.FontPointSize = uint16(tmp21)
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp22, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp22 = tmp22
	this.SectionType = string(tmp22)
	tmp23, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenBody = uint32(tmp23)
	if (this.SectionType != "DATA") {
		switch (this.SectionType) {
		case "ASCE":
			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_AsceSection()
			err = tmp25.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp25
		case "CHIX":
			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_ChixSection()
			err = tmp27.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp27
		case "DESC":
			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_DescSection()
			err = tmp29.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp29
		case "FAMI":
			tmp30, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp30 = tmp30
			this._raw_Body = tmp30
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp31 := NewGrub2Font_FamiSection()
			err = tmp31.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp31
		case "MAXH":
			tmp32, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp32 = tmp32
			this._raw_Body = tmp32
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp33 := NewGrub2Font_MaxhSection()
			err = tmp33.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp33
		case "MAXW":
			tmp34, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp34 = tmp34
			this._raw_Body = tmp34
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp35 := NewGrub2Font_MaxwSection()
			err = tmp35.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp35
		case "NAME":
			tmp36, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp36 = tmp36
			this._raw_Body = tmp36
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp37 := NewGrub2Font_NameSection()
			err = tmp37.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp37
		case "PTSZ":
			tmp38, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp38 = tmp38
			this._raw_Body = tmp38
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp39 := NewGrub2Font_PtszSection()
			err = tmp39.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp39
		case "SLAN":
			tmp40, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp40 = tmp40
			this._raw_Body = tmp40
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp41 := NewGrub2Font_SlanSection()
			err = tmp41.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp41
		case "WEIG":
			tmp42, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp42 = tmp42
			this._raw_Body = tmp42
			_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
			tmp43 := NewGrub2Font_WeigSection()
			err = tmp43.Read(_io__raw_Body, this, this._root)
			if err != nil {
				return err
			}
			this.Body = tmp43
		default:
			tmp44, err := this._io.ReadBytes(int(this.LenBody))
			if err != nil {
				return err
			}
			tmp44 = tmp44
			this._raw_Body = tmp44
		}
	}
	return err
}

/**
 * Should be set to `0xFFFF_FFFF` for `section_type != "DATA"`
 */
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) IO_() *kaitai.Stream {
	return this._io
}

func (this *Grub2Font_SlanSection) 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.FontSlant = string(tmp45)
	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) IO_() *kaitai.Stream {
	return this._io
}

func (this *Grub2Font_WeigSection) 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.FontWeight = string(tmp46)
	return err
}