diff --git a/geobuf.cpp b/geobuf.cpp index 2fab3d8..6e502c0 100644 --- a/geobuf.cpp +++ b/geobuf.cpp @@ -9,6 +9,7 @@ #include "protozero/pbf_reader.hpp" #include "protozero/pbf_writer.hpp" #include "milo/dtoa_milo.h" +#include "jsonpull/jsonpull.h" #define POINT 0 #define MULTIPOINT 1 @@ -41,7 +42,7 @@ serial_val readValue(protozero::pbf_reader &pbf, std::vector &keys) case 4: sv.type = mvt_double; - sv.s = std::to_string(- (long long) pbf.get_uint64()); + sv.s = std::to_string(-(long long) pbf.get_uint64()); break; case 5: @@ -226,8 +227,9 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector values; - std::vector properties; int type = 0; + serial_feature sf; + std::map other; while (pbf.next()) { switch (pbf.tag()) { @@ -259,10 +261,53 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector properties; auto pi = pbf.get_packed_uint32(); for (auto it = pi.first; it != pi.second; ++it) { properties.push_back(*it); } + + for (size_t i = 0; i + 1 < properties.size(); i += 2) { + if (properties[i] >= keys.size()) { + fprintf(stderr, "Out of bounds key: %zu in %zu\n", properties[i], keys.size()); + exit(EXIT_FAILURE); + } + + if (properties[i + 1] >= values.size()) { + fprintf(stderr, "Out of bounds value: %zu in %zu\n", properties[i + 1], values.size()); + exit(EXIT_FAILURE); + } + + sf.full_keys.push_back(keys[properties[i]]); + sf.full_values.push_back(values[properties[i + 1]]); + } + + values.clear(); + break; + } + + case 15: { + std::vector misc; + auto pi = pbf.get_packed_uint32(); + for (auto it = pi.first; it != pi.second; ++it) { + misc.push_back(*it); + } + + for (size_t i = 0; i + 1 < misc.size(); i += 2) { + if (misc[i] >= keys.size()) { + fprintf(stderr, "Out of bounds key: %zu in %zu\n", misc[i], keys.size()); + exit(EXIT_FAILURE); + } + + if (misc[i + 1] >= values.size()) { + fprintf(stderr, "Out of bounds value: %zu in %zu\n", misc[i + 1], values.size()); + exit(EXIT_FAILURE); + } + + other.insert(std::pair(keys[misc[i]], values[misc[i + 1]])); + } + + values.clear(); break; } @@ -271,7 +316,6 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vectorlayer_seq); sf.geometry = dv; sf.t = type; - - for (size_t i = 0; i + 1 < properties.size(); i += 2) { - if (properties[i] >= keys.size()) { - fprintf(stderr, "Out of bounds key: %zu in %zu\n", properties[i], keys.size()); - exit(EXIT_FAILURE); - } - - if (properties[i + 1] >= values.size()) { - fprintf(stderr, "Out of bounds value: %zu in %zu\n", properties[i + 1], values.size()); - exit(EXIT_FAILURE); - } - - sf.full_keys.push_back(keys[properties[i]]); - sf.full_values.push_back(values[properties[i + 1]]); - } - sf.m = sf.full_values.size(); + auto tip = other.find("tippecanoe"); + if (tip != other.end()) { + json_pull *jp = json_begin_string(tip->second.s.c_str()); + json_object *o = json_read_tree(jp); + + if (o != NULL) { + json_object *min = json_hash_get(o, "minzoom"); + if (min != NULL && (min->type == JSON_STRING || min->type == JSON_NUMBER)) { + sf.has_tippecanoe_minzoom = true; + sf.tippecanoe_minzoom = atoi(min->string); + } + + json_object *max = json_hash_get(o, "maxzoom"); + if (max != NULL && (max->type == JSON_STRING || max->type == JSON_NUMBER)) { + sf.has_tippecanoe_maxzoom = true; + sf.tippecanoe_maxzoom = atoi(max->string); + } + } + + json_free(o); + json_end(jp); + } + serialize_feature(sst, sf); } diff --git a/jsonpull/jsonpull.c b/jsonpull/jsonpull.c index ad4d152..3067f4f 100644 --- a/jsonpull/jsonpull.c +++ b/jsonpull/jsonpull.c @@ -69,7 +69,7 @@ json_pull *json_begin_file(FILE *f) { } static ssize_t read_string(json_pull *j, char *buffer, size_t n) { - char *cp = j->source; + const char *cp = j->source; size_t out = 0; while (out < n && cp[out] != '\0') { @@ -77,12 +77,12 @@ static ssize_t read_string(json_pull *j, char *buffer, size_t n) { out++; } - j->source = cp + out; + j->source = (void *) (cp + out); return out; } -json_pull *json_begin_string(char *s) { - return json_begin(read_string, s); +json_pull *json_begin_string(const char *s) { + return json_begin(read_string, (void *) s); } void json_end(json_pull *p) { diff --git a/jsonpull/jsonpull.h b/jsonpull/jsonpull.h index dabeb30..1983a35 100644 --- a/jsonpull/jsonpull.h +++ b/jsonpull/jsonpull.h @@ -56,7 +56,7 @@ typedef struct json_pull { } json_pull; json_pull *json_begin_file(FILE *f); -json_pull *json_begin_string(char *s); +json_pull *json_begin_string(const char *s); json_pull *json_begin(ssize_t (*read)(struct json_pull *, char *buffer, size_t n), void *source); void json_end(json_pull *p); diff --git a/mvt.cpp b/mvt.cpp index 1f2c1aa..6feceb9 100644 --- a/mvt.cpp +++ b/mvt.cpp @@ -11,6 +11,7 @@ #include "protozero/varint.hpp" #include "protozero/pbf_reader.hpp" #include "protozero/pbf_writer.hpp" +#include "milo/dtoa_milo.h" mvt_geometry::mvt_geometry(int nop, long long nx, long long ny) { this->op = nop; @@ -394,6 +395,57 @@ bool mvt_value::operator<(const mvt_value &o) const { return false; } +static std::string quote(std::string const &s) { + std::string buf; + + for (size_t i = 0; i < s.size(); i++) { + unsigned char ch = s[i]; + + if (ch == '\\' || ch == '\"') { + buf.push_back('\\'); + buf.push_back(ch); + } else if (ch < ' ') { + char tmp[7]; + sprintf(tmp, "\\u%04x", ch); + buf.append(std::string(tmp)); + } else { + buf.push_back(ch); + } + } + + return buf; +} + +std::string mvt_value::toString() { + if (type == mvt_string) { + return quote(string_value); + } else if (type == mvt_int) { + return std::to_string((long long) numeric_value.int_value); + } else if (type == mvt_double) { + double v = numeric_value.double_value; + if (v == (long long) v) { + return std::to_string((long long) v); + } else { + return milo::dtoa_milo(v); + } + } else if (type == mvt_float) { + double v = numeric_value.float_value; + if (v == (long long) v) { + return std::to_string((long long) v); + } else { + return milo::dtoa_milo(v); + } + } else if (type == mvt_sint) { + return std::to_string((long long) numeric_value.sint_value); + } else if (type == mvt_uint) { + return std::to_string((long long) numeric_value.uint_value); + } else if (type == mvt_bool) { + return numeric_value.bool_value ? "true" : "false"; + } else { + return "unknown"; + } +} + void mvt_layer::tag(mvt_feature &feature, std::string key, mvt_value value) { size_t ko, vo; diff --git a/mvt.hpp b/mvt.hpp index 68131ec..32ef55f 100644 --- a/mvt.hpp +++ b/mvt.hpp @@ -79,6 +79,7 @@ struct mvt_value { } numeric_value; bool operator<(const mvt_value &o) const; + std::string toString(); }; struct mvt_layer {