This page hosts a formal specification of .dat file format of Fallout 2 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__fallout2_dat {
label="Fallout2Dat";
graph[style=dotted];
fallout2_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>
</TABLE>>];
fallout2_dat__inst__footer [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="footer_pos">(_io.size - 8)</TD><TD PORT="footer_size">8</TD><TD>Footer</TD><TD PORT="footer_type">footer</TD></TR>
</TABLE>>];
fallout2_dat__inst__index [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="index_pos">((_io.size - 8) - footer.index_size)</TD><TD PORT="index_size">...</TD><TD>Index</TD><TD PORT="index_type">index</TD></TR>
</TABLE>>];
subgraph cluster__pstr {
label="Fallout2Dat::Pstr";
graph[style=dotted];
pstr__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="size_pos">0</TD><TD PORT="size_size">4</TD><TD>u4le</TD><TD PORT="size_type">size</TD></TR>
<TR><TD PORT="str_pos">4</TD><TD PORT="str_size">size</TD><TD>str(ASCII)</TD><TD PORT="str_type">str</TD></TR>
</TABLE>>];
}
subgraph cluster__footer {
label="Fallout2Dat::Footer";
graph[style=dotted];
footer__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="index_size_pos">0</TD><TD PORT="index_size_size">4</TD><TD>u4le</TD><TD PORT="index_size_type">index_size</TD></TR>
<TR><TD PORT="file_size_pos">4</TD><TD PORT="file_size_size">4</TD><TD>u4le</TD><TD PORT="file_size_type">file_size</TD></TR>
</TABLE>>];
}
subgraph cluster__index {
label="Fallout2Dat::Index";
graph[style=dotted];
index__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="file_count_pos">0</TD><TD PORT="file_count_size">4</TD><TD>u4le</TD><TD PORT="file_count_type">file_count</TD></TR>
<TR><TD PORT="files_pos">4</TD><TD PORT="files_size">...</TD><TD>File</TD><TD PORT="files_type">files</TD></TR>
<TR><TD COLSPAN="4" PORT="files__repeat">repeat file_count times</TD></TR>
</TABLE>>];
}
subgraph cluster__file {
label="Fallout2Dat::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="name_pos">0</TD><TD PORT="name_size">...</TD><TD>Pstr</TD><TD PORT="name_type">name</TD></TR>
<TR><TD PORT="flags_pos">...</TD><TD PORT="flags_size">1</TD><TD>u1→Compression</TD><TD PORT="flags_type">flags</TD></TR>
<TR><TD PORT="size_unpacked_pos">...</TD><TD PORT="size_unpacked_size">4</TD><TD>u4le</TD><TD PORT="size_unpacked_type">size_unpacked</TD></TR>
<TR><TD PORT="size_packed_pos">...</TD><TD PORT="size_packed_size">4</TD><TD>u4le</TD><TD PORT="size_packed_type">size_packed</TD></TR>
<TR><TD PORT="offset_pos">...</TD><TD PORT="offset_size">4</TD><TD>u4le</TD><TD PORT="offset_type">offset</TD></TR>
</TABLE>>];
file__inst__contents_raw [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="contents_raw_pos">offset</TD><TD PORT="contents_raw_size">size_unpacked</TD><TD></TD><TD PORT="contents_raw_type">contents_raw</TD></TR>
</TABLE>>];
file__inst__contents_zlib [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="contents_zlib_pos">offset</TD><TD PORT="contents_zlib_size">size_packed</TD><TD></TD><TD PORT="contents_zlib_type">contents_zlib</TD></TR>
</TABLE>>];
file__inst__contents [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>contents</TD><TD>(flags == :compression_zlib ? contents_zlib : contents_raw)</TD></TR>
</TABLE>>];
}
}
fallout2_dat__inst__footer:footer_type -> footer__seq [style=bold];
footer__seq:index_size_type -> fallout2_dat__inst__index:index_pos [color="#404040"];
fallout2_dat__inst__index:index_type -> index__seq [style=bold];
pstr__seq:size_type -> pstr__seq:str_size [color="#404040"];
index__seq:files_type -> file__seq [style=bold];
index__seq:file_count_type -> index__seq:files__repeat [color="#404040"];
file__seq:name_type -> pstr__seq [style=bold];
file__seq:offset_type -> file__inst__contents_raw:contents_raw_pos [color="#404040"];
file__seq:size_unpacked_type -> file__inst__contents_raw:contents_raw_size [color="#404040"];
file__seq:offset_type -> file__inst__contents_zlib:contents_zlib_pos [color="#404040"];
file__seq:size_packed_type -> file__inst__contents_zlib:contents_zlib_size [color="#404040"];
file__seq:flags_type -> file__inst__contents [color="#404040"];
file__inst__contents_zlib:contents_zlib_type -> file__inst__contents [color="#404040"];
file__inst__contents_raw:contents_raw_type -> file__inst__contents [color="#404040"];
}