Allegro data file: PHP parsing library

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.

Application

Allegro library (v2.2-v4.4)

KS implementation details

License: CC0-1.0

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.

PHP source code to parse Allegro data file

AllegroDat.php

<?php
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

/**
 * 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.
 */

class AllegroDat extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \Kaitai\Struct\Struct $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_packMagic = $this->_io->readU4be();
        $this->_m_datMagic = $this->_io->ensureFixedContents("\x41\x4C\x4C\x2E");
        $this->_m_numObjects = $this->_io->readU4be();
        $this->_m_objects = [];
        $n = $this->numObjects();
        for ($i = 0; $i < $n; $i++) {
            $this->_m_objects[] = new \AllegroDat\DatObject($this->_io, $this, $this->_root);
        }
    }
    protected $_m_packMagic;
    protected $_m_datMagic;
    protected $_m_numObjects;
    protected $_m_objects;
    public function packMagic() { return $this->_m_packMagic; }
    public function datMagic() { return $this->_m_datMagic; }
    public function numObjects() { return $this->_m_numObjects; }
    public function objects() { return $this->_m_objects; }
}

/**
 * Simple monochrome monospaced font, 95 characters, 8x16 px
 * characters.
 */

namespace \AllegroDat;

class DatFont16 extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatFont $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_chars = [];
        $n = 95;
        for ($i = 0; $i < $n; $i++) {
            $this->_m_chars[] = $this->_io->readBytes(16);
        }
    }
    protected $_m_chars;
    public function chars() { return $this->_m_chars; }
}

namespace \AllegroDat;

class DatBitmap extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatObject $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_bitsPerPixel = $this->_io->readS2be();
        $this->_m_width = $this->_io->readU2be();
        $this->_m_height = $this->_io->readU2be();
        $this->_m_image = $this->_io->readBytesFull();
    }
    protected $_m_bitsPerPixel;
    protected $_m_width;
    protected $_m_height;
    protected $_m_image;
    public function bitsPerPixel() { return $this->_m_bitsPerPixel; }
    public function width() { return $this->_m_width; }
    public function height() { return $this->_m_height; }
    public function image() { return $this->_m_image; }
}

namespace \AllegroDat;

class DatFont extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatObject $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_fontSize = $this->_io->readS2be();
        switch ($this->fontSize()) {
            case 8:
                $this->_m_body = new \AllegroDat\DatFont8($this->_io, $this, $this->_root);
                break;
            case 16:
                $this->_m_body = new \AllegroDat\DatFont16($this->_io, $this, $this->_root);
                break;
            case 0:
                $this->_m_body = new \AllegroDat\DatFont39($this->_io, $this, $this->_root);
                break;
        }
    }
    protected $_m_fontSize;
    protected $_m_body;
    public function fontSize() { return $this->_m_fontSize; }
    public function body() { return $this->_m_body; }
}

/**
 * Simple monochrome monospaced font, 95 characters, 8x8 px
 * characters.
 */

namespace \AllegroDat;

class DatFont8 extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatFont $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_chars = [];
        $n = 95;
        for ($i = 0; $i < $n; $i++) {
            $this->_m_chars[] = $this->_io->readBytes(8);
        }
    }
    protected $_m_chars;
    public function chars() { return $this->_m_chars; }
}

namespace \AllegroDat;

class DatObject extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_properties = [];
        $i = 0;
        do {
            $_ = new \AllegroDat\Property($this->_io, $this, $this->_root);
            $this->_m_properties[] = $_;
            $i++;
        } while (!(!($_->isValid())));
        $this->_m_lenCompressed = $this->_io->readS4be();
        $this->_m_lenUncompressed = $this->_io->readS4be();
        switch ($this->type()) {
            case "BMP ":
                $this->_m__raw_body = $this->_io->readBytes($this->lenCompressed());
                $io = new \Kaitai\Struct\Stream($this->_m__raw_body);
                $this->_m_body = new \AllegroDat\DatBitmap($io, $this, $this->_root);
                break;
            case "RLE ":
                $this->_m__raw_body = $this->_io->readBytes($this->lenCompressed());
                $io = new \Kaitai\Struct\Stream($this->_m__raw_body);
                $this->_m_body = new \AllegroDat\DatRleSprite($io, $this, $this->_root);
                break;
            case "FONT":
                $this->_m__raw_body = $this->_io->readBytes($this->lenCompressed());
                $io = new \Kaitai\Struct\Stream($this->_m__raw_body);
                $this->_m_body = new \AllegroDat\DatFont($io, $this, $this->_root);
                break;
            default:
                $this->_m_body = $this->_io->readBytes($this->lenCompressed());
                break;
        }
    }
    protected $_m_type;
    public function type() {
        if ($this->_m_type !== null)
            return $this->_m_type;
        $this->_m_type = $this->properties()[count($this->properties()) - 1]->magic();
        return $this->_m_type;
    }
    protected $_m_properties;
    protected $_m_lenCompressed;
    protected $_m_lenUncompressed;
    protected $_m_body;
    protected $_m__raw_body;
    public function properties() { return $this->_m_properties; }
    public function lenCompressed() { return $this->_m_lenCompressed; }
    public function lenUncompressed() { return $this->_m_lenUncompressed; }
    public function body() { return $this->_m_body; }
    public function _raw_body() { return $this->_m__raw_body; }
}

/**
 * New bitmap font format introduced since Allegro 3.9: allows
 * flexible designation of character ranges, 8-bit colored
 * characters, etc.
 */

namespace \AllegroDat;

class DatFont39 extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatFont $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_numRanges = $this->_io->readS2be();
        $this->_m_ranges = [];
        $n = $this->numRanges();
        for ($i = 0; $i < $n; $i++) {
            $this->_m_ranges[] = new \AllegroDat\DatFont39\Range($this->_io, $this, $this->_root);
        }
    }
    protected $_m_numRanges;
    protected $_m_ranges;
    public function numRanges() { return $this->_m_numRanges; }
    public function ranges() { return $this->_m_ranges; }
}

namespace \AllegroDat\DatFont39;

class Range extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatFont39 $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_mono = $this->_io->readU1();
        $this->_m_startChar = $this->_io->readU4be();
        $this->_m_endChar = $this->_io->readU4be();
        $this->_m_chars = [];
        $n = (($this->endChar() - $this->startChar()) + 1);
        for ($i = 0; $i < $n; $i++) {
            $this->_m_chars[] = new \AllegroDat\DatFont39\FontChar($this->_io, $this, $this->_root);
        }
    }
    protected $_m_mono;
    protected $_m_startChar;
    protected $_m_endChar;
    protected $_m_chars;
    public function mono() { return $this->_m_mono; }

    /**
     * First character in range
     */
    public function startChar() { return $this->_m_startChar; }

    /**
     * Last character in range (inclusive)
     */
    public function endChar() { return $this->_m_endChar; }
    public function chars() { return $this->_m_chars; }
}

namespace \AllegroDat\DatFont39;

class FontChar extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatFont39\Range $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_width = $this->_io->readU2be();
        $this->_m_height = $this->_io->readU2be();
        $this->_m_body = $this->_io->readBytes(($this->width() * $this->height()));
    }
    protected $_m_width;
    protected $_m_height;
    protected $_m_body;
    public function width() { return $this->_m_width; }
    public function height() { return $this->_m_height; }
    public function body() { return $this->_m_body; }
}

namespace \AllegroDat;

class Property extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatObject $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_magic = \Kaitai\Struct\Stream::bytesToStr($this->_io->readBytes(4), "UTF-8");
        if ($this->isValid()) {
            $this->_m_type = \Kaitai\Struct\Stream::bytesToStr($this->_io->readBytes(4), "UTF-8");
        }
        if ($this->isValid()) {
            $this->_m_lenBody = $this->_io->readU4be();
        }
        if ($this->isValid()) {
            $this->_m_body = \Kaitai\Struct\Stream::bytesToStr($this->_io->readBytes($this->lenBody()), "UTF-8");
        }
    }
    protected $_m_isValid;
    public function isValid() {
        if ($this->_m_isValid !== null)
            return $this->_m_isValid;
        $this->_m_isValid = $this->magic() == "prop";
        return $this->_m_isValid;
    }
    protected $_m_magic;
    protected $_m_type;
    protected $_m_lenBody;
    protected $_m_body;
    public function magic() { return $this->_m_magic; }
    public function type() { return $this->_m_type; }
    public function lenBody() { return $this->_m_lenBody; }
    public function body() { return $this->_m_body; }
}

namespace \AllegroDat;

class DatRleSprite extends \Kaitai\Struct\Struct {
    public function __construct(\Kaitai\Struct\Stream $_io, \AllegroDat\DatObject $_parent = null, \AllegroDat $_root = null) {
        parent::__construct($_io, $_parent, $_root);
        $this->_read();
    }

    private function _read() {
        $this->_m_bitsPerPixel = $this->_io->readS2be();
        $this->_m_width = $this->_io->readU2be();
        $this->_m_height = $this->_io->readU2be();
        $this->_m_lenImage = $this->_io->readU4be();
        $this->_m_image = $this->_io->readBytesFull();
    }
    protected $_m_bitsPerPixel;
    protected $_m_width;
    protected $_m_height;
    protected $_m_lenImage;
    protected $_m_image;
    public function bitsPerPixel() { return $this->_m_bitsPerPixel; }
    public function width() { return $this->_m_width; }
    public function height() { return $this->_m_height; }
    public function lenImage() { return $this->_m_lenImage; }
    public function image() { return $this->_m_image; }
}

namespace \AllegroDat;

class PackEnum {
    const UNPACKED = 1936484398;
}