Allegro library for C (mostly used for game and multimedia apps programming) used its own container file format.
In general, it allows storage of arbitrary binary data blocks bundled together with some simple key-value style metadata ("properties") for every block. Allegro also pre-defines some simple formats for bitmaps, fonts, MIDI music, sound samples and palettes. Allegro library v4.0+ also support LZSS compression.
This spec applies to Allegro data files for library versions 2.2 up to 4.4.
This page hosts a formal specification of Allegro data file 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"
"bytes"
)
/**
* Allegro library for C (mostly used for game and multimedia apps
* programming) used its own container file format.
*
* In general, it allows storage of arbitrary binary data blocks
* bundled together with some simple key-value style metadata
* ("properties") for every block. Allegro also pre-defines some simple
* formats for bitmaps, fonts, MIDI music, sound samples and
* palettes. Allegro library v4.0+ also support LZSS compression.
*
* This spec applies to Allegro data files for library versions 2.2 up
* to 4.4.
* @see <a href="https://liballeg.org/stabledocs/en/datafile.html">Source</a>
*/
type AllegroDat_PackEnum int
const (
AllegroDat_PackEnum__Unpacked AllegroDat_PackEnum = 1936484398
)
var values_AllegroDat_PackEnum = map[AllegroDat_PackEnum]struct{}{1936484398: {}}
func (v AllegroDat_PackEnum) isDefined() bool {
_, ok := values_AllegroDat_PackEnum[v]
return ok
}
type AllegroDat struct {
PackMagic AllegroDat_PackEnum
DatMagic []byte
NumObjects uint32
Objects []*AllegroDat_DatObject
_io *kaitai.Stream
_root *AllegroDat
_parent kaitai.Struct
}
func NewAllegroDat() *AllegroDat {
return &AllegroDat{
}
}
func (this AllegroDat) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat) Read(io *kaitai.Stream, parent kaitai.Struct, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1, err := this._io.ReadU4be()
if err != nil {
return err
}
this.PackMagic = AllegroDat_PackEnum(tmp1)
tmp2, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp2 = tmp2
this.DatMagic = tmp2
if !(bytes.Equal(this.DatMagic, []uint8{65, 76, 76, 46})) {
return kaitai.NewValidationNotEqualError([]uint8{65, 76, 76, 46}, this.DatMagic, this._io, "/seq/1")
}
tmp3, err := this._io.ReadU4be()
if err != nil {
return err
}
this.NumObjects = uint32(tmp3)
for i := 0; i < int(this.NumObjects); i++ {
_ = i
tmp4 := NewAllegroDat_DatObject()
err = tmp4.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Objects = append(this.Objects, tmp4)
}
return err
}
type AllegroDat_DatBitmap struct {
BitsPerPixel int16
Width uint16
Height uint16
Image []byte
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatObject
}
func NewAllegroDat_DatBitmap() *AllegroDat_DatBitmap {
return &AllegroDat_DatBitmap{
}
}
func (this AllegroDat_DatBitmap) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatBitmap) Read(io *kaitai.Stream, parent *AllegroDat_DatObject, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp5, err := this._io.ReadS2be()
if err != nil {
return err
}
this.BitsPerPixel = int16(tmp5)
tmp6, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Width = uint16(tmp6)
tmp7, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Height = uint16(tmp7)
tmp8, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp8 = tmp8
this.Image = tmp8
return err
}
type AllegroDat_DatFont struct {
FontSize int16
Body kaitai.Struct
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatObject
}
func NewAllegroDat_DatFont() *AllegroDat_DatFont {
return &AllegroDat_DatFont{
}
}
func (this AllegroDat_DatFont) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatFont) Read(io *kaitai.Stream, parent *AllegroDat_DatObject, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp9, err := this._io.ReadS2be()
if err != nil {
return err
}
this.FontSize = int16(tmp9)
switch (this.FontSize) {
case 0:
tmp10 := NewAllegroDat_DatFont39()
err = tmp10.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp10
case 16:
tmp11 := NewAllegroDat_DatFont16()
err = tmp11.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp11
case 8:
tmp12 := NewAllegroDat_DatFont8()
err = tmp12.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp12
}
return err
}
/**
* Simple monochrome monospaced font, 95 characters, 8x16 px
* characters.
*/
type AllegroDat_DatFont16 struct {
Chars [][]byte
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatFont
}
func NewAllegroDat_DatFont16() *AllegroDat_DatFont16 {
return &AllegroDat_DatFont16{
}
}
func (this AllegroDat_DatFont16) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatFont16) Read(io *kaitai.Stream, parent *AllegroDat_DatFont, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 0; i < int(95); i++ {
_ = i
tmp13, err := this._io.ReadBytes(int(16))
if err != nil {
return err
}
tmp13 = tmp13
this.Chars = append(this.Chars, tmp13)
}
return err
}
/**
* New bitmap font format introduced since Allegro 3.9: allows
* flexible designation of character ranges, 8-bit colored
* characters, etc.
*/
type AllegroDat_DatFont39 struct {
NumRanges int16
Ranges []*AllegroDat_DatFont39_Range
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatFont
}
func NewAllegroDat_DatFont39() *AllegroDat_DatFont39 {
return &AllegroDat_DatFont39{
}
}
func (this AllegroDat_DatFont39) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatFont39) Read(io *kaitai.Stream, parent *AllegroDat_DatFont, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp14, err := this._io.ReadS2be()
if err != nil {
return err
}
this.NumRanges = int16(tmp14)
for i := 0; i < int(this.NumRanges); i++ {
_ = i
tmp15 := NewAllegroDat_DatFont39_Range()
err = tmp15.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Ranges = append(this.Ranges, tmp15)
}
return err
}
type AllegroDat_DatFont39_FontChar struct {
Width uint16
Height uint16
Body []byte
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatFont39_Range
}
func NewAllegroDat_DatFont39_FontChar() *AllegroDat_DatFont39_FontChar {
return &AllegroDat_DatFont39_FontChar{
}
}
func (this AllegroDat_DatFont39_FontChar) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatFont39_FontChar) Read(io *kaitai.Stream, parent *AllegroDat_DatFont39_Range, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp16, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Width = uint16(tmp16)
tmp17, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Height = uint16(tmp17)
tmp18, err := this._io.ReadBytes(int(this.Width * this.Height))
if err != nil {
return err
}
tmp18 = tmp18
this.Body = tmp18
return err
}
type AllegroDat_DatFont39_Range struct {
Mono uint8
StartChar uint32
EndChar uint32
Chars []*AllegroDat_DatFont39_FontChar
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatFont39
}
func NewAllegroDat_DatFont39_Range() *AllegroDat_DatFont39_Range {
return &AllegroDat_DatFont39_Range{
}
}
func (this AllegroDat_DatFont39_Range) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatFont39_Range) Read(io *kaitai.Stream, parent *AllegroDat_DatFont39, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp19, err := this._io.ReadU1()
if err != nil {
return err
}
this.Mono = tmp19
tmp20, err := this._io.ReadU4be()
if err != nil {
return err
}
this.StartChar = uint32(tmp20)
tmp21, err := this._io.ReadU4be()
if err != nil {
return err
}
this.EndChar = uint32(tmp21)
for i := 0; i < int((this.EndChar - this.StartChar) + 1); i++ {
_ = i
tmp22 := NewAllegroDat_DatFont39_FontChar()
err = tmp22.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Chars = append(this.Chars, tmp22)
}
return err
}
/**
* First character in range
*/
/**
* Last character in range (inclusive)
*/
/**
* Simple monochrome monospaced font, 95 characters, 8x8 px
* characters.
*/
type AllegroDat_DatFont8 struct {
Chars [][]byte
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatFont
}
func NewAllegroDat_DatFont8() *AllegroDat_DatFont8 {
return &AllegroDat_DatFont8{
}
}
func (this AllegroDat_DatFont8) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatFont8) Read(io *kaitai.Stream, parent *AllegroDat_DatFont, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 0; i < int(95); i++ {
_ = i
tmp23, err := this._io.ReadBytes(int(8))
if err != nil {
return err
}
tmp23 = tmp23
this.Chars = append(this.Chars, tmp23)
}
return err
}
type AllegroDat_DatObject struct {
Properties []*AllegroDat_Property
LenCompressed int32
LenUncompressed int32
Body interface{}
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat
_raw_Body []byte
_f_type bool
type string
}
func NewAllegroDat_DatObject() *AllegroDat_DatObject {
return &AllegroDat_DatObject{
}
}
func (this AllegroDat_DatObject) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatObject) Read(io *kaitai.Stream, parent *AllegroDat, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 1;; i++ {
tmp24 := NewAllegroDat_Property()
err = tmp24.Read(this._io, this, this._root)
if err != nil {
return err
}
_it := tmp24
this.Properties = append(this.Properties, _it)
tmp25, err := _it.IsValid()
if err != nil {
return err
}
if !(tmp25) {
break
}
}
tmp26, err := this._io.ReadS4be()
if err != nil {
return err
}
this.LenCompressed = int32(tmp26)
tmp27, err := this._io.ReadS4be()
if err != nil {
return err
}
this.LenUncompressed = int32(tmp27)
tmp28, err := this.Type()
if err != nil {
return err
}
switch (tmp28) {
case "BMP ":
tmp29, err := this._io.ReadBytes(int(this.LenCompressed))
if err != nil {
return err
}
tmp29 = tmp29
this._raw_Body = tmp29
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp30 := NewAllegroDat_DatBitmap()
err = tmp30.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp30
case "FONT":
tmp31, err := this._io.ReadBytes(int(this.LenCompressed))
if err != nil {
return err
}
tmp31 = tmp31
this._raw_Body = tmp31
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp32 := NewAllegroDat_DatFont()
err = tmp32.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp32
case "RLE ":
tmp33, err := this._io.ReadBytes(int(this.LenCompressed))
if err != nil {
return err
}
tmp33 = tmp33
this._raw_Body = tmp33
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp34 := NewAllegroDat_DatRleSprite()
err = tmp34.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp34
default:
tmp35, err := this._io.ReadBytes(int(this.LenCompressed))
if err != nil {
return err
}
tmp35 = tmp35
this._raw_Body = tmp35
}
return err
}
func (this *AllegroDat_DatObject) Type() (v string, err error) {
if (this._f_type) {
return this.type, nil
}
this._f_type = true
tmp36 := this.Properties
this.type = string(tmp36[len(tmp36) - 1].Magic)
return this.type, nil
}
type AllegroDat_DatRleSprite struct {
BitsPerPixel int16
Width uint16
Height uint16
LenImage uint32
Image []byte
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatObject
}
func NewAllegroDat_DatRleSprite() *AllegroDat_DatRleSprite {
return &AllegroDat_DatRleSprite{
}
}
func (this AllegroDat_DatRleSprite) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_DatRleSprite) Read(io *kaitai.Stream, parent *AllegroDat_DatObject, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp37, err := this._io.ReadS2be()
if err != nil {
return err
}
this.BitsPerPixel = int16(tmp37)
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.ReadU4be()
if err != nil {
return err
}
this.LenImage = uint32(tmp40)
tmp41, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp41 = tmp41
this.Image = tmp41
return err
}
type AllegroDat_Property struct {
Magic string
Type string
LenBody uint32
Body string
_io *kaitai.Stream
_root *AllegroDat
_parent *AllegroDat_DatObject
_f_isValid bool
isValid bool
}
func NewAllegroDat_Property() *AllegroDat_Property {
return &AllegroDat_Property{
}
}
func (this AllegroDat_Property) IO_() *kaitai.Stream {
return this._io
}
func (this *AllegroDat_Property) Read(io *kaitai.Stream, parent *AllegroDat_DatObject, root *AllegroDat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp42, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp42 = tmp42
this.Magic = string(tmp42)
tmp43, err := this.IsValid()
if err != nil {
return err
}
if (tmp43) {
tmp44, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp44 = tmp44
this.Type = string(tmp44)
}
tmp45, err := this.IsValid()
if err != nil {
return err
}
if (tmp45) {
tmp46, err := this._io.ReadU4be()
if err != nil {
return err
}
this.LenBody = uint32(tmp46)
}
tmp47, err := this.IsValid()
if err != nil {
return err
}
if (tmp47) {
tmp48, err := this._io.ReadBytes(int(this.LenBody))
if err != nil {
return err
}
tmp48 = tmp48
this.Body = string(tmp48)
}
return err
}
func (this *AllegroDat_Property) IsValid() (v bool, err error) {
if (this._f_isValid) {
return this.isValid, nil
}
this._f_isValid = true
this.isValid = bool(this.Magic == "prop")
return this.isValid, nil
}