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.
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></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>"BMP "</TD><TD PORT="case0">DatBitmap</TD></TR>
<TR><TD>"RLE "</TD><TD PORT="case1">DatRleSprite</TD></TR>
<TR><TD>"FONT"</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 == "prop"</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"];
}