Shapefile main file: Lua parsing library

File extension

shp

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of Shapefile main file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Lua source code to parse Shapefile main file

shapefile_main.lua

-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
--
-- This file is compatible with Lua 5.3

local class = require("class")
require("kaitaistruct")
local enum = require("enum")

ShapefileMain = class.class(KaitaiStruct)

ShapefileMain.ShapeType = enum.Enum {
  null_shape = 0,
  point = 1,
  poly_line = 3,
  polygon = 5,
  multi_point = 8,
  point_z = 11,
  poly_line_z = 13,
  polygon_z = 15,
  multi_point_z = 18,
  point_m = 21,
  poly_line_m = 23,
  polygon_m = 25,
  multi_point_m = 28,
  multi_patch = 31,
}

ShapefileMain.PartType = enum.Enum {
  triangle_strip = 0,
  triangle_fan = 1,
  outer_ring = 2,
  inner_ring = 3,
  first_ring = 4,
  ring = 5,
}

function ShapefileMain:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain:_read()
  self.header = ShapefileMain.FileHeader(self._io, self, self._root)
  self.records = {}
  local i = 0
  while not self._io:is_eof() do
    self.records[i + 1] = ShapefileMain.Record(self._io, self, self._root)
    i = i + 1
  end
end

-- 
-- the size of this section of the file in bytes must equal (header.file_length * 2) - 100.

ShapefileMain.MultiPointM = class.class(KaitaiStruct)

function ShapefileMain.MultiPointM:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.MultiPointM:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_points = self._io:read_s4le()
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
  self.m_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m_values = {}
  for i = 0, self.number_of_points - 1 do
    self.m_values[i + 1] = self._io:read_f8le()
  end
end


ShapefileMain.BoundingBoxXYZM = class.class(KaitaiStruct)

function ShapefileMain.BoundingBoxXYZM:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.BoundingBoxXYZM:_read()
  self.x = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.y = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.z = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m = ShapefileMain.BoundsMinMax(self._io, self, self._root)
end


ShapefileMain.Point = class.class(KaitaiStruct)

function ShapefileMain.Point:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.Point:_read()
  self.x = self._io:read_f8le()
  self.y = self._io:read_f8le()
end


ShapefileMain.Polygon = class.class(KaitaiStruct)

function ShapefileMain.Polygon:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.Polygon:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_parts = self._io:read_s4le()
  self.number_of_points = self._io:read_s4le()
  self.parts = {}
  for i = 0, self.number_of_parts - 1 do
    self.parts[i + 1] = self._io:read_s4le()
  end
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
end


ShapefileMain.BoundsMinMax = class.class(KaitaiStruct)

function ShapefileMain.BoundsMinMax:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.BoundsMinMax:_read()
  self.min = self._io:read_f8le()
  self.max = self._io:read_f8le()
end


ShapefileMain.PolyLine = class.class(KaitaiStruct)

function ShapefileMain.PolyLine:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.PolyLine:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_parts = self._io:read_s4le()
  self.number_of_points = self._io:read_s4le()
  self.parts = {}
  for i = 0, self.number_of_parts - 1 do
    self.parts[i + 1] = self._io:read_s4le()
  end
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
end


ShapefileMain.MultiPointZ = class.class(KaitaiStruct)

function ShapefileMain.MultiPointZ:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.MultiPointZ:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_points = self._io:read_s4le()
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
  self.z_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.z_values = {}
  for i = 0, self.number_of_points - 1 do
    self.z_values[i + 1] = self._io:read_f8le()
  end
  self.m_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m_values = {}
  for i = 0, self.number_of_points - 1 do
    self.m_values[i + 1] = self._io:read_f8le()
  end
end


ShapefileMain.PolyLineZ = class.class(KaitaiStruct)

function ShapefileMain.PolyLineZ:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.PolyLineZ:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_parts = self._io:read_s4le()
  self.number_of_points = self._io:read_s4le()
  self.parts = {}
  for i = 0, self.number_of_parts - 1 do
    self.parts[i + 1] = self._io:read_s4le()
  end
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
  self.z_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.z_values = {}
  for i = 0, self.number_of_points - 1 do
    self.z_values[i + 1] = self._io:read_f8le()
  end
  self.m_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m_values = {}
  for i = 0, self.number_of_points - 1 do
    self.m_values[i + 1] = self._io:read_f8le()
  end
end


ShapefileMain.PolygonZ = class.class(KaitaiStruct)

function ShapefileMain.PolygonZ:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.PolygonZ:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_parts = self._io:read_s4le()
  self.number_of_points = self._io:read_s4le()
  self.parts = {}
  for i = 0, self.number_of_parts - 1 do
    self.parts[i + 1] = self._io:read_s4le()
  end
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
  self.z_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.z_values = {}
  for i = 0, self.number_of_points - 1 do
    self.z_values[i + 1] = self._io:read_f8le()
  end
  self.m_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m_values = {}
  for i = 0, self.number_of_points - 1 do
    self.m_values[i + 1] = self._io:read_f8le()
  end
end


ShapefileMain.BoundingBoxXY = class.class(KaitaiStruct)

function ShapefileMain.BoundingBoxXY:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.BoundingBoxXY:_read()
  self.x = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.y = ShapefileMain.BoundsMinMax(self._io, self, self._root)
end


ShapefileMain.PointM = class.class(KaitaiStruct)

function ShapefileMain.PointM:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.PointM:_read()
  self.x = self._io:read_f8le()
  self.y = self._io:read_f8le()
  self.m = self._io:read_f8le()
end


ShapefileMain.PolygonM = class.class(KaitaiStruct)

function ShapefileMain.PolygonM:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.PolygonM:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_parts = self._io:read_s4le()
  self.number_of_points = self._io:read_s4le()
  self.parts = {}
  for i = 0, self.number_of_parts - 1 do
    self.parts[i + 1] = self._io:read_s4le()
  end
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
  self.m_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m_values = {}
  for i = 0, self.number_of_points - 1 do
    self.m_values[i + 1] = self._io:read_f8le()
  end
end


ShapefileMain.RecordHeader = class.class(KaitaiStruct)

function ShapefileMain.RecordHeader:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.RecordHeader:_read()
  self.record_number = self._io:read_s4be()
  self.content_length = self._io:read_s4be()
end


ShapefileMain.MultiPoint = class.class(KaitaiStruct)

function ShapefileMain.MultiPoint:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.MultiPoint:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_points = self._io:read_s4le()
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
end


ShapefileMain.FileHeader = class.class(KaitaiStruct)

function ShapefileMain.FileHeader:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.FileHeader:_read()
  self.file_code = self._io:read_bytes(4)
  if not(self.file_code == "\000\000\039\010") then
    error("not equal, expected " ..  "\000\000\039\010" .. ", but got " .. self.file_code)
  end
  self.unused_field_1 = self._io:read_bytes(4)
  if not(self.unused_field_1 == "\000\000\000\000") then
    error("not equal, expected " ..  "\000\000\000\000" .. ", but got " .. self.unused_field_1)
  end
  self.unused_field_2 = self._io:read_bytes(4)
  if not(self.unused_field_2 == "\000\000\000\000") then
    error("not equal, expected " ..  "\000\000\000\000" .. ", but got " .. self.unused_field_2)
  end
  self.unused_field_3 = self._io:read_bytes(4)
  if not(self.unused_field_3 == "\000\000\000\000") then
    error("not equal, expected " ..  "\000\000\000\000" .. ", but got " .. self.unused_field_3)
  end
  self.unused_field_4 = self._io:read_bytes(4)
  if not(self.unused_field_4 == "\000\000\000\000") then
    error("not equal, expected " ..  "\000\000\000\000" .. ", but got " .. self.unused_field_4)
  end
  self.unused_field_5 = self._io:read_bytes(4)
  if not(self.unused_field_5 == "\000\000\000\000") then
    error("not equal, expected " ..  "\000\000\000\000" .. ", but got " .. self.unused_field_5)
  end
  self.file_length = self._io:read_s4be()
  self.version = self._io:read_bytes(4)
  if not(self.version == "\232\003\000\000") then
    error("not equal, expected " ..  "\232\003\000\000" .. ", but got " .. self.version)
  end
  self.shape_type = ShapefileMain.ShapeType(self._io:read_s4le())
  self.bounding_box = ShapefileMain.BoundingBoxXYZM(self._io, self, self._root)
end

-- 
-- corresponds to s4be value of 9994.
-- 
-- corresponds to s4le value of 1000.

ShapefileMain.PointZ = class.class(KaitaiStruct)

function ShapefileMain.PointZ:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.PointZ:_read()
  self.x = self._io:read_f8le()
  self.y = self._io:read_f8le()
  self.z = self._io:read_f8le()
  self.m = self._io:read_f8le()
end


ShapefileMain.Record = class.class(KaitaiStruct)

function ShapefileMain.Record:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.Record:_read()
  self.header = ShapefileMain.RecordHeader(self._io, self, self._root)
  self.contents = ShapefileMain.RecordContents(self._io, self, self._root)
end

-- 
-- the size of this contents section in bytes must equal header.content_length * 2.

ShapefileMain.RecordContents = class.class(KaitaiStruct)

function ShapefileMain.RecordContents:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.RecordContents:_read()
  self.shape_type = ShapefileMain.ShapeType(self._io:read_s4le())
  if self.shape_type ~= ShapefileMain.ShapeType.null_shape then
    local _on = self.shape_type
    if _on == ShapefileMain.ShapeType.poly_line_z then
      self.shape_parameters = ShapefileMain.PolyLineZ(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.multi_patch then
      self.shape_parameters = ShapefileMain.MultiPatch(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.poly_line_m then
      self.shape_parameters = ShapefileMain.PolyLineM(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.polygon then
      self.shape_parameters = ShapefileMain.Polygon(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.polygon_z then
      self.shape_parameters = ShapefileMain.PolygonZ(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.point_z then
      self.shape_parameters = ShapefileMain.PointZ(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.poly_line then
      self.shape_parameters = ShapefileMain.PolyLine(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.point_m then
      self.shape_parameters = ShapefileMain.PointM(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.polygon_m then
      self.shape_parameters = ShapefileMain.PolygonM(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.multi_point then
      self.shape_parameters = ShapefileMain.MultiPoint(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.point then
      self.shape_parameters = ShapefileMain.Point(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.multi_point_m then
      self.shape_parameters = ShapefileMain.MultiPointM(self._io, self, self._root)
    elseif _on == ShapefileMain.ShapeType.multi_point_z then
      self.shape_parameters = ShapefileMain.MultiPointZ(self._io, self, self._root)
    end
  end
end


ShapefileMain.MultiPatch = class.class(KaitaiStruct)

function ShapefileMain.MultiPatch:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.MultiPatch:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_parts = self._io:read_s4le()
  self.number_of_points = self._io:read_s4le()
  self.parts = {}
  for i = 0, self.number_of_parts - 1 do
    self.parts[i + 1] = self._io:read_s4le()
  end
  self.part_types = {}
  for i = 0, self.number_of_parts - 1 do
    self.part_types[i + 1] = ShapefileMain.PartType(self._io:read_s4le())
  end
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
  self.z_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.z_values = {}
  for i = 0, self.number_of_points - 1 do
    self.z_values[i + 1] = self._io:read_f8le()
  end
  self.m_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m_values = {}
  for i = 0, self.number_of_points - 1 do
    self.m_values[i + 1] = self._io:read_f8le()
  end
end


ShapefileMain.PolyLineM = class.class(KaitaiStruct)

function ShapefileMain.PolyLineM:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function ShapefileMain.PolyLineM:_read()
  self.bounding_box = ShapefileMain.BoundingBoxXY(self._io, self, self._root)
  self.number_of_parts = self._io:read_s4le()
  self.number_of_points = self._io:read_s4le()
  self.parts = {}
  for i = 0, self.number_of_parts - 1 do
    self.parts[i + 1] = self._io:read_s4le()
  end
  self.points = {}
  for i = 0, self.number_of_points - 1 do
    self.points[i + 1] = ShapefileMain.Point(self._io, self, self._root)
  end
  self.m_range = ShapefileMain.BoundsMinMax(self._io, self, self._root)
  self.m_values = {}
  for i = 0, self.number_of_points - 1 do
    self.m_values[i + 1] = self._io:read_f8le()
  end
end