From dbd89f44c326f5d9917f8d62acdcf86cf6d35b5f Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Tue, 26 Sep 2017 17:12:03 -0700 Subject: [PATCH] Start trying to validate .prj files for shapefiles --- projection.cpp | 139 ++++++++++++++++++++++++++++++++++++++++++++++++- projection.hpp | 3 ++ shapefile.cpp | 6 +++ 3 files changed, 146 insertions(+), 2 deletions(-) diff --git a/projection.cpp b/projection.cpp index f1d84f6..d5ad259 100644 --- a/projection.cpp +++ b/projection.cpp @@ -2,11 +2,146 @@ #include #include #include +#include +#include +#include #include "projection.hpp" +struct wkt { + std::string s; + std::vector sublist; + + wkt(std::string s_) { + s = s_; + } +}; + +static int peekc(FILE *f) { + int c = getc(f); + ungetc(c, f); + return c; +} + +static void parsewkt(FILE *f, std::vector &w) { + int c; + + while ((c = getc(f)) != EOF) { + if (c == ' ' || c == '\t' || c == '\n' || c == ',') { + continue; + } + + if (c == '"') { + std::string s; + + while ((c = getc(f)) != EOF) { + if (c == '"' && peekc(f) == '"') { + getc(f); + s.push_back('"'); + continue; + } + + if (c == '"') { + break; + } + + s.push_back(c); + } + + w.push_back(wkt(s)); + continue; + } + + if (isalpha(c)) { + std::string s; + s.push_back(tolower(c)); + + while ((c = peekc(f)) != EOF && isalpha(c)) { + s.push_back(tolower(c)); + c = getc(f); + } + + w.push_back(wkt(s)); + continue; + } + + if (isdigit(c) || c == '.' || c == '-') { + std::string s; + s.push_back(c); + + while ((c = peekc(f)) != EOF && (isdigit(c) || c == '.')) { + s.push_back(c); + c = getc(f); + } + + w.push_back(wkt(s)); + continue; + } + + if (c == ')' || c == ']') { + return; + } + + if (c == '(' || c == '[') { + if (w.size() == 0) { + fprintf(stderr, "[ or ( in projection without a leading token\n"); + exit(EXIT_FAILURE); + } + + parsewkt(f, w[w.size() - 1].sublist); + continue; + } + + fprintf(stderr, "Unexpected character %c in projection\n", c); + exit(EXIT_FAILURE); + } +} + +wkt *find(std::vector *w, std::string s) { + for (size_t i = 0; i < w->size(); i++) { + if ((*w)[i].s == s) { + return &(*w)[i]; + } + } + + return NULL; +} + +void warn_wgs84(FILE *f) { + std::vector w; + parsewkt(f, w); + + wkt *geogcs = find(&w, "geogcs"); + if (geogcs == NULL) { + fprintf(stderr, "Warning: expected geographic coordinate system for projection\n"); + return; + } + + wkt *datum = find(&(geogcs->sublist), "datum"); + if (datum == NULL) { + fprintf(stderr, "Warning: expected datum in projection\n"); + return; + } + + wkt *spheroid = find(&(datum->sublist), "spheroid"); + if (spheroid == NULL || spheroid->sublist.size() == 0) { + fprintf(stderr, "Warning: expected spheroid in projection\n"); + return; + } + + if (spheroid->sublist[0].s != "WGS_1984") { + fprintf(stderr, "Warning: expected WGS_1984 spheroid in projection, not %s\n", spheroid->sublist[0].s.c_str()); + return; + } +} + +void warn_epsg3857(FILE *f) { + std::vector w; + parsewkt(f, w); +} + struct projection projections[] = { - {"EPSG:4326", lonlat2tile, tile2lonlat, "urn:ogc:def:crs:OGC:1.3:CRS84"}, - {"EPSG:3857", epsg3857totile, tiletoepsg3857, "urn:ogc:def:crs:EPSG::3857"}, + {"EPSG:4326", lonlat2tile, tile2lonlat, "urn:ogc:def:crs:OGC:1.3:CRS84", warn_wgs84}, + {"EPSG:3857", epsg3857totile, tiletoepsg3857, "urn:ogc:def:crs:EPSG::3857", warn_epsg3857}, {NULL, NULL}, }; diff --git a/projection.hpp b/projection.hpp index 4915f83..0f34ba8 100644 --- a/projection.hpp +++ b/projection.hpp @@ -1,6 +1,8 @@ #ifndef PROJECTION_HPP #define PROJECTION_HPP +#include + void lonlat2tile(double lon, double lat, int zoom, long long *x, long long *y); void epsg3857totile(double ix, double iy, int zoom, long long *x, long long *y); void tile2lonlat(long long x, long long y, int zoom, double *lon, double *lat); @@ -14,6 +16,7 @@ struct projection { void (*project)(double ix, double iy, int zoom, long long *ox, long long *oy); void (*unproject)(long long ix, long long iy, int zoom, double *ox, double *oy); const char *alias; + void (*warn)(FILE *prj); }; extern struct projection *projection; diff --git a/shapefile.cpp b/shapefile.cpp index 1be484d..3ea05b9 100644 --- a/shapefile.cpp +++ b/shapefile.cpp @@ -198,6 +198,7 @@ drawvec decode_geometry(unsigned char *data, size_t len, int *type) { void parse_shapefile(struct serialization_state *sst, std::string fname, int layer, std::string layername) { std::string dbfname = fname.substr(0, fname.size() - 3) + "dbf"; + std::string prjname = fname.substr(0, fname.size() - 3) + "prj"; FILE *shp = fopen(fname.c_str(), "rb"); if (shp == NULL) { @@ -209,6 +210,11 @@ void parse_shapefile(struct serialization_state *sst, std::string fname, int lay perror(dbfname.c_str()); exit(EXIT_FAILURE); } + FILE *prj = fopen(prjname.c_str(), "r"); + if (prj != NULL) { + projection->warn(prj); + fclose(prj); + } unsigned char shpheader[100]; if (fread(shpheader, 1, 100, shp) != 100) {