This page hosts a formal specification of Shapefile index 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__shapefile_index {
label="ShapefileIndex";
graph[style=dotted];
shapefile_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="header_pos">0</TD><TD PORT="header_size">100</TD><TD>FileHeader</TD><TD PORT="header_type">header</TD></TR>
<TR><TD PORT="records_pos">100</TD><TD PORT="records_size">8</TD><TD>Record</TD><TD PORT="records_type">records</TD></TR>
<TR><TD COLSPAN="4" PORT="records__repeat">repeat to end of stream</TD></TR>
</TABLE>>];
subgraph cluster__file_header {
label="ShapefileIndex::FileHeader";
graph[style=dotted];
file_header__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_code_pos">0</TD><TD PORT="file_code_size">4</TD><TD></TD><TD PORT="file_code_type">file_code</TD></TR>
<TR><TD PORT="unused_field_1_pos">4</TD><TD PORT="unused_field_1_size">4</TD><TD></TD><TD PORT="unused_field_1_type">unused_field_1</TD></TR>
<TR><TD PORT="unused_field_2_pos">8</TD><TD PORT="unused_field_2_size">4</TD><TD></TD><TD PORT="unused_field_2_type">unused_field_2</TD></TR>
<TR><TD PORT="unused_field_3_pos">12</TD><TD PORT="unused_field_3_size">4</TD><TD></TD><TD PORT="unused_field_3_type">unused_field_3</TD></TR>
<TR><TD PORT="unused_field_4_pos">16</TD><TD PORT="unused_field_4_size">4</TD><TD></TD><TD PORT="unused_field_4_type">unused_field_4</TD></TR>
<TR><TD PORT="unused_field_5_pos">20</TD><TD PORT="unused_field_5_size">4</TD><TD></TD><TD PORT="unused_field_5_type">unused_field_5</TD></TR>
<TR><TD PORT="file_length_pos">24</TD><TD PORT="file_length_size">4</TD><TD>s4be</TD><TD PORT="file_length_type">file_length</TD></TR>
<TR><TD PORT="version_pos">28</TD><TD PORT="version_size">4</TD><TD></TD><TD PORT="version_type">version</TD></TR>
<TR><TD PORT="shape_type_pos">32</TD><TD PORT="shape_type_size">4</TD><TD>s4le→ShapeType</TD><TD PORT="shape_type_type">shape_type</TD></TR>
<TR><TD PORT="bounding_box_pos">36</TD><TD PORT="bounding_box_size">64</TD><TD>BoundingBoxXYZM</TD><TD PORT="bounding_box_type">bounding_box</TD></TR>
</TABLE>>];
}
subgraph cluster__record {
label="ShapefileIndex::Record";
graph[style=dotted];
record__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="offset_pos">0</TD><TD PORT="offset_size">4</TD><TD>s4be</TD><TD PORT="offset_type">offset</TD></TR>
<TR><TD PORT="content_length_pos">4</TD><TD PORT="content_length_size">4</TD><TD>s4be</TD><TD PORT="content_length_type">content_length</TD></TR>
</TABLE>>];
}
subgraph cluster__bounding_box_x_y_z_m {
label="ShapefileIndex::BoundingBoxXYZM";
graph[style=dotted];
bounding_box_x_y_z_m__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="x_pos">0</TD><TD PORT="x_size">16</TD><TD>BoundsMinMax</TD><TD PORT="x_type">x</TD></TR>
<TR><TD PORT="y_pos">16</TD><TD PORT="y_size">16</TD><TD>BoundsMinMax</TD><TD PORT="y_type">y</TD></TR>
<TR><TD PORT="z_pos">32</TD><TD PORT="z_size">16</TD><TD>BoundsMinMax</TD><TD PORT="z_type">z</TD></TR>
<TR><TD PORT="m_pos">48</TD><TD PORT="m_size">16</TD><TD>BoundsMinMax</TD><TD PORT="m_type">m</TD></TR>
</TABLE>>];
}
subgraph cluster__bounds_min_max {
label="ShapefileIndex::BoundsMinMax";
graph[style=dotted];
bounds_min_max__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="min_pos">0</TD><TD PORT="min_size">8</TD><TD>f8be</TD><TD PORT="min_type">min</TD></TR>
<TR><TD PORT="max_pos">8</TD><TD PORT="max_size">8</TD><TD>f8be</TD><TD PORT="max_type">max</TD></TR>
</TABLE>>];
}
}
shapefile_index__seq:header_type -> file_header__seq [style=bold];
shapefile_index__seq:records_type -> record__seq [style=bold];
file_header__seq:bounding_box_type -> bounding_box_x_y_z_m__seq [style=bold];
bounding_box_x_y_z_m__seq:x_type -> bounds_min_max__seq [style=bold];
bounding_box_x_y_z_m__seq:y_type -> bounds_min_max__seq [style=bold];
bounding_box_x_y_z_m__seq:z_type -> bounds_min_max__seq [style=bold];
bounding_box_x_y_z_m__seq:m_type -> bounds_min_max__seq [style=bold];
}