This page hosts a formal specification of .pak file format of Dune 2 game engine 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__dune_2_pak {
label="Dune2Pak";
graph[style=dotted];
dune_2_pak__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="dir_pos">0</TD><TD PORT="dir_size">dir_size</TD><TD>Files</TD><TD PORT="dir_type">dir</TD></TR>
</TABLE>>];
dune_2_pak__inst__dir_size [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="dir_size_pos">0</TD><TD PORT="dir_size_size">4</TD><TD>u4le</TD><TD PORT="dir_size_type">dir_size</TD></TR>
</TABLE>>];
subgraph cluster__file {
label="Dune2Pak::File";
graph[style=dotted];
file__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="ofs_pos">0</TD><TD PORT="ofs_size">4</TD><TD>u4le</TD><TD PORT="ofs_type">ofs</TD></TR>
<TR><TD PORT="file_name_pos">4</TD><TD PORT="file_name_size">...</TD><TD>str(term=0, ASCII)</TD><TD PORT="file_name_type">file_name</TD></TR>
<TR><TD COLSPAN="4" PORT="file_name__if">if ofs != 0</TD></TR>
</TABLE>>];
file__inst__body [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="body_pos">ofs</TD><TD PORT="body_size">next_ofs - ofs</TD><TD></TD><TD PORT="body_type">body</TD></TR>
<TR><TD COLSPAN="4" PORT="body__if">if ofs != 0</TD></TR>
</TABLE>>];
file__inst__next_ofs [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>next_ofs</TD><TD>(next_ofs0 == 0 ? _root._io.size : next_ofs0)</TD></TR>
</TABLE>>];
file__inst__next_ofs0 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>next_ofs0</TD><TD>_root.dir.files[idx + 1].ofs</TD></TR>
</TABLE>>];
}
subgraph cluster__files {
label="Dune2Pak::Files";
graph[style=dotted];
files__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="files_pos">0</TD><TD PORT="files_size">...</TD><TD>File</TD><TD PORT="files_type">files</TD></TR>
<TR><TD COLSPAN="4" PORT="files__repeat">repeat to end of stream</TD></TR>
</TABLE>>];
}
}
dune_2_pak__inst__dir_size:dir_size_type -> dune_2_pak__seq:dir_size [color="#404040"];
dune_2_pak__seq:dir_type -> files__seq [style=bold];
file__seq:ofs_type -> file__seq:file_name__if [color="#404040"];
file__seq:ofs_type -> file__inst__body:body_pos [color="#404040"];
file__inst__next_ofs:next_ofs_type -> file__inst__body:body_size [color="#404040"];
file__seq:ofs_type -> file__inst__body:body_size [color="#404040"];
file__seq:ofs_type -> file__inst__body:body__if [color="#404040"];
file__inst__next_ofs0:next_ofs0_type -> file__inst__next_ofs [color="#404040"];
file__seq:ofs_type -> file__inst__next_ofs0 [color="#404040"];
files__seq:files_type -> file__seq [style=bold];
}