Allegro data file: GraphViz block diagram (.dot) source

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.

GraphViz block diagram source

allegro_dat.dot

digraph {
	rankdir=LR;
	node [shape=plaintext];
	subgraph cluster__allegro_dat {
		label="AllegroDat";
		graph[style=dotted];

		allegro_dat__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
			<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
			<TR><TD PORT="pack_magic_pos">0</TD><TD PORT="pack_magic_size">4</TD><TD>u4be→PackEnum</TD><TD PORT="pack_magic_type">pack_magic</TD></TR>
			<TR><TD PORT="dat_magic_pos">4</TD><TD PORT="dat_magic_size">4</TD><TD>41 4C 4C 2E</TD><TD PORT="dat_magic_type">dat_magic</TD></TR>
			<TR><TD PORT="num_objects_pos">8</TD><TD PORT="num_objects_size">4</TD><TD>u4be</TD><TD PORT="num_objects_type">num_objects</TD></TR>
			<TR><TD PORT="objects_pos">12</TD><TD PORT="objects_size">...</TD><TD>DatObject</TD><TD PORT="objects_type">objects</TD></TR>
			<TR><TD COLSPAN="4" PORT="objects__repeat">repeat num_objects times</TD></TR>
		</TABLE>>];
		subgraph cluster__dat_font_16 {
			label="AllegroDat::DatFont16";
			graph[style=dotted];

			dat_font_16__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="chars_pos">0</TD><TD PORT="chars_size">16</TD><TD></TD><TD PORT="chars_type">chars</TD></TR>
				<TR><TD COLSPAN="4" PORT="chars__repeat">repeat 95 times</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__dat_bitmap {
			label="AllegroDat::DatBitmap";
			graph[style=dotted];

			dat_bitmap__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="bits_per_pixel_pos">0</TD><TD PORT="bits_per_pixel_size">2</TD><TD>s2be</TD><TD PORT="bits_per_pixel_type">bits_per_pixel</TD></TR>
				<TR><TD PORT="width_pos">2</TD><TD PORT="width_size">2</TD><TD>u2be</TD><TD PORT="width_type">width</TD></TR>
				<TR><TD PORT="height_pos">4</TD><TD PORT="height_size">2</TD><TD>u2be</TD><TD PORT="height_type">height</TD></TR>
				<TR><TD PORT="image_pos">6</TD><TD PORT="image_size">⇲</TD><TD></TD><TD PORT="image_type">image</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__dat_font {
			label="AllegroDat::DatFont";
			graph[style=dotted];

			dat_font__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="font_size_pos">0</TD><TD PORT="font_size_size">2</TD><TD>s2be</TD><TD PORT="font_size_type">font_size</TD></TR>
				<TR><TD PORT="body_pos">2</TD><TD PORT="body_size">...</TD><TD>switch (font_size)</TD><TD PORT="body_type">body</TD></TR>
			</TABLE>>];
dat_font__seq_body_switch [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
	<TR><TD BGCOLOR="#F0F2E4">case</TD><TD BGCOLOR="#F0F2E4">type</TD></TR>
	<TR><TD>8</TD><TD PORT="case0">DatFont8</TD></TR>
	<TR><TD>16</TD><TD PORT="case1">DatFont16</TD></TR>
	<TR><TD>0</TD><TD PORT="case2">DatFont39</TD></TR>
</TABLE>>];
		}
		subgraph cluster__dat_font_8 {
			label="AllegroDat::DatFont8";
			graph[style=dotted];

			dat_font_8__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="chars_pos">0</TD><TD PORT="chars_size">8</TD><TD></TD><TD PORT="chars_type">chars</TD></TR>
				<TR><TD COLSPAN="4" PORT="chars__repeat">repeat 95 times</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__dat_object {
			label="AllegroDat::DatObject";
			graph[style=dotted];

			dat_object__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="properties_pos">0</TD><TD PORT="properties_size">...</TD><TD>Property</TD><TD PORT="properties_type">properties</TD></TR>
				<TR><TD COLSPAN="4" PORT="properties__repeat">repeat until !(_.is_valid)</TD></TR>
				<TR><TD PORT="len_compressed_pos">...</TD><TD PORT="len_compressed_size">4</TD><TD>s4be</TD><TD PORT="len_compressed_type">len_compressed</TD></TR>
				<TR><TD PORT="len_uncompressed_pos">...</TD><TD PORT="len_uncompressed_size">4</TD><TD>s4be</TD><TD PORT="len_uncompressed_type">len_uncompressed</TD></TR>
				<TR><TD PORT="body_pos">...</TD><TD PORT="body_size">...</TD><TD>switch (type)</TD><TD PORT="body_type">body</TD></TR>
			</TABLE>>];
			dat_object__inst__type [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>type</TD><TD>properties.last.magic</TD></TR>
			</TABLE>>];
dat_object__seq_body_switch [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
	<TR><TD BGCOLOR="#F0F2E4">case</TD><TD BGCOLOR="#F0F2E4">type</TD></TR>
	<TR><TD>&quot;BMP &quot;</TD><TD PORT="case0">DatBitmap</TD></TR>
	<TR><TD>&quot;RLE &quot;</TD><TD PORT="case1">DatRleSprite</TD></TR>
	<TR><TD>&quot;FONT&quot;</TD><TD PORT="case2">DatFont</TD></TR>
</TABLE>>];
		}
		subgraph cluster__dat_font_3_9 {
			label="AllegroDat::DatFont39";
			graph[style=dotted];

			dat_font_3_9__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="num_ranges_pos">0</TD><TD PORT="num_ranges_size">2</TD><TD>s2be</TD><TD PORT="num_ranges_type">num_ranges</TD></TR>
				<TR><TD PORT="ranges_pos">2</TD><TD PORT="ranges_size">...</TD><TD>Range</TD><TD PORT="ranges_type">ranges</TD></TR>
				<TR><TD COLSPAN="4" PORT="ranges__repeat">repeat num_ranges times</TD></TR>
			</TABLE>>];
			subgraph cluster__range {
				label="AllegroDat::DatFont39::Range";
				graph[style=dotted];

				range__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
					<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
					<TR><TD PORT="mono_pos">0</TD><TD PORT="mono_size">1</TD><TD>u1</TD><TD PORT="mono_type">mono</TD></TR>
					<TR><TD PORT="start_char_pos">1</TD><TD PORT="start_char_size">4</TD><TD>u4be</TD><TD PORT="start_char_type">start_char</TD></TR>
					<TR><TD PORT="end_char_pos">5</TD><TD PORT="end_char_size">4</TD><TD>u4be</TD><TD PORT="end_char_type">end_char</TD></TR>
					<TR><TD PORT="chars_pos">9</TD><TD PORT="chars_size">...</TD><TD>FontChar</TD><TD PORT="chars_type">chars</TD></TR>
					<TR><TD COLSPAN="4" PORT="chars__repeat">repeat ((end_char - start_char) + 1) times</TD></TR>
				</TABLE>>];
			}
			subgraph cluster__font_char {
				label="AllegroDat::DatFont39::FontChar";
				graph[style=dotted];

				font_char__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
					<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
					<TR><TD PORT="width_pos">0</TD><TD PORT="width_size">2</TD><TD>u2be</TD><TD PORT="width_type">width</TD></TR>
					<TR><TD PORT="height_pos">2</TD><TD PORT="height_size">2</TD><TD>u2be</TD><TD PORT="height_type">height</TD></TR>
					<TR><TD PORT="body_pos">4</TD><TD PORT="body_size">(width * height)</TD><TD></TD><TD PORT="body_type">body</TD></TR>
				</TABLE>>];
			}
		}
		subgraph cluster__property {
			label="AllegroDat::Property";
			graph[style=dotted];

			property__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="magic_pos">0</TD><TD PORT="magic_size">4</TD><TD>str(UTF-8)</TD><TD PORT="magic_type">magic</TD></TR>
				<TR><TD PORT="type_pos">4</TD><TD PORT="type_size">4</TD><TD>str(UTF-8)</TD><TD PORT="type_type">type</TD></TR>
				<TR><TD PORT="len_body_pos">8</TD><TD PORT="len_body_size">4</TD><TD>u4be</TD><TD PORT="len_body_type">len_body</TD></TR>
				<TR><TD PORT="body_pos">12</TD><TD PORT="body_size">len_body</TD><TD>str(UTF-8)</TD><TD PORT="body_type">body</TD></TR>
			</TABLE>>];
			property__inst__is_valid [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>is_valid</TD><TD>magic == &quot;prop&quot;</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__dat_rle_sprite {
			label="AllegroDat::DatRleSprite";
			graph[style=dotted];

			dat_rle_sprite__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="bits_per_pixel_pos">0</TD><TD PORT="bits_per_pixel_size">2</TD><TD>s2be</TD><TD PORT="bits_per_pixel_type">bits_per_pixel</TD></TR>
				<TR><TD PORT="width_pos">2</TD><TD PORT="width_size">2</TD><TD>u2be</TD><TD PORT="width_type">width</TD></TR>
				<TR><TD PORT="height_pos">4</TD><TD PORT="height_size">2</TD><TD>u2be</TD><TD PORT="height_type">height</TD></TR>
				<TR><TD PORT="len_image_pos">6</TD><TD PORT="len_image_size">4</TD><TD>u4be</TD><TD PORT="len_image_type">len_image</TD></TR>
				<TR><TD PORT="image_pos">10</TD><TD PORT="image_size">⇲</TD><TD></TD><TD PORT="image_type">image</TD></TR>
			</TABLE>>];
		}
	}
	allegro_dat__seq:objects_type -> dat_object__seq [style=bold];
	allegro_dat__seq:num_objects_type -> allegro_dat__seq:objects__repeat [color="#404040"];
	dat_font__seq:body_type -> dat_font__seq_body_switch [style=bold];
	dat_font__seq_body_switch:case0 -> dat_font_8__seq [style=bold];
	dat_font__seq_body_switch:case1 -> dat_font_16__seq [style=bold];
	dat_font__seq_body_switch:case2 -> dat_font_3_9__seq [style=bold];
	dat_font__seq:font_size_type -> dat_font__seq:body_type [color="#404040"];
	dat_object__seq:properties_type -> property__seq [style=bold];
	property__inst__is_valid:is_valid_type -> dat_object__seq:properties__repeat [color="#404040"];
	dat_object__seq:body_type -> dat_object__seq_body_switch [style=bold];
	dat_object__seq_body_switch:case0 -> dat_bitmap__seq [style=bold];
	dat_object__seq_body_switch:case1 -> dat_rle_sprite__seq [style=bold];
	dat_object__seq_body_switch:case2 -> dat_font__seq [style=bold];
	dat_object__inst__type:type_type -> dat_object__seq:body_type [color="#404040"];
	property__seq:magic_type -> dat_object__inst__type [color="#404040"];
	dat_font_3_9__seq:ranges_type -> range__seq [style=bold];
	dat_font_3_9__seq:num_ranges_type -> dat_font_3_9__seq:ranges__repeat [color="#404040"];
	range__seq:chars_type -> font_char__seq [style=bold];
	range__seq:end_char_type -> range__seq:chars__repeat [color="#404040"];
	range__seq:start_char_type -> range__seq:chars__repeat [color="#404040"];
	font_char__seq:width_type -> font_char__seq:body_size [color="#404040"];
	font_char__seq:height_type -> font_char__seq:body_size [color="#404040"];
	property__seq:len_body_type -> property__seq:body_size [color="#404040"];
	property__seq:magic_type -> property__inst__is_valid [color="#404040"];
}