#!/usr/bin/env python # Utility to interrogate ESRI shape files import os import sys import struct ShapeType = { 0 : "NullShape", 1 : "Point", 3 : "PolyLine", 5 : "Polygon", 8 : "MultiPoint", 11: "PointZ", 13: "PolyLineZ", 15: "PolygonZ", 18: "MultiPointZ", 21: "PointM", 23: "PolyLineM", 25: "PolygonM", 28: "MultiPointM", 31: "MultiPatch"} def test_record(_type, record) : if _type == 0: print "NULL shape" elif _type == 11: #PointZ test_pointz(record) elif _type == 5: test_polygon(record) def test_pointz(record): _type, = struct.unpack("<i", record[0:4]) if _type == 0: print "NULL shape" return if len(record) != 36 : print>>sys.stderr,"BAD SHAPE FILE: expected 36 bytes got",len(record) sys.exit(1) x,y,z,m = struct.unpack("<dddd",record[4:36]) if _type != 11: print>>sys.stderr,"BAD SHAPE FILE: expected PointZ or NullShape got",_type sys.exit(1) def test_polygon(record): _type, = struct.unpack("<i", record[0:4]) if _type == 0: print "NULL shape" return x0, y0, x1, y0, num_parts, num_points = struct.unpack("<ddddii", record[4:44]) if _type != 5: print>>sys.stderr, "BAD SHAPE FILE: expected Polygon or NullShape got", _type sys.exit(1) length = len(record) rec_length = 44 + num_parts * 4 + num_points * 16 if rec_length <> length: print>>sys.stderr, "BAD SHAPE FILE: expected", rec_length, "got", length sys.exit(1) if __name__ == "__main__" : if len(sys.argv) !=2: print>>sys.stderr, "Usage:",sys.argv[0],"<shapefile>" sys.exit(1) shx_filename = sys.argv[1][:-3]+"shx" shp_filename = sys.argv[1][:-3]+"shp" shx = open(shx_filename) shp = open(shp_filename) header = (struct.Struct(">IIIIIII"),struct.Struct("<IIdddddddd")) # SHX header _,_,_,_,_,_,shx_file_length = header[0].unpack_from(shx.read(28)) _,_,lox,loy,hix,hiy,_,_,_,_ = header[1].unpack_from(shx.read(72)) shx_bbox = [lox,loy,hix,hiy] # SHP header _,_,_,_,_,_,shp_file_length = header[0].unpack_from(shp.read(28)) version,_type,lox,loy,hix,hiy,_,_,_,_ = header[1].unpack_from(shp.read(72)) shp_bbox = [lox,loy,hix,hiy] if shx_bbox <> shp_bbox : print "BAD SHAPE FILE: bounding box mismatch in *.shp and *.shx", shp_bbox, shx_bbox sys.exit(1) print "SHX FILE_LENGTH=",shx_file_length,"bytes" print "SHP FILE_LENGTH=",shp_file_length,"bytes" print "TYPE", ShapeType[_type] print "BBOX(",lox,loy,hix,hiy,")" record_header = struct.Struct(">II") record = struct.Struct(">II") calc_total_size = 50 count = 0 while shx.tell() <= shx_file_length * 2 - 4 * 2 : offset,shx_content_length = record.unpack_from(shx.read(8)) shp.seek(offset*2, os.SEEK_SET) record_number,content_length = record_header.unpack_from(shp.read(8)) if shx_content_length <> content_length: print "BAD SHAPE FILE: content_lenght mismatch in SHP and SHX",shx_content_length,content_length sys.exit(1) ## test_record(_type, shp.read(2*content_length)) calc_total_size +=(4 + content_length) count+=1 print "SHAPES COUNT=",count delta = shp_file_length-calc_total_size if delta > 0 : print "BAD SHAPE FILE: extra ", 2*delta,"bytes" elif delta < 0: print "BAD SHAPE FILE: missing ", 2*delta,"bytes" else: print "SHAPE FILE LOOKS GOOD!"