2 * Hic Est Leo -- Reading ESRI Shape Files
4 * (c) 2014--2015 Martin Mares <mj@ucw.cz>
6 * FIXME: Currently, this parser handles only the subset
7 * of shape file syntax which is used by gdal_contours.
14 #include <ucw/fastbuf.h>
16 #include <ucw/unaligned.h>
26 static osm_id_t shp_id_counter;
28 static double shp_get_double(byte *p)
30 // FIXME: This is non-portable!
36 static void shp_record_polyline(byte *buf, u32 len)
39 die("Polyline record too short: %u bytes", len);
41 u32 num_parts = get_u32_le(buf+36);
42 u32 num_points = get_u32_le(buf+40);
43 DBG("%u parts, %u points", num_parts, num_points);
45 die("Polylines with multiple parts are not supported yet");
47 if (len < 44 + 4*num_parts + 16*num_points)
48 die("Polyline record too short for %u parts and %u points: %u bytes", num_parts, num_points, len);
50 struct osm_way *w = osm_way_new(shp_id_counter++);
51 osm_obj_add_tag(&w->o, "shape", "contour");
53 byte *p = buf + 44 + 4*num_parts;
54 for (uint i=0; i < num_points; i++)
56 double x = shp_get_double(p);
57 double y = shp_get_double(p+8);
58 DBG(">>> x=%.10g y=%.10g", x, y);
59 struct osm_node *n = osm_node_new(shp_id_counter++);
62 osm_way_add_node(w, n);
67 void shp_parse(const char *name)
69 msg(L_INFO, "Loading shape file %s", name);
70 struct fastbuf *fb = bopen_file(name, O_RDONLY, NULL);
76 uns len = bread(fb, buf, 100);
77 if (len != 100 || get_u32_be(buf) != 9994)
78 die("Invalid shape file header");
80 u32 version = get_u32_le(buf+28);
82 die("Unknown shape file version %u", version);
84 u32 type = get_u32_le(buf+32);
86 die("Unsupported shape file type %u", type);
92 uns len = bread(fb, buf, 8);
96 die("Truncated record header at %ju", (uintmax_t) pos);
97 u32 recno = get_u32_be(buf);
98 u32 reclen = get_u32_be(buf+4) * 2;
99 if (recno != ++last_recno)
100 die("Unexpected record #%u (should be #%u) at %ju", recno, last_recno, (uintmax_t) pos);
101 if (reclen > GARY_SIZE(buf))
102 GARY_RESIZE(buf, reclen);
103 len = bread(fb, buf, reclen);
105 die("Truncated record: %u < %u at %ju", len, reclen, (uintmax_t) pos);
107 die("Record too short: %u bytes at %ju", reclen, (uintmax_t) pos);
109 u32 rectype = get_u32_le(buf);
110 DBG("@%ju: recno=%u len=%u type=%u", (uintmax_t) pos, recno, reclen, rectype);
112 shp_record_polyline(buf, len);