Start trying to validate .prj files for shapefiles

This commit is contained in:
Eric Fischer 2017-09-26 17:12:03 -07:00
parent 27139eb295
commit dbd89f44c3
3 changed files with 146 additions and 2 deletions

View File

@ -2,11 +2,146 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <string>
#include <ctype.h>
#include "projection.hpp"
struct wkt {
std::string s;
std::vector<wkt> 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<wkt> &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<wkt> *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<wkt> 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<wkt> 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},
};

View File

@ -1,6 +1,8 @@
#ifndef PROJECTION_HPP
#define PROJECTION_HPP
#include <stdio.h>
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;

View File

@ -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) {