Convert jsonpull to C++ with shared_ptr and std::vector/std::string

Replace the manual malloc/realloc/free memory management in jsonpull
with std::shared_ptr ownership. Each json_object now owns its children
through std::vector<json_object_ptr>; raw back-pointers to parent and
parser remain valid by structural invariant and are cleared on
json_disconnect so detached subtrees can outlive their parser.
Strings become std::string, child arrays become std::vector, and the
old union becomes a struct so non-trivial members can coexist while
preserving the existing o->value.xxx access paths.

The old jsonpull.c is replaced by jsonpull.cpp, json_stringify now
returns std::string, and all callers across tippecanoe, tile-join,
tippecanoe-decode, tippecanoe-json-tool, tippecanoe-overzoom and the
unit tests are updated to use json_object_ptr / json_pull_ptr.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Erica Fischer
2026-05-30 17:48:32 -07:00
co-authored by Cursor
parent 9381158165
commit 3da03c6075
25 changed files with 1295 additions and 531 deletions
+1 -1
View File
@@ -92,7 +92,7 @@ clean:
rm -f ./tippecanoe ./tippecanoe-* ./tile-join ./unit *.o *.d */*.o */*.d tests/**/*.mbtiles tests/**/*.check
indent:
clang-format -i -style="{BasedOnStyle: Google, IndentWidth: 8, UseTab: Always, AllowShortIfStatementsOnASingleLine: false, ColumnLimit: 0, ContinuationIndentWidth: 8, SpaceAfterCStyleCast: true, IndentCaseLabels: false, AllowShortBlocksOnASingleLine: false, AllowShortFunctionsOnASingleLine: false, SortIncludes: false}" $(filter-out flatgeobuf.cpp,$(C)) $(H) jsonpull/*.[ch]
clang-format -i -style="{BasedOnStyle: Google, IndentWidth: 8, UseTab: Always, AllowShortIfStatementsOnASingleLine: false, ColumnLimit: 0, ContinuationIndentWidth: 8, SpaceAfterCStyleCast: true, IndentCaseLabels: false, AllowShortBlocksOnASingleLine: false, AllowShortFunctionsOnASingleLine: false, SortIncludes: false}" $(filter-out flatgeobuf.cpp,$(C)) $(H) jsonpull/jsonpull.h jsonpull/jsonpull.cpp
TESTS = $(wildcard tests/*/out/*.json)
SPACE = $(NULL) $(NULL)
+7 -9
View File
@@ -42,10 +42,10 @@ void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribut
void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribute_accum, const char *arg, char **argv) {
if (*arg == '{') {
json_pull *jp = json_begin_string(arg);
json_object *o = json_read_tree(jp);
json_pull_ptr jp = json_begin_string(arg);
json_object_ptr o = json_read_tree(jp);
if (o == NULL) {
if (o == nullptr) {
fprintf(stderr, "%s: -E%s: %s\n", *argv, arg, jp->error);
exit(EXIT_JSON);
}
@@ -55,9 +55,9 @@ void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribut
exit(EXIT_JSON);
}
for (size_t i = 0; i < o->value.object.length; i++) {
json_object *k = o->value.object.keys[i];
json_object *v = o->value.object.values[i];
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
json_object_ptr k = o->value.object.keys[i];
json_object_ptr v = o->value.object.values[i];
if (k->type != JSON_STRING) {
fprintf(stderr, "%s: -E%s: key %zu not a string\n", *argv, arg, i);
@@ -68,11 +68,9 @@ void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribut
exit(EXIT_JSON);
}
set_attribute_accum(attribute_accum, k->value.string.string, v->value.string.string);
set_attribute_accum(attribute_accum, k->value.string.string.c_str(), v->value.string.string.c_str());
}
json_free(o);
json_end(jp);
return;
}
+2 -2
View File
@@ -1221,7 +1221,7 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
std::vector<std::string> const &exclude_prefix,
bool do_compress,
std::vector<std::pair<unsigned, unsigned>> *next_overzoomed_tiles,
bool demultiply, json_object *filter, bool preserve_input_order,
bool demultiply, json_object_ptr filter, bool preserve_input_order,
std::unordered_map<std::string, attribute_op> const &attribute_accum,
std::vector<std::string> const &unidecode_data, double simplification,
double tiny_polygon_size,
@@ -1457,7 +1457,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
std::vector<std::string> const &exclude_prefix,
bool do_compress,
std::vector<std::pair<unsigned, unsigned>> *next_overzoomed_tiles,
bool demultiply, json_object *filter, bool preserve_input_order,
bool demultiply, json_object_ptr filter, bool preserve_input_order,
std::unordered_map<std::string, attribute_op> const &attribute_accum,
std::vector<std::string> const &unidecode_data, double simplification,
double tiny_polygon_size,
+6 -7
View File
@@ -248,9 +248,9 @@ sqlite3 *dirmeta2tmp(const char *fname) {
if (f == NULL) {
perror(name.c_str());
} else {
json_pull *jp = json_begin_file(f);
json_object *o = json_read_tree(jp);
if (o == NULL) {
json_pull_ptr jp = json_begin_file(f);
json_object_ptr o = json_read_tree(jp);
if (o == nullptr) {
fprintf(stderr, "%s: metadata parsing error: %s\n", name.c_str(), jp->error);
exit(EXIT_JSON);
}
@@ -260,19 +260,18 @@ sqlite3 *dirmeta2tmp(const char *fname) {
exit(EXIT_JSON);
}
for (size_t i = 0; i < o->value.object.length; i++) {
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
if (o->value.object.keys[i]->type != JSON_STRING || o->value.object.values[i]->type != JSON_STRING) {
fprintf(stderr, "%s: non-string in metadata\n", name.c_str());
}
char *sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", o->value.object.keys[i]->value.string.string, o->value.object.values[i]->value.string.string);
char *sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", o->value.object.keys[i]->value.string.string.c_str(), o->value.object.values[i]->value.string.string.c_str());
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set %s in metadata: %s\n", o->value.object.keys[i]->value.string.string, err);
fprintf(stderr, "set %s in metadata: %s\n", o->value.object.keys[i]->value.string.string.c_str(), err);
}
sqlite3_free(sql);
}
json_end(jp);
fclose(f);
}
+82 -90
View File
@@ -9,7 +9,7 @@
#include "milo/dtoa_milo.h"
#include "text.hpp"
int compare(mvt_value const &one, json_object *two, bool &fail) {
int compare(mvt_value const &one, json_object_ptr two, bool &fail) {
switch (one.type) {
case mvt_string:
if (two->type != JSON_STRING) {
@@ -17,7 +17,7 @@ int compare(mvt_value const &one, json_object *two, bool &fail) {
return false; // string vs non-string
}
return strcmp(one.c_str(), two->value.string.string);
return strcmp(one.c_str(), two->value.string.string.c_str());
case mvt_double:
case mvt_float:
@@ -91,8 +91,8 @@ int compare(mvt_value const &one, json_object *two, bool &fail) {
// 0: false
// 1: true
// -1: incomparable (sql null), treated as false in final output
static int eval(std::function<mvt_value(std::string const &)> feature, json_object *f, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data) {
if (f != NULL) {
static int eval(std::function<mvt_value(std::string const &)> feature, json_object_ptr f, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data) {
if (f != nullptr) {
if (f->type == JSON_TRUE) {
return 1;
} else if (f->type == JSON_FALSE) {
@@ -110,7 +110,7 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
}
if (f->type == JSON_STRING) {
if (f->value.string.string[0] == '\0') {
if (f->value.string.string.empty()) {
return 0;
} else {
return 1;
@@ -118,70 +118,70 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
}
}
if (f == NULL || f->type != JSON_ARRAY) {
fprintf(stderr, "Filter is not an array: %s\n", json_stringify(f));
if (f == nullptr || f->type != JSON_ARRAY) {
fprintf(stderr, "Filter is not an array: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
if (f->value.array.length < 1) {
fprintf(stderr, "Array too small in filter: %s\n", json_stringify(f));
if (f->value.array.array.size() < 1) {
fprintf(stderr, "Array too small in filter: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
if (f->value.array.array[0]->type != JSON_STRING) {
fprintf(stderr, "Filter operation is not a string: %s\n", json_stringify(f));
fprintf(stderr, "Filter operation is not a string: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
if (strcmp(f->value.array.array[0]->value.string.string, "has") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, "!has") == 0) {
if (f->value.array.length != 2) {
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f));
const std::string &op = f->value.array.array[0]->value.string.string;
if (op == "has" ||
op == "!has") {
if (f->value.array.array.size() != 2) {
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
if (strcmp(f->value.array.array[0]->value.string.string, "has") == 0) {
if (op == "has") {
if (f->value.array.array[1]->type != JSON_STRING) {
fprintf(stderr, "\"has\" key is not a string: %s\n", json_stringify(f));
fprintf(stderr, "\"has\" key is not a string: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
return feature(std::string(f->value.array.array[1]->value.string.string)).type != mvt_no_such_key;
return feature(f->value.array.array[1]->value.string.string).type != mvt_no_such_key;
}
if (strcmp(f->value.array.array[0]->value.string.string, "!has") == 0) {
if (op == "!has") {
if (f->value.array.array[1]->type != JSON_STRING) {
fprintf(stderr, "\"!has\" key is not a string: %s\n", json_stringify(f));
fprintf(stderr, "\"!has\" key is not a string: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
return feature(std::string(f->value.array.array[1]->value.string.string)).type == mvt_no_such_key;
return feature(f->value.array.array[1]->value.string.string).type == mvt_no_such_key;
}
}
if (strcmp(f->value.array.array[0]->value.string.string, "==") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, "!=") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, ">") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, ">=") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, "<") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, "<=") == 0) {
if (f->value.array.length != 3) {
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f));
if (op == "==" ||
op == "!=" ||
op == ">" ||
op == ">=" ||
op == "<" ||
op == "<=") {
if (f->value.array.array.size() != 3) {
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
if (f->value.array.array[1]->type != JSON_STRING) {
fprintf(stderr, "comparison key is not a string: %s\n", json_stringify(f));
fprintf(stderr, "comparison key is not a string: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
mvt_value ff = feature(std::string(f->value.array.array[1]->value.string.string));
mvt_value ff = feature(f->value.array.array[1]->value.string.string);
if (ff.type == mvt_no_such_key) {
static bool warned = false;
if (!warned) {
const char *s = json_stringify(f);
fprintf(stderr, "Warning: attribute not found for comparison: %s\n", s);
free((void *) s);
fprintf(stderr, "Warning: attribute not found for comparison: %s\n", json_stringify(f).c_str());
warned = true;
}
if (strcmp(f->value.array.array[0]->value.string.string, "!=") == 0) {
if (op == "!=") {
return true; // attributes that aren't found are not equal
}
return false; // not found: comparison is false
@@ -193,56 +193,54 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
if (fail) {
static bool warned = false;
if (!warned) {
const char *s = json_stringify(f);
fprintf(stderr, "Warning: mismatched type in comparison: %s\n", s);
free((void *) s);
fprintf(stderr, "Warning: mismatched type in comparison: %s\n", json_stringify(f).c_str());
warned = true;
}
if (strcmp(f->value.array.array[0]->value.string.string, "!=") == 0) {
if (op == "!=") {
return true; // mismatched types are not equal
}
return false;
}
if (strcmp(f->value.array.array[0]->value.string.string, "==") == 0) {
if (op == "==") {
return cmp == 0;
}
if (strcmp(f->value.array.array[0]->value.string.string, "!=") == 0) {
if (op == "!=") {
return cmp != 0;
}
if (strcmp(f->value.array.array[0]->value.string.string, ">") == 0) {
if (op == ">") {
return cmp > 0;
}
if (strcmp(f->value.array.array[0]->value.string.string, ">=") == 0) {
if (op == ">=") {
return cmp >= 0;
}
if (strcmp(f->value.array.array[0]->value.string.string, "<") == 0) {
if (op == "<") {
return cmp < 0;
}
if (strcmp(f->value.array.array[0]->value.string.string, "<=") == 0) {
if (op == "<=") {
return cmp <= 0;
}
fprintf(stderr, "Internal error: can't happen: %s\n", json_stringify(f));
fprintf(stderr, "Internal error: can't happen: %s\n", json_stringify(f).c_str());
exit(EXIT_IMPOSSIBLE);
}
if (strcmp(f->value.array.array[0]->value.string.string, "all") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, "any") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, "none") == 0) {
if (op == "all" ||
op == "any" ||
op == "none") {
bool v;
if (strcmp(f->value.array.array[0]->value.string.string, "all") == 0) {
if (op == "all") {
v = true;
} else {
v = false;
}
for (size_t i = 1; i < f->value.array.length; i++) {
for (size_t i = 1; i < f->value.array.array.size(); i++) {
int out = eval(feature, f->value.array.array[i], exclude_attributes, unidecode_data);
if (out >= 0) { // nulls are ignored in boolean and/or expressions
if (strcmp(f->value.array.array[0]->value.string.string, "all") == 0) {
if (op == "all") {
v = v && out;
if (!v) {
break;
@@ -256,51 +254,47 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
}
}
if (strcmp(f->value.array.array[0]->value.string.string, "none") == 0) {
if (op == "none") {
return !v;
} else {
return v;
}
}
if (strcmp(f->value.array.array[0]->value.string.string, "in") == 0 ||
strcmp(f->value.array.array[0]->value.string.string, "!in") == 0) {
if (f->value.array.length < 2) {
fprintf(stderr, "Array too small in filter: %s\n", json_stringify(f));
if (op == "in" ||
op == "!in") {
if (f->value.array.array.size() < 2) {
fprintf(stderr, "Array too small in filter: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
if (f->value.array.array[1]->type != JSON_STRING) {
fprintf(stderr, "\"!in\" key is not a string: %s\n", json_stringify(f));
fprintf(stderr, "\"!in\" key is not a string: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
mvt_value ff = feature(std::string(f->value.array.array[1]->value.string.string));
mvt_value ff = feature(f->value.array.array[1]->value.string.string);
if (ff.type == mvt_no_such_key) {
static bool warned = false;
if (!warned) {
const char *s = json_stringify(f);
fprintf(stderr, "Warning: attribute not found for comparison: %s\n", s);
free((void *) s);
fprintf(stderr, "Warning: attribute not found for comparison: %s\n", json_stringify(f).c_str());
warned = true;
}
if (strcmp(f->value.array.array[0]->value.string.string, "!in") == 0) {
if (op == "!in") {
return true; // attributes that aren't found are not in
}
return false; // not found: comparison is false
}
bool found = false;
for (size_t i = 2; i < f->value.array.length; i++) {
for (size_t i = 2; i < f->value.array.array.size(); i++) {
bool fail = false;
int cmp = compare(ff, f->value.array.array[i], fail);
if (fail) {
static bool warned = false;
if (!warned) {
const char *s = json_stringify(f);
fprintf(stderr, "Warning: mismatched type in comparison: %s\n", s);
free((void *) s);
fprintf(stderr, "Warning: mismatched type in comparison: %s\n", json_stringify(f).c_str());
warned = true;
}
cmp = 1;
@@ -312,21 +306,21 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
}
}
if (strcmp(f->value.array.array[0]->value.string.string, "in") == 0) {
if (op == "in") {
return found;
} else {
return !found;
}
}
if (strcmp(f->value.array.array[0]->value.string.string, "attribute-filter") == 0) {
if (f->value.array.length != 3) {
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f));
if (op == "attribute-filter") {
if (f->value.array.array.size() != 3) {
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
if (f->value.array.array[1]->type != JSON_STRING) {
fprintf(stderr, "\"attribute-filter\" key is not a string: %s\n", json_stringify(f));
fprintf(stderr, "\"attribute-filter\" key is not a string: %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
@@ -338,65 +332,63 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
return true;
}
fprintf(stderr, "Unknown filter %s\n", json_stringify(f));
fprintf(stderr, "Unknown filter %s\n", json_stringify(f).c_str());
exit(EXIT_FILTER);
}
bool evaluate(std::function<mvt_value(std::string const &)> feature, std::string const &layer, json_object *filter, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data) {
if (filter == NULL || filter->type != JSON_HASH) {
fprintf(stderr, "Error: filter is not a hash: %s\n", json_stringify(filter));
bool evaluate(std::function<mvt_value(std::string const &)> feature, std::string const &layer, json_object_ptr filter, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data) {
if (filter == nullptr || filter->type != JSON_HASH) {
fprintf(stderr, "Error: filter is not a hash: %s\n", json_stringify(filter).c_str());
exit(EXIT_JSON);
}
bool ok = true;
json_object *f;
json_object_ptr f;
f = json_hash_get(filter, layer.c_str());
if (ok && f != NULL) {
if (ok && f != nullptr) {
ok = eval(feature, f, exclude_attributes, unidecode_data) > 0;
}
f = json_hash_get(filter, "*");
if (ok && f != NULL) {
if (ok && f != nullptr) {
ok = eval(feature, f, exclude_attributes, unidecode_data) > 0;
}
return ok;
}
json_object *read_filter(const char *fname) {
json_object_ptr read_filter(const char *fname) {
FILE *fp = fopen(fname, "r");
if (fp == NULL) {
perror(fname);
exit(EXIT_OPEN);
}
json_pull *jp = json_begin_file(fp);
json_object *filter = json_read_tree(jp);
if (filter == NULL) {
json_pull_ptr jp = json_begin_file(fp);
json_object_ptr filter = json_read_tree(jp);
if (filter == nullptr) {
fprintf(stderr, "%s: %s\n", fname, jp->error);
exit(EXIT_JSON);
}
json_disconnect(filter);
json_end(jp);
fclose(fp);
return filter;
}
json_object *parse_filter(const char *s) {
json_pull *jp = json_begin_string(s);
json_object *filter = json_read_tree(jp);
if (filter == NULL) {
json_object_ptr parse_filter(const char *s) {
json_pull_ptr jp = json_begin_string(s);
json_object_ptr filter = json_read_tree(jp);
if (filter == nullptr) {
fprintf(stderr, "Could not parse filter %s\n", s);
fprintf(stderr, "%s\n", jp->error);
exit(EXIT_JSON);
}
json_disconnect(filter);
json_end(jp);
return filter;
}
bool evaluate(std::unordered_map<std::string, mvt_value> const &feature, std::string const &layer, json_object *filter, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data) {
bool evaluate(std::unordered_map<std::string, mvt_value> const &feature, std::string const &layer, json_object_ptr filter, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data) {
std::function<mvt_value(std::string const &)> getter = [&](std::string const &key) {
auto f = feature.find(key);
if (f != feature.end()) {
@@ -412,7 +404,7 @@ bool evaluate(std::unordered_map<std::string, mvt_value> const &feature, std::st
return evaluate(getter, layer, filter, exclude_attributes, unidecode_data);
}
bool evaluate(mvt_feature const &feat, mvt_layer const &layer, json_object *filter, std::set<std::string> &exclude_attributes, int z, std::vector<std::string> const &unidecode_data) {
bool evaluate(mvt_feature const &feat, mvt_layer const &layer, json_object_ptr filter, std::set<std::string> &exclude_attributes, int z, std::vector<std::string> const &unidecode_data) {
std::function<mvt_value(std::string const &)> getter = [&](std::string const &key) {
const static std::string dollar_id = "$id";
if (key == dollar_id && feat.has_id) {
+4 -4
View File
@@ -7,10 +7,10 @@
#include "jsonpull/jsonpull.h"
#include "mvt.hpp"
bool evaluate(std::unordered_map<std::string, mvt_value> const &feature, std::string const &layer, json_object *filter, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data);
json_object *parse_filter(const char *s);
json_object *read_filter(const char *fname);
bool evaluate(std::unordered_map<std::string, mvt_value> const &feature, std::string const &layer, json_object_ptr filter, std::set<std::string> &exclude_attributes, std::vector<std::string> const &unidecode_data);
json_object_ptr parse_filter(const char *s);
json_object_ptr read_filter(const char *fname);
bool evaluate(mvt_feature const &feat, mvt_layer const &layer, json_object *filter, std::set<std::string> &exclude_attributes, int z, std::vector<std::string> const &unidecode_data);
bool evaluate(mvt_feature const &feat, mvt_layer const &layer, json_object_ptr filter, std::set<std::string> &exclude_attributes, int z, std::vector<std::string> const &unidecode_data);
#endif
+9 -12
View File
@@ -394,28 +394,25 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
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);
json_pull_ptr jp = json_begin_string(tip->second.s.c_str());
json_object_ptr o = json_read_tree(jp);
if (o != NULL) {
json_object *min = json_hash_get(o, "minzoom");
if (min != NULL && (min->type == JSON_NUMBER)) {
if (o != nullptr) {
json_object_ptr min = json_hash_get(o, "minzoom");
if (min != nullptr && (min->type == JSON_NUMBER)) {
sf.tippecanoe_minzoom = integer_zoom(sst->fname, milo::dtoa_milo(min->value.number.number));
}
json_object *max = json_hash_get(o, "maxzoom");
if (max != NULL && (max->type == JSON_NUMBER)) {
json_object_ptr max = json_hash_get(o, "maxzoom");
if (max != nullptr && (max->type == JSON_NUMBER)) {
sf.tippecanoe_maxzoom = integer_zoom(sst->fname, milo::dtoa_milo(max->value.number.number));
}
json_object *tlayer = json_hash_get(o, "layer");
if (tlayer != NULL && (tlayer->type == JSON_STRING)) {
json_object_ptr tlayer = json_hash_get(o, "layer");
if (tlayer != nullptr && (tlayer->type == JSON_STRING)) {
layername = tlayer->value.string.string;
}
}
json_free(o);
json_end(jp);
}
serialize_feature(sst, sf, layername);
+40 -40
View File
@@ -25,35 +25,35 @@ static const char *geometry_names[GEOM_TYPES] = {
};
// XXX duplicated
static void json_context(json_object *j) {
char *s = json_stringify(j);
static void json_context(json_object_ptr j) {
std::string s = json_stringify(j);
if (strlen(s) >= 500) {
snprintf(s + 497, strlen(s) + 1 - 497, "...");
if (s.size() >= 500) {
s.resize(497);
s.append("...");
}
fprintf(stderr, "in JSON object %s\n", s);
free(s); // stringify
fprintf(stderr, "in JSON object %s\n", s.c_str());
}
void parse_json(json_feature_action *jfa, json_pull *jp) {
void parse_json(json_feature_action *jfa, json_pull_ptr jp) {
long long found_hashes = 0;
long long found_features = 0;
long long found_geometries = 0;
while (1) {
json_object *j = json_read(jp);
if (j == NULL) {
if (jp->error != NULL) {
json_object_ptr j = json_read(jp);
if (j == nullptr) {
if (jp->error != nullptr) {
fprintf(stderr, "%s:%d: %s: ", jfa->fname.c_str(), jp->line, jp->error);
if (jp->root != NULL) {
if (jp->root != nullptr) {
json_context(jp->root);
} else {
fprintf(stderr, "\n");
}
}
json_free(jp->root);
jp->root.reset();
break;
}
@@ -65,8 +65,8 @@ void parse_json(json_feature_action *jfa, json_pull *jp) {
}
}
json_object *type = json_hash_get(j, "type");
if (type == NULL || type->type != JSON_STRING) {
json_object_ptr type = json_hash_get(j, "type");
if (type == nullptr || type->type != JSON_STRING) {
continue;
}
@@ -74,25 +74,25 @@ void parse_json(json_feature_action *jfa, json_pull *jp) {
int i;
int is_geometry = 0;
for (i = 0; i < GEOM_TYPES; i++) {
if (strcmp(type->value.string.string, geometry_names[i]) == 0) {
if (type->value.string.string == geometry_names[i]) {
is_geometry = 1;
break;
}
}
if (is_geometry) {
if (j->parent != NULL) {
if (j->parent->type == JSON_ARRAY && j->parent->parent != NULL) {
if (j->parent != nullptr) {
if (j->parent->type == JSON_ARRAY && j->parent->parent != nullptr) {
if (j->parent->parent->type == JSON_HASH) {
json_object *geometries = json_hash_get(j->parent->parent, "geometries");
if (geometries != NULL) {
json_object_ptr geometries = json_hash_get(j->parent->parent->shared_from_this(), "geometries");
if (geometries != nullptr) {
// Parent of Parent must be a GeometryCollection
is_geometry = 0;
}
}
} else if (j->parent->type == JSON_HASH) {
json_object *geometry = json_hash_get(j->parent, "geometry");
if (geometry != NULL) {
json_object_ptr geometry = json_hash_get(j->parent->shared_from_this(), "geometry");
if (geometry != nullptr) {
// Parent must be a Feature
is_geometry = 0;
}
@@ -101,10 +101,10 @@ void parse_json(json_feature_action *jfa, json_pull *jp) {
}
if (is_geometry) {
json_object *jo = j;
while (jo != NULL) {
if (jo->parent != NULL && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent, "properties") == jo) {
json_object *jo = j.get();
while (jo != nullptr) {
if (jo->parent != nullptr && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent->shared_from_this(), "properties").get() == jo) {
// Ancestor is the value corresponding to a properties key
is_geometry = 0;
break;
@@ -120,14 +120,14 @@ void parse_json(json_feature_action *jfa, json_pull *jp) {
}
found_geometries++;
jfa->add_feature(j, false, NULL, NULL, NULL, j);
jfa->add_feature(j, false, nullptr, nullptr, nullptr, j);
json_free(j);
continue;
}
}
if (strcmp(type->value.string.string, "Feature") != 0) {
if (strcmp(type->value.string.string, "FeatureCollection") == 0) {
if (type->value.string.string != "Feature") {
if (type->value.string.string == "FeatureCollection") {
jfa->check_crs(j);
json_free(j);
}
@@ -140,16 +140,16 @@ void parse_json(json_feature_action *jfa, json_pull *jp) {
}
found_features++;
json_object *geometry = json_hash_get(j, "geometry");
if (geometry == NULL) {
json_object_ptr geometry = json_hash_get(j, "geometry");
if (geometry == nullptr) {
fprintf(stderr, "%s:%d: feature with no geometry: ", jfa->fname.c_str(), jp->line);
json_context(j);
json_free(j);
continue;
}
json_object *properties = json_hash_get(j, "properties");
if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
json_object_ptr properties = json_hash_get(j, "properties");
if (properties == nullptr || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
fprintf(stderr, "%s:%d: feature without properties hash: ", jfa->fname.c_str(), jp->line);
json_context(j);
json_free(j);
@@ -158,10 +158,10 @@ void parse_json(json_feature_action *jfa, json_pull *jp) {
bool is_feature = true;
{
json_object *jo = j;
while (jo != NULL) {
if (jo->parent != NULL && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent, "properties") == jo) {
json_object *jo = j.get();
while (jo != nullptr) {
if (jo->parent != nullptr && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent->shared_from_this(), "properties").get() == jo) {
// Ancestor is the value corresponding to a properties key
is_feature = false;
break;
@@ -174,11 +174,11 @@ void parse_json(json_feature_action *jfa, json_pull *jp) {
continue;
}
json_object *tippecanoe = json_hash_get(j, "tippecanoe");
json_object *id = json_hash_get(j, "id");
json_object_ptr tippecanoe = json_hash_get(j, "tippecanoe");
json_object_ptr id = json_hash_get(j, "id");
json_object *geometries = json_hash_get(geometry, "geometries");
if (geometries != NULL && geometries->type == JSON_ARRAY) {
json_object_ptr geometries = json_hash_get(geometry, "geometries");
if (geometries != nullptr && geometries->type == JSON_ARRAY) {
jfa->add_feature(geometries, true, properties, id, tippecanoe, j);
} else {
jfa->add_feature(geometry, false, properties, id, tippecanoe, j);
+3 -3
View File
@@ -4,8 +4,8 @@
struct json_feature_action {
std::string fname;
virtual int add_feature(json_object *geometry, bool geometrycollection, json_object *properties, json_object *id, json_object *tippecanoe, json_object *feature) = 0;
virtual void check_crs(json_object *j) = 0;
virtual int add_feature(json_object_ptr geometry, bool geometrycollection, json_object_ptr properties, json_object_ptr id, json_object_ptr tippecanoe, json_object_ptr feature) = 0;
virtual void check_crs(json_object_ptr j) = 0;
};
void parse_json(json_feature_action *action, json_pull *jp);
void parse_json(json_feature_action *action, json_pull_ptr jp);
+38 -40
View File
@@ -40,9 +40,9 @@
#include "milo/dtoa_milo.h"
#include "errors.hpp"
int serialize_geojson_feature(struct serialization_state *sst, json_object *geometry, json_object *properties, json_object *id, int layer, json_object *tippecanoe, json_object *feature, std::string const &layername) {
json_object *geometry_type = json_hash_get(geometry, "type");
if (geometry_type == NULL) {
int serialize_geojson_feature(struct serialization_state *sst, json_object_ptr geometry, json_object_ptr properties, json_object_ptr id, int layer, json_object_ptr tippecanoe, json_object_ptr feature, std::string const &layername) {
json_object_ptr geometry_type = json_hash_get(geometry, "type");
if (geometry_type == nullptr) {
static int warned = 0;
if (!warned) {
fprintf(stderr, "%s:%d: null geometry (additional not reported): ", sst->fname, sst->line);
@@ -59,8 +59,8 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
return 0;
}
json_object *coordinates = json_hash_get(geometry, "coordinates");
if (coordinates == NULL || coordinates->type != JSON_ARRAY) {
json_object_ptr coordinates = json_hash_get(geometry, "coordinates");
if (coordinates == nullptr || coordinates->type != JSON_ARRAY) {
fprintf(stderr, "%s:%d: feature without coordinates array: ", sst->fname, sst->line);
json_context(feature);
return 0;
@@ -68,12 +68,12 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
int t;
for (t = 0; t < GEOM_TYPES; t++) {
if (strcmp(geometry_type->value.string.string, geometry_names[t]) == 0) {
if (geometry_type->value.string.string == geometry_names[t]) {
break;
}
}
if (t >= GEOM_TYPES) {
fprintf(stderr, "%s:%d: Can't handle geometry type %s: ", sst->fname, sst->line, geometry_type->value.string.string);
fprintf(stderr, "%s:%d: Can't handle geometry type %s: ", sst->fname, sst->line, geometry_type->value.string.string.c_str());
json_context(feature);
return 0;
}
@@ -82,26 +82,26 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
int tippecanoe_maxzoom = -1;
std::string tippecanoe_layername = layername;
if (tippecanoe != NULL) {
json_object *min = json_hash_get(tippecanoe, "minzoom");
if (min != NULL && (min->type == JSON_NUMBER)) {
if (tippecanoe != nullptr) {
json_object_ptr min = json_hash_get(tippecanoe, "minzoom");
if (min != nullptr && (min->type == JSON_NUMBER)) {
tippecanoe_minzoom = integer_zoom(sst->fname, milo::dtoa_milo(min->value.number.number));
}
json_object *max = json_hash_get(tippecanoe, "maxzoom");
if (max != NULL && (max->type == JSON_NUMBER)) {
json_object_ptr max = json_hash_get(tippecanoe, "maxzoom");
if (max != nullptr && (max->type == JSON_NUMBER)) {
tippecanoe_maxzoom = integer_zoom(sst->fname, milo::dtoa_milo(max->value.number.number));
}
json_object *ln = json_hash_get(tippecanoe, "layer");
if (ln != NULL && (ln->type == JSON_STRING)) {
tippecanoe_layername = std::string(ln->value.string.string);
json_object_ptr ln = json_hash_get(tippecanoe, "layer");
if (ln != nullptr && (ln->type == JSON_STRING)) {
tippecanoe_layername = ln->value.string.string;
}
}
bool has_id = false;
unsigned long long id_value = 0;
if (id != NULL) {
if (id != nullptr) {
if (id->type == JSON_NUMBER) {
if (id->value.number.number >= 0) {
char *err = NULL;
@@ -142,20 +142,20 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
if (additional[A_CONVERT_NUMERIC_IDS] && id->type == JSON_STRING) {
char *err = NULL;
id_value = strtoull(id->value.string.string, &err, 10);
id_value = strtoull(id->value.string.string.c_str(), &err, 10);
if (err != NULL && *err != '\0') {
static bool warned_frac = false;
if (!warned_frac) {
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", id->value.string.string);
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", id->value.string.string.c_str());
warned_frac = true;
}
} else if (std::to_string(id_value) != id->value.string.string) {
static bool warned = false;
if (!warned) {
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", id->value.string.string);
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", id->value.string.string.c_str());
warned = true;
}
} else {
@@ -168,9 +168,7 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
static bool warned_nan = false;
if (!warned_nan) {
char *s = json_stringify(id);
fprintf(stderr, "Warning: Can't represent non-numeric feature ID %s\n", s);
free(s); // stringify
fprintf(stderr, "Warning: Can't represent non-numeric feature ID %s\n", json_stringify(id).c_str());
warned_nan = true;
}
}
@@ -178,8 +176,8 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
}
size_t nprop = 0;
if (properties != NULL && properties->type == JSON_HASH) {
nprop = properties->value.object.length;
if (properties != nullptr && properties->type == JSON_HASH) {
nprop = properties->value.object.keys.size();
}
std::vector<std::shared_ptr<std::string>> full_keys;
@@ -193,7 +191,7 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
if (properties->value.object.keys[i]->type == JSON_STRING) {
serial_val sv = stringify_value(properties->value.object.values[i], sst->fname, sst->line, feature);
full_keys.emplace_back(key_pool.pool(properties->value.object.keys[i]->value.string.string));
full_keys.emplace_back(key_pool.pool(properties->value.object.keys[i]->value.string.string.c_str()));
values.push_back(std::move(sv));
}
}
@@ -218,16 +216,16 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
return serialize_feature(sst, sf, tippecanoe_layername);
}
void check_crs(json_object *j, const char *reading) {
json_object *crs = json_hash_get(j, "crs");
if (crs != NULL) {
json_object *properties = json_hash_get(crs, "properties");
if (properties != NULL) {
json_object *name = json_hash_get(properties, "name");
if (name != NULL && name->type == JSON_STRING) {
if (strcmp(name->value.string.string, projection->alias) != 0) {
void check_crs(json_object_ptr j, const char *reading) {
json_object_ptr crs = json_hash_get(j, "crs");
if (crs != nullptr) {
json_object_ptr properties = json_hash_get(crs, "properties");
if (properties != nullptr) {
json_object_ptr name = json_hash_get(properties, "name");
if (name != nullptr && name->type == JSON_STRING) {
if (name->value.string.string != projection->alias) {
if (!quiet) {
fprintf(stderr, "%s: Warning: GeoJSON specified projection \"%s\", not the expected \"%s\".\n", reading, name->value.string.string, projection->alias);
fprintf(stderr, "%s: Warning: GeoJSON specified projection \"%s\", not the expected \"%s\".\n", reading, name->value.string.string.c_str(), projection->alias);
fprintf(stderr, "%s: If \"%s\" is not the expected projection, use -s to specify the right one.\n", reading, projection->alias);
}
}
@@ -241,11 +239,11 @@ struct json_serialize_action : json_feature_action {
int layer;
std::string layername;
int add_feature(json_object *geometry, bool geometrycollection, json_object *properties, json_object *id, json_object *tippecanoe, json_object *feature) {
int add_feature(json_object_ptr geometry, bool geometrycollection, json_object_ptr properties, json_object_ptr id, json_object_ptr tippecanoe, json_object_ptr feature) {
sst->line = geometry->parser->line;
if (geometrycollection) {
int ret = 1;
for (size_t g = 0; g < geometry->value.array.length; g++) {
for (size_t g = 0; g < geometry->value.array.array.size(); g++) {
ret &= serialize_geojson_feature(sst, geometry->value.array.array[g], properties, id, layer, tippecanoe, feature, layername);
}
return ret;
@@ -254,12 +252,12 @@ struct json_serialize_action : json_feature_action {
}
}
void check_crs(json_object *j) {
void check_crs(json_object_ptr j) {
::check_crs(j, fname.c_str());
}
};
void parse_json(struct serialization_state *sst, json_pull *jp, int layer, std::string layername) {
void parse_json(struct serialization_state *sst, json_pull_ptr jp, int layer, std::string layername) {
json_serialize_action jsa;
jsa.fname = sst->fname;
jsa.sst = sst;
@@ -296,7 +294,7 @@ ssize_t json_map_read(struct json_pull *jp, char *buffer, size_t n) {
return n;
}
struct json_pull *json_begin_map(char *map, long long len) {
json_pull_ptr json_begin_map(char *map, long long len) {
struct jsonmap *jm = new jsonmap;
if (jm == NULL) {
perror("Out of memory");
@@ -310,7 +308,7 @@ struct json_pull *json_begin_map(char *map, long long len) {
return json_begin(json_map_read, jm);
}
void json_end_map(struct json_pull *jp) {
void json_end_map(json_pull_ptr jp) {
delete (struct jsonmap *) jp->source;
json_end(jp);
}
+5 -5
View File
@@ -10,21 +10,21 @@
#include "serial.hpp"
struct parse_json_args {
json_pull *jp;
json_pull_ptr jp;
int layer;
std::string *layername;
struct serialization_state *sst;
parse_json_args(json_pull *jp1, int layer1, std::string *layername1, struct serialization_state *sst1)
parse_json_args(json_pull_ptr jp1, int layer1, std::string *layername1, struct serialization_state *sst1)
: jp(jp1), layer(layer1), layername(layername1), sst(sst1) {
}
};
struct json_pull *json_begin_map(char *map, long long len);
void json_end_map(struct json_pull *jp);
json_pull_ptr json_begin_map(char *map, long long len);
void json_end_map(json_pull_ptr jp);
void parse_json(struct serialization_state *sst, json_pull *jp, int layer, std::string layername);
void parse_json(struct serialization_state *sst, json_pull_ptr jp, int layer, std::string layername);
void *run_parse_json(void *v);
#endif
+2 -2
View File
@@ -141,7 +141,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
std::vector<std::string> const &exclude_prefix,
bool do_compress,
std::vector<std::pair<unsigned, unsigned>> *next_overzoomed_tiles,
bool demultiply, json_object *filter, bool preserve_input_order,
bool demultiply, json_object_ptr filter, bool preserve_input_order,
std::unordered_map<std::string, attribute_op> const &attribute_accum,
std::vector<std::string> const &unidecode_data, double simplification,
double tiny_polygon_size,
@@ -157,7 +157,7 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
std::vector<std::string> const &exclude_prefix,
bool do_compress,
std::vector<std::pair<unsigned, unsigned>> *next_overzoomed_tiles,
bool demultiply, json_object *filter, bool preserve_input_order,
bool demultiply, json_object_ptr filter, bool preserve_input_order,
std::unordered_map<std::string, attribute_op> const &attribute_accum,
std::vector<std::string> const &unidecode_data, double simplification,
double tiny_polygon_size,
+819
View File
@@ -0,0 +1,819 @@
#define _GNU_SOURCE // for asprintf()
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <memory>
#include <string>
#include <vector>
#include "jsonpull.h"
#include "../milo/milo.h"
#define BUFFER 10000
json_pull_ptr json_begin(ssize_t (*read)(struct json_pull *, char *buffer, size_t n), void *source) {
auto j = std::make_shared<json_pull>();
j->read = read;
j->source = source;
j->buffer.resize(BUFFER);
return j;
}
static inline int peek(json_pull *j) {
if (j->buffer_head < j->buffer_tail) {
return (unsigned char) j->buffer[j->buffer_head];
} else {
j->buffer_head = 0;
j->buffer_tail = j->read(j, j->buffer.data(), BUFFER);
if (j->buffer_head >= j->buffer_tail) {
return EOF;
}
return (unsigned char) j->buffer[j->buffer_head];
}
}
static inline int next(json_pull *j) {
if (j->buffer_head < j->buffer_tail) {
return (unsigned char) j->buffer[j->buffer_head++];
} else {
j->buffer_head = 0;
j->buffer_tail = j->read(j, j->buffer.data(), BUFFER);
if (j->buffer_head >= j->buffer_tail) {
return EOF;
}
return (unsigned char) j->buffer[j->buffer_head++];
}
}
static ssize_t read_file(json_pull *j, char *buffer, size_t n) {
return fread(buffer, 1, n, (FILE *) j->source);
}
json_pull_ptr json_begin_file(FILE *f) {
return json_begin(read_file, f);
}
static ssize_t read_string(json_pull *j, char *buffer, size_t n) {
const char *cp = (const char *) j->source;
size_t out = 0;
while (out < n && cp[out] != '\0') {
buffer[out] = cp[out];
out++;
}
j->source = (void *) (cp + out);
return out;
}
json_pull_ptr json_begin_string(const char *s) {
return json_begin(read_string, (void *) s);
}
void json_end(json_pull_ptr &p) {
p.reset();
}
static inline int read_wrap(json_pull *j) {
int c = next(j);
if (c == '\n') {
j->line++;
}
return c;
}
static json_object_ptr fabricate_object(json_pull *jp, json_object *parent, json_type type) {
auto o = std::make_shared<json_object>();
o->type = type;
o->parent = parent;
o->parser = jp;
return o;
}
static json_object_ptr add_object(json_pull *j, json_type type) {
json_object *c = j->container.get();
json_object_ptr o = fabricate_object(j, c, type);
if (c != nullptr) {
if (c->type == JSON_ARRAY) {
if (c->expect == JSON_ITEM) {
c->value.array.array.push_back(o);
c->expect = JSON_COMMA;
} else {
j->error = "Expected a comma, not a list item";
return nullptr;
}
} else if (c->type == JSON_HASH) {
if (c->expect == JSON_VALUE) {
c->value.object.values.back() = o;
c->expect = JSON_COMMA;
} else if (c->expect == JSON_KEY) {
if (type != JSON_STRING) {
j->error = "Hash key is not a string";
return nullptr;
}
c->value.object.keys.push_back(o);
c->value.object.values.push_back(nullptr);
c->expect = JSON_COLON;
} else {
j->error = "Expected a comma or colon";
return nullptr;
}
}
} else {
// Drop the previous top-level value; replacing the parser's root
// shared_ptr will free it if no one else holds a reference.
j->root = o;
}
return o;
}
json_object_ptr json_hash_get(json_object_ptr o, const char *s) {
if (o == nullptr || o->type != JSON_HASH) {
return nullptr;
}
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
const auto &key = o->value.object.keys[i];
if (key != nullptr && key->type == JSON_STRING) {
if (key->value.string.string == s) {
return o->value.object.values[i];
}
}
}
return nullptr;
}
json_object_ptr json_read_separators(json_pull_ptr jp, json_separator_callback cb, void *state) {
int c;
json_pull *j = jp.get();
// In case there is an error at the top level
if (j->container == nullptr) {
j->root.reset();
}
again:
c = read_wrap(j);
if (c == EOF) {
if (j->container != nullptr) {
j->error = "Reached EOF without all containers being closed";
}
return nullptr;
}
switch (c) {
/////////////////////////// Byte order mark
case 0xEF: {
int c2 = peek(j);
if (c2 == 0xBB) {
c2 = read_wrap(j);
c2 = peek(j);
if (c2 == 0xBF) {
c2 = read_wrap(j);
c = ' ';
goto again;
}
}
j->error = "Corrupt byte-order mark found";
return nullptr;
}
/////////////////////////// Whitespace
case ' ':
case '\t':
case '\r':
case '\n':
case 0x1E:
goto again;
/////////////////////////// Arrays
case '[': {
json_object_ptr o = add_object(j, JSON_ARRAY);
if (o == nullptr) {
return nullptr;
}
j->container = o;
j->container->expect = JSON_ITEM;
if (cb != nullptr) {
cb(JSON_ARRAY, j, state);
}
goto again;
}
case ']': {
if (j->container == nullptr) {
j->error = "Found ] at top level";
return nullptr;
}
if (j->container->type != JSON_ARRAY) {
j->error = "Found ] not in an array";
return nullptr;
}
if (j->container->expect != JSON_COMMA) {
if (!(j->container->expect == JSON_ITEM && j->container->value.array.array.size() == 0)) {
j->error = "Found ] without final element";
return nullptr;
}
}
json_object_ptr ret = j->container;
// Walk up to the parent container. The parent (if any) still owns
// `ret` via its own array vector, so the raw `parent` pointer is
// still valid and we can resurrect a shared_ptr to it.
if (ret->parent != nullptr) {
j->container = ret->parent->shared_from_this();
} else {
j->container.reset();
}
return ret;
}
/////////////////////////// Hashes
case '{': {
json_object_ptr o = add_object(j, JSON_HASH);
if (o == nullptr) {
return nullptr;
}
j->container = o;
j->container->expect = JSON_KEY;
if (cb != nullptr) {
cb(JSON_HASH, j, state);
}
goto again;
}
case '}': {
if (j->container == nullptr) {
j->error = "Found } at top level";
return nullptr;
}
if (j->container->type != JSON_HASH) {
j->error = "Found } not in a hash";
return nullptr;
}
if (j->container->expect != JSON_COMMA) {
if (!(j->container->expect == JSON_KEY && j->container->value.object.keys.size() == 0)) {
j->error = "Found } without final element";
return nullptr;
}
}
json_object_ptr ret = j->container;
if (ret->parent != nullptr) {
j->container = ret->parent->shared_from_this();
} else {
j->container.reset();
}
return ret;
}
/////////////////////////// Null
case 'n': {
if (read_wrap(j) != 'u' || read_wrap(j) != 'l' || read_wrap(j) != 'l') {
j->error = "Found misspelling of null";
return nullptr;
}
return add_object(j, JSON_NULL);
}
/////////////////////////// NaN
case 'N': {
if (read_wrap(j) != 'a' || read_wrap(j) != 'N') {
j->error = "Found misspelling of NaN";
return nullptr;
}
j->error = "JSON does not allow NaN";
return nullptr;
}
/////////////////////////// Infinity
case 'I': {
if (read_wrap(j) != 'n' || read_wrap(j) != 'f' || read_wrap(j) != 'i' ||
read_wrap(j) != 'n' || read_wrap(j) != 'i' || read_wrap(j) != 't' ||
read_wrap(j) != 'y') {
j->error = "Found misspelling of Infinity";
return nullptr;
}
j->error = "JSON does not allow Infinity";
return nullptr;
}
/////////////////////////// True
case 't': {
if (read_wrap(j) != 'r' || read_wrap(j) != 'u' || read_wrap(j) != 'e') {
j->error = "Found misspelling of true";
return nullptr;
}
return add_object(j, JSON_TRUE);
}
/////////////////////////// False
case 'f': {
if (read_wrap(j) != 'a' || read_wrap(j) != 'l' || read_wrap(j) != 's' || read_wrap(j) != 'e') {
j->error = "Found misspelling of false";
return nullptr;
}
return add_object(j, JSON_FALSE);
}
/////////////////////////// Comma
case ',': {
if (j->container != nullptr) {
if (j->container->expect != JSON_COMMA) {
j->error = "Found unexpected comma";
return nullptr;
}
if (j->container->type == JSON_HASH) {
j->container->expect = JSON_KEY;
} else {
j->container->expect = JSON_ITEM;
}
}
if (cb != nullptr) {
cb(JSON_COMMA, j, state);
}
goto again;
}
/////////////////////////// Colon
case ':': {
if (j->container == nullptr) {
j->error = "Found colon at top level";
return nullptr;
}
if (j->container->expect != JSON_COLON) {
j->error = "Found unexpected colon";
return nullptr;
}
j->container->expect = JSON_VALUE;
if (cb != nullptr) {
cb(JSON_COLON, j, state);
}
goto again;
}
/////////////////////////// Numbers
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
j->number_buffer.clear();
int decimal = 0;
if (c == '-') {
j->number_buffer.push_back(c);
c = read_wrap(j);
}
if (c == '0') {
j->number_buffer.push_back(c);
} else if (c >= '1' && c <= '9') {
j->number_buffer.push_back(c);
c = peek(j);
while (c >= '0' && c <= '9') {
j->number_buffer.push_back(read_wrap(j));
c = peek(j);
}
}
if (peek(j) == '.') {
j->number_buffer.push_back(read_wrap(j));
decimal = 1;
c = peek(j);
if (c < '0' || c > '9') {
j->error = "Decimal point without digits";
return nullptr;
}
while (c >= '0' && c <= '9') {
j->number_buffer.push_back(read_wrap(j));
c = peek(j);
}
}
c = peek(j);
if (c == 'e' || c == 'E') {
j->number_buffer.push_back(read_wrap(j));
decimal = 1;
c = peek(j);
if (c == '+' || c == '-') {
j->number_buffer.push_back(read_wrap(j));
}
c = peek(j);
if (c < '0' || c > '9') {
j->error = "Exponent without digits";
return nullptr;
}
while (c >= '0' && c <= '9') {
j->number_buffer.push_back(read_wrap(j));
c = peek(j);
}
}
json_object_ptr n = add_object(j, JSON_NUMBER);
if (n != nullptr) {
n->value.number.number = atof(j->number_buffer.c_str());
n->value.number.large_signed = 0;
n->value.number.large_unsigned = 0;
#define MAX_SAFE_INTEGER 9007199254740991.0
#define MIN_SAFE_INTEGER -9007199254740991.0
if (!decimal && n->value.number.number > MAX_SAFE_INTEGER) {
errno = 0;
char *err = nullptr;
unsigned long long ull = strtoull(j->number_buffer.c_str(), &err, 10);
if (errno == 0 && (err == nullptr || *err == '\0')) {
n->value.number.large_unsigned = ull;
}
}
if (!decimal && n->value.number.number < MIN_SAFE_INTEGER) {
errno = 0;
char *err = nullptr;
long long ll = strtoll(j->number_buffer.c_str(), &err, 10);
if (errno == 0 && (err == nullptr || *err == '\0')) {
n->value.number.large_signed = ll;
}
}
}
return n;
}
/////////////////////////// Strings
case '"': {
std::string val;
int surrogate = -1;
while ((c = read_wrap(j)) != EOF) {
if (c == '"') {
if (surrogate >= 0) {
val.push_back(0xE0 | (surrogate >> 12));
val.push_back(0x80 | ((surrogate >> 6) & 0x3F));
val.push_back(0x80 | (surrogate & 0x3F));
surrogate = -1;
}
break;
} else if (c == '\\') {
c = read_wrap(j);
if (c == 'u') {
char hex[5] = "aaaa";
int i;
for (i = 0; i < 4; i++) {
hex[i] = read_wrap(j);
if (hex[i] < '0' || (hex[i] > '9' && hex[i] < 'A') || (hex[i] > 'F' && hex[i] < 'a') || hex[i] > 'f') {
j->error = "Invalid \\u hex character";
return nullptr;
}
}
unsigned long ch = strtoul(hex, nullptr, 16);
if (ch >= 0xd800 && ch <= 0xdbff) {
if (surrogate < 0) {
surrogate = ch;
} else {
// Impossible surrogate, so output the first half,
// keep what might be a legitimate new first half.
val.push_back(0xE0 | (surrogate >> 12));
val.push_back(0x80 | ((surrogate >> 6) & 0x3F));
val.push_back(0x80 | (surrogate & 0x3F));
surrogate = ch;
}
continue;
} else if (ch >= 0xdc00 && c <= 0xdfff) {
if (surrogate >= 0) {
long c1 = surrogate - 0xd800;
long c2 = ch - 0xdc00;
ch = ((c1 << 10) | c2) + 0x010000;
surrogate = -1;
}
}
if (surrogate >= 0) {
val.push_back(0xE0 | (surrogate >> 12));
val.push_back(0x80 | ((surrogate >> 6) & 0x3F));
val.push_back(0x80 | (surrogate & 0x3F));
surrogate = -1;
}
if (ch <= 0x7F) {
val.push_back(ch);
} else if (ch <= 0x7FF) {
val.push_back(0xC0 | (ch >> 6));
val.push_back(0x80 | (ch & 0x3F));
} else if (ch < 0xFFFF) {
val.push_back(0xE0 | (ch >> 12));
val.push_back(0x80 | ((ch >> 6) & 0x3F));
val.push_back(0x80 | (ch & 0x3F));
} else {
val.push_back(0xF0 | (ch >> 18));
val.push_back(0x80 | ((ch >> 12) & 0x3F));
val.push_back(0x80 | ((ch >> 6) & 0x3F));
val.push_back(0x80 | (ch & 0x3F));
}
} else {
if (surrogate >= 0) {
val.push_back(0xE0 | (surrogate >> 12));
val.push_back(0x80 | ((surrogate >> 6) & 0x3F));
val.push_back(0x80 | (surrogate & 0x3F));
surrogate = -1;
}
if (c == '"') {
val.push_back('"');
} else if (c == '\\') {
val.push_back('\\');
} else if (c == '/') {
val.push_back('/');
} else if (c == 'b') {
val.push_back('\b');
} else if (c == 'f') {
val.push_back('\f');
} else if (c == 'n') {
val.push_back('\n');
} else if (c == 'r') {
val.push_back('\r');
} else if (c == 't') {
val.push_back('\t');
} else {
j->error = "Found backslash followed by unknown character";
return nullptr;
}
}
} else if (c < ' ') {
j->error = "Found control character in string";
return nullptr;
} else {
if (surrogate >= 0) {
val.push_back(0xE0 | (surrogate >> 12));
val.push_back(0x80 | ((surrogate >> 6) & 0x3F));
val.push_back(0x80 | (surrogate & 0x3F));
surrogate = -1;
}
val.push_back(c);
}
}
if (c == EOF) {
j->error = "String without closing quote mark";
return nullptr;
}
json_object_ptr s = add_object(j, JSON_STRING);
if (s != nullptr) {
s->value.string.string = std::move(val);
s->value.string.refcon = nullptr;
}
return s;
}
}
j->error = "Found unexpected character";
return nullptr;
}
json_object_ptr json_read(json_pull_ptr j) {
return json_read_separators(j, nullptr, nullptr);
}
json_object_ptr json_read_tree(json_pull_ptr p) {
json_object_ptr j;
while ((j = json_read(p)) != nullptr) {
if (j->parent == nullptr) {
return j;
}
}
return nullptr;
}
void json_free(json_object_ptr &o) {
o.reset();
}
// Walk the subtree clearing parent/parser back-pointers so the detached
// subtree can outlive the original parser.
static void clear_back_pointers(json_object *o) {
if (o == nullptr) {
return;
}
if (o->type == JSON_HASH) {
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
clear_back_pointers(o->value.object.keys[i].get());
clear_back_pointers(o->value.object.values[i].get());
}
} else if (o->type == JSON_ARRAY) {
for (size_t i = 0; i < o->value.array.array.size(); i++) {
clear_back_pointers(o->value.array.array[i].get());
}
}
o->parent = nullptr;
o->parser = nullptr;
}
void json_disconnect(json_object_ptr o) {
if (o == nullptr) {
return;
}
// Splice o out of its parent's array or object. The parent's vector
// holds the shared_ptr to this child; erasing it removes one reference,
// but the caller still holds `o`, so the subtree stays alive.
json_object *parent = o->parent;
if (parent != nullptr) {
if (parent->type == JSON_ARRAY) {
auto &arr = parent->value.array.array;
for (size_t i = 0; i < arr.size(); i++) {
if (arr[i].get() == o.get()) {
arr.erase(arr.begin() + i);
break;
}
}
} else if (parent->type == JSON_HASH) {
auto &keys = parent->value.object.keys;
auto &vals = parent->value.object.values;
for (size_t i = 0; i < keys.size(); i++) {
if (keys[i].get() == o.get()) {
// Leave a NULL placeholder in the key slot so the
// surrounding value isn't shifted; if the corresponding
// value is also detached the pair is removed below.
keys[i] = fabricate_object(parent->parser, parent, JSON_NULL);
if (vals[i] != nullptr && vals[i]->type == JSON_NULL && keys[i]->type == JSON_NULL) {
keys.erase(keys.begin() + i);
vals.erase(vals.begin() + i);
}
break;
}
if (vals[i].get() == o.get()) {
vals[i] = fabricate_object(parent->parser, parent, JSON_NULL);
if (keys[i] != nullptr && keys[i]->type == JSON_NULL && vals[i]->type == JSON_NULL) {
keys.erase(keys.begin() + i);
vals.erase(vals.begin() + i);
}
break;
}
}
}
}
// Drop the parser's reference to this subtree if it was the root.
json_pull *parser = o->parser;
if (parser != nullptr && parser->root.get() == o.get()) {
parser->root.reset();
}
clear_back_pointers(o.get());
}
static void string_append_c(std::string &val, char c) {
val.push_back(c);
}
static void string_append(std::string &val, const char *add) {
val.append(add);
}
static void json_print_one(std::string &val, json_object *o) {
if (o == nullptr) {
string_append(val, "...");
} else if (o->type == JSON_STRING) {
string_append_c(val, '\"');
for (const char *cp = o->value.string.string.c_str(); *cp != '\0'; cp++) {
if (*cp == '\\' || *cp == '"') {
string_append_c(val, '\\');
string_append_c(val, *cp);
} else if (*cp >= 0 && *cp < ' ') {
char *s;
if (asprintf(&s, "\\u%04x", *cp) >= 0) {
string_append(val, s);
free(s);
}
} else {
string_append_c(val, *cp);
}
}
string_append_c(val, '\"');
} else if (o->type == JSON_NUMBER) {
if (o->value.number.large_signed != 0) {
char s[65];
snprintf(s, sizeof(s), "%lld", o->value.number.large_signed);
string_append(val, s);
} else if (o->value.number.large_unsigned != 0) {
char s[65];
snprintf(s, sizeof(s), "%llu", o->value.number.large_unsigned);
string_append(val, s);
} else {
char *s = dtoa_milo(o->value.number.number);
string_append(val, s);
free(s);
}
} else if (o->type == JSON_NULL) {
string_append(val, "null");
} else if (o->type == JSON_TRUE) {
string_append(val, "true");
} else if (o->type == JSON_FALSE) {
string_append(val, "false");
} else if (o->type == JSON_HASH) {
string_append_c(val, '}');
} else if (o->type == JSON_ARRAY) {
string_append_c(val, ']');
}
}
static void json_print(std::string &val, json_object *o) {
if (o == nullptr) {
// Hash value in incompletely read hash
string_append(val, "...");
} else if (o->type == JSON_HASH) {
string_append_c(val, '{');
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
json_print(val, o->value.object.keys[i].get());
string_append_c(val, ':');
json_print(val, o->value.object.values[i].get());
if (i + 1 < o->value.object.keys.size()) {
string_append_c(val, ',');
}
}
string_append_c(val, '}');
} else if (o->type == JSON_ARRAY) {
string_append_c(val, '[');
for (size_t i = 0; i < o->value.array.array.size(); i++) {
json_print(val, o->value.array.array[i].get());
if (i + 1 < o->value.array.array.size()) {
string_append_c(val, ',');
}
}
string_append_c(val, ']');
} else {
json_print_one(val, o);
}
}
std::string json_stringify(json_object_ptr o) {
std::string val;
json_print(val, o.get());
return val;
}
+72 -46
View File
@@ -1,9 +1,11 @@
#ifndef JSONPULL_H
#define JSONPULL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <sys/types.h>
#include <memory>
#include <string>
#include <vector>
typedef enum json_type {
// These types can be returned by json_read()
@@ -25,74 +27,98 @@ typedef enum json_type {
JSON_VALUE,
} json_type;
typedef struct json_object {
struct json_object *parent;
struct json_pull *parser;
struct json_object;
struct json_pull;
union {
typedef std::shared_ptr<json_object> json_object_ptr;
typedef std::shared_ptr<json_pull> json_pull_ptr;
// json_object owns its descendants via std::shared_ptr in std::vector<>s,
// and keeps raw back-pointers to its parent and to the parser. The back-pointers
// remain valid as long as the node is attached to the tree (the parent is kept
// alive by holding a shared_ptr to this child, and the parser is kept alive by
// the caller's json_pull_ptr). json_disconnect() splices a node out of its
// parent and clears those back-pointers in the detached subtree, so the
// detached subtree can outlive the original parser.
struct json_object : public std::enable_shared_from_this<json_object> {
json_object *parent = nullptr;
json_pull *parser = nullptr;
json_type type = JSON_NULL;
int expect = 0;
// Members named to match the previous C union layout so that existing
// access paths like `o->value.string.string` and `o->value.array.array[i]`
// continue to work. This is no longer a union because std::string and
// std::vector have non-trivial destructors.
struct value_t {
struct {
double number;
unsigned long long large_unsigned;
long long large_signed;
double number = 0;
unsigned long long large_unsigned = 0;
long long large_signed = 0;
} number;
struct {
char *string;
void *refcon; // reference constant for caller's use
std::string string;
void *refcon = nullptr; // reference constant for caller's use
} string;
struct {
struct json_object **array;
size_t length;
std::vector<json_object_ptr> array;
} array;
struct {
struct json_object **keys;
struct json_object **values;
size_t length;
std::vector<json_object_ptr> keys;
std::vector<json_object_ptr> values;
} object;
} value;
};
json_type type;
int expect;
} json_object;
struct json_pull {
const char *error = nullptr; // points at a string literal; no allocation
int line = 1;
typedef struct json_pull {
char *error;
int line;
ssize_t (*read)(struct json_pull *, char *buf, size_t n) = nullptr;
void *source = nullptr;
std::vector<char> buffer;
ssize_t buffer_tail = 0;
ssize_t buffer_head = 0;
ssize_t (*read)(struct json_pull *, char *buf, size_t n);
void *source;
char *buffer;
ssize_t buffer_tail;
ssize_t buffer_head;
json_object_ptr container;
json_object_ptr root;
json_object *container;
json_object *root;
std::string number_buffer;
};
struct string *number_buffer;
} json_pull;
json_pull_ptr json_begin_file(FILE *f);
json_pull_ptr json_begin_string(const char *s);
json_pull *json_begin_file(FILE *f);
json_pull *json_begin_string(const char *s);
json_pull_ptr json_begin(ssize_t (*read)(struct json_pull *, char *buffer, size_t n), void *source);
json_pull *json_begin(ssize_t (*read)(struct json_pull *, char *buffer, size_t n), void *source);
void json_end(json_pull *p);
// json_end is now a thin convenience that resets the caller's json_pull_ptr.
// The parser (and any tree it still owns) is freed when the last shared_ptr
// to it is dropped, so calling json_end is optional if the json_pull_ptr will
// go out of scope on its own.
void json_end(json_pull_ptr &p);
typedef void (*json_separator_callback)(json_type type, json_pull *j, void *state);
json_object *json_read_tree(json_pull *j);
json_object *json_read(json_pull *j);
json_object *json_read_separators(json_pull *j, json_separator_callback cb, void *state);
void json_free(json_object *j);
void json_disconnect(json_object *j);
json_object_ptr json_read_tree(json_pull_ptr j);
json_object_ptr json_read(json_pull_ptr j);
json_object_ptr json_read_separators(json_pull_ptr j, json_separator_callback cb, void *state);
json_object *json_hash_get(json_object *o, const char *s);
// json_free now just resets the caller's json_object_ptr. The subtree is
// destroyed when the last shared_ptr to it is dropped (typically by also
// being removed from its parent or parser).
void json_free(json_object_ptr &j);
char *json_stringify(json_object *o);
// Splice o out of its parent's array/object and clear parent/parser back-pointers
// throughout the detached subtree so it can outlive the original parser.
void json_disconnect(json_object_ptr j);
#ifdef __cplusplus
}
#endif
json_object_ptr json_hash_get(json_object_ptr o, const char *s);
std::string json_stringify(json_object_ptr o);
#endif
+26 -60
View File
@@ -140,23 +140,18 @@ std::string sort_quote(const char *s) {
return ret;
}
void out(std::string const &s, int type, json_object *properties) {
void out(std::string const &s, int type, json_object_ptr properties) {
if (extract != NULL) {
std::string extracted = sort_quote("null");
bool found = false;
json_object *o = json_hash_get(properties, extract);
if (o != NULL) {
json_object_ptr o = json_hash_get(properties, extract);
if (o != nullptr) {
found = true;
if (o->type == JSON_STRING || o->type == JSON_NUMBER) {
extracted = sort_quote(o->value.string.string);
extracted = sort_quote(o->value.string.string.c_str());
} else {
// Don't really know what to do about sort quoting
// for arbitrary objects
const char *out = json_stringify(o);
extracted = sort_quote(out);
free((void *) out);
extracted = sort_quote(json_stringify(o).c_str());
}
}
@@ -205,7 +200,7 @@ void out(std::string const &s, int type, json_object *properties) {
std::string prev_joinkey;
void join_csv(json_object *j) {
void join_csv(json_object_ptr j) {
if (header.size() == 0) {
std::string s = csv_getline(csvfile);
if (s.size() == 0) {
@@ -231,14 +226,14 @@ void join_csv(json_object *j) {
}
}
json_object *properties = json_hash_get(j, "properties");
json_object *key = NULL;
json_object_ptr properties = json_hash_get(j, "properties");
json_object_ptr key;
if (properties != NULL) {
if (properties != nullptr) {
key = json_hash_get(properties, header[0].c_str());
}
if (key == NULL) {
if (key == nullptr) {
static bool warned = false;
if (!warned) {
fprintf(stderr, "Warning: couldn't find CSV key \"%s\" in JSON\n", header[0].c_str());
@@ -253,9 +248,7 @@ void join_csv(json_object *j) {
} else if (key->type == JSON_NUMBER) {
joinkey = milo::dtoa_milo(key->value.number.number);
} else {
const char *s = json_stringify(key);
joinkey = s;
free((void *) s);
joinkey = json_stringify(key);
}
if (joinkey < prev_joinkey) {
@@ -305,14 +298,8 @@ void join_csv(json_object *j) {
}
if (fields.size() > 0 && joinkey == fields[0]) {
// This knows more about the structure of JSON objects than it ought to
// The 8 is to round up at least as much as SIZE_FOR in json_pull.c
properties->value.object.keys = (json_object **) realloc((void *) properties->value.object.keys, (properties->value.object.length + 8 + fields.size()) * sizeof(json_object *));
properties->value.object.values = (json_object **) realloc((void *) properties->value.object.values, (properties->value.object.length + 8 + fields.size()) * sizeof(json_object *));
if (properties->value.object.keys == NULL || properties->value.object.values == NULL) {
perror("realloc");
exit(EXIT_MEMORY);
}
properties->value.object.keys.reserve(properties->value.object.keys.size() + fields.size());
properties->value.object.values.reserve(properties->value.object.values.size() + fields.size());
for (size_t i = 1; i < fields.size(); i++) {
std::string k = header[i];
@@ -330,35 +317,20 @@ void join_csv(json_object *j) {
}
if (attr_type != JSON_NULL) {
// This knows more about the structure of JSON objects than it ought to
json_object *ko = (json_object *) malloc(sizeof(json_object));
json_object *vo = (json_object *) malloc(sizeof(json_object));
if (ko == NULL || vo == NULL) {
perror("malloc");
exit(EXIT_MEMORY);
}
auto ko = std::make_shared<json_object>();
auto vo = std::make_shared<json_object>();
ko->type = JSON_STRING;
ko->parent = properties;
ko->parent = properties.get();
ko->parser = properties->parser;
ko->value.string.string = strdup(k.c_str());
if (ko->value.string.string == NULL) {
perror("strdup");
exit(EXIT_MEMORY);
}
ko->value.string.string = k;
vo->type = attr_type;
vo->parent = properties;
vo->parent = properties.get();
vo->parser = properties->parser;
if (attr_type == JSON_STRING) {
vo->value.string.string = strdup(v.c_str());
if (vo->value.string.string == NULL) {
perror("strdup");
exit(EXIT_MEMORY);
}
vo->value.string.string = v;
} else if (attr_type == JSON_NUMBER) {
vo->value.number.number = atof(v.c_str());
vo->value.number.large_unsigned = 0;
@@ -367,44 +339,38 @@ void join_csv(json_object *j) {
abort();
}
properties->value.object.keys[properties->value.object.length] = ko;
properties->value.object.values[properties->value.object.length] = vo;
properties->value.object.length++;
properties->value.object.keys.push_back(ko);
properties->value.object.values.push_back(vo);
}
}
}
}
struct json_join_action : json_feature_action {
int add_feature(json_object *geometry, bool, json_object *, json_object *, json_object *, json_object *feature) {
int add_feature(json_object_ptr geometry, bool, json_object_ptr, json_object_ptr, json_object_ptr, json_object_ptr feature) {
if (feature != geometry) { // a real feature, not a bare geometry
if (csvfile != NULL) {
join_csv(feature);
}
char *s = json_stringify(feature);
out(s, 1, json_hash_get(feature, "properties"));
free(s);
out(json_stringify(feature), 1, json_hash_get(feature, "properties"));
} else {
char *s = json_stringify(geometry);
out(s, 2, NULL);
free(s);
out(json_stringify(geometry), 2, nullptr);
}
return 1;
}
void check_crs(json_object *) {
void check_crs(json_object_ptr) {
}
};
void process(FILE *fp, const char *fname) {
json_pull *jp = json_begin_file(fp);
json_pull_ptr jp = json_begin_file(fp);
json_join_action jja;
jja.fname = fname;
parse_json(&jja, jp);
json_end(jp);
}
int main(int argc, char **argv) {
+26 -34
View File
@@ -586,7 +586,7 @@ struct STREAM {
}
}
json_pull *json_begin() {
json_pull_ptr json_begin() {
return ::json_begin(read_stream, this);
}
};
@@ -1215,7 +1215,7 @@ double round_droprate(double r) {
return std::round(r * 100000.0) / 100000.0;
}
std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, int maxzoom, int minzoom, int basezoom, double basezoom_marker_width, sqlite3 *outdb, const char *outdir, std::set<std::string> *exclude, std::set<std::string> *include, int exclude_all, json_object *filter, double droprate, int buffer, const char *tmpdir, double gamma, int read_parallel, int forcetable, const char *attribution, bool uses_gamma, long long *file_bbox, long long *file_bbox1, long long *file_bbox2, const char *prefilter, const char *postfilter, const char *description, bool guess_maxzoom, bool guess_cluster_maxzoom, std::unordered_map<std::string, int> const *attribute_types, const char *pgm, std::unordered_map<std::string, attribute_op> const *attribute_accum, std::map<std::string, std::string> const &attribute_descriptions, std::string const &commandline, int minimum_maxzoom) {
std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, int maxzoom, int minzoom, int basezoom, double basezoom_marker_width, sqlite3 *outdb, const char *outdir, std::set<std::string> *exclude, std::set<std::string> *include, int exclude_all, json_object_ptr filter, double droprate, int buffer, const char *tmpdir, double gamma, int read_parallel, int forcetable, const char *attribution, bool uses_gamma, long long *file_bbox, long long *file_bbox1, long long *file_bbox2, const char *prefilter, const char *postfilter, const char *description, bool guess_maxzoom, bool guess_cluster_maxzoom, std::unordered_map<std::string, int> const *attribute_types, const char *pgm, std::unordered_map<std::string, attribute_op> const *attribute_accum, std::map<std::string, std::string> const &attribute_descriptions, std::string const &commandline, int minimum_maxzoom) {
int ret = EXIT_SUCCESS;
std::vector<struct reader> readers;
@@ -1818,7 +1818,7 @@ std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, i
// Plain serial reading
std::atomic<long long> layer_seq(overall_offset);
json_pull *jp = fp->json_begin();
json_pull_ptr jp = fp->json_begin();
struct serialization_state sst;
sst.fname = reading.c_str();
@@ -1845,7 +1845,6 @@ std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, i
sst.attribute_types = attribute_types;
parse_json(&sst, jp, layer, sources[layer].layer);
json_end(jp);
overall_offset = layer_seq;
checkdisk(&readers);
}
@@ -2873,10 +2872,10 @@ void set_attribute_type(std::unordered_map<std::string, int> &attribute_types, c
void set_attribute_value(const char *arg) {
if (*arg == '{') {
json_pull *jp = json_begin_string(arg);
json_object *o = json_read_tree(jp);
json_pull_ptr jp = json_begin_string(arg);
json_object_ptr o = json_read_tree(jp);
if (o == NULL) {
if (o == nullptr) {
fprintf(stderr, "%s: --set-attribute %s: %s\n", *av, arg, jp->error);
exit(EXIT_JSON);
}
@@ -2886,9 +2885,9 @@ void set_attribute_value(const char *arg) {
exit(EXIT_JSON);
}
for (size_t i = 0; i < o->value.object.length; i++) {
json_object *k = o->value.object.keys[i];
json_object *v = o->value.object.values[i];
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
json_object_ptr k = o->value.object.keys[i];
json_object_ptr v = o->value.object.values[i];
if (k->type != JSON_STRING) {
fprintf(stderr, "%s: --set-attribute %s: key %zu not a string\n", *av, arg, i);
@@ -2899,8 +2898,6 @@ void set_attribute_value(const char *arg) {
set_attributes.emplace(k->value.string.string, val);
}
json_free(o);
json_end(jp);
return;
}
@@ -2925,10 +2922,10 @@ void set_attribute_value(const char *arg) {
}
void parse_json_source(const char *arg, struct source &src) {
json_pull *jp = json_begin_string(arg);
json_object *o = json_read_tree(jp);
json_pull_ptr jp = json_begin_string(arg);
json_object_ptr o = json_read_tree(jp);
if (o == NULL) {
if (o == nullptr) {
fprintf(stderr, "%s: -L%s: %s\n", *av, arg, jp->error);
exit(EXIT_JSON);
}
@@ -2938,31 +2935,28 @@ void parse_json_source(const char *arg, struct source &src) {
exit(EXIT_JSON);
}
json_object *fname = json_hash_get(o, "file");
if (fname == NULL || fname->type != JSON_STRING) {
json_object_ptr fname = json_hash_get(o, "file");
if (fname == nullptr || fname->type != JSON_STRING) {
fprintf(stderr, "%s: -L%s: requires \"file\": filename\n", *av, arg);
exit(EXIT_JSON);
}
src.file = std::string(fname->value.string.string);
src.file = fname->value.string.string;
json_object *layer = json_hash_get(o, "layer");
if (layer != NULL && layer->type == JSON_STRING) {
src.layer = std::string(layer->value.string.string);
json_object_ptr layer = json_hash_get(o, "layer");
if (layer != nullptr && layer->type == JSON_STRING) {
src.layer = layer->value.string.string;
}
json_object *description = json_hash_get(o, "description");
if (description != NULL && description->type == JSON_STRING) {
src.description = std::string(description->value.string.string);
json_object_ptr description = json_hash_get(o, "description");
if (description != nullptr && description->type == JSON_STRING) {
src.description = description->value.string.string;
}
json_object *format = json_hash_get(o, "format");
if (format != NULL && format->type == JSON_STRING) {
src.format = std::string(format->value.string.string);
json_object_ptr format = json_hash_get(o, "format");
if (format != nullptr && format->type == JSON_STRING) {
src.format = format->value.string.string;
}
json_free(o);
json_end(jp);
}
int main(int argc, char **argv) {
@@ -3008,7 +3002,7 @@ int main(int argc, char **argv) {
int exclude_all = 0;
int read_parallel = 0;
int files_open_at_start;
json_object *filter = NULL;
json_object_ptr filter;
memsize = calc_memsize();
@@ -3876,9 +3870,7 @@ int main(int argc, char **argv) {
exit(EXIT_IMPOSSIBLE);
}
if (filter != NULL) {
json_free(filter);
}
filter.reset();
return ret;
}
+1 -1
View File
@@ -238,7 +238,7 @@ int main(int argc, char **argv) {
std::string out;
{
json_object *json_filter = NULL;
json_object_ptr json_filter;
if (filter.size() > 0) {
json_filter = parse_filter(filter.c_str());
}
+37 -44
View File
@@ -27,9 +27,7 @@
#include "errors.hpp"
#include "thread.hpp"
extern "C" {
#include "jsonpull/jsonpull.h"
}
#include "plugin.hpp"
#include "write_json.hpp"
@@ -145,15 +143,15 @@ std::vector<mvt_layer> parse_layers(int fd, int z, unsigned x, unsigned y, std::
}
// Reads from the prefilter
serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::vector<std::map<std::string, layermap_entry>> *layermaps, size_t tiling_seg, std::vector<std::vector<std::string>> *layer_unmaps, bool postfilter, key_pool &key_pool) {
serial_feature parse_feature(json_pull_ptr jp, int z, unsigned x, unsigned y, std::vector<std::map<std::string, layermap_entry>> *layermaps, size_t tiling_seg, std::vector<std::vector<std::string>> *layer_unmaps, bool postfilter, key_pool &key_pool) {
serial_feature sf;
while (1) {
json_object *j = json_read(jp);
if (j == NULL) {
if (jp->error != NULL) {
json_object_ptr j = json_read(jp);
if (j == nullptr) {
if (jp->error != nullptr) {
fprintf(stderr, "Filter output:%d: %s: ", jp->line, jp->error);
if (jp->root != NULL) {
if (jp->root != nullptr) {
json_context(jp->root);
} else {
fprintf(stderr, "\n");
@@ -161,37 +159,35 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
exit(EXIT_JSON);
}
json_free(jp->root);
jp->root.reset();
sf.t = -1;
return sf;
}
json_object *type = json_hash_get(j, "type");
if (type == NULL || type->type != JSON_STRING) {
json_object_ptr type = json_hash_get(j, "type");
if (type == nullptr || type->type != JSON_STRING) {
continue;
}
if (strcmp(type->value.string.string, "Feature") != 0) {
if (type->value.string.string != "Feature") {
continue;
}
json_object *geometry = json_hash_get(j, "geometry");
if (geometry == NULL) {
json_object_ptr geometry = json_hash_get(j, "geometry");
if (geometry == nullptr) {
fprintf(stderr, "Filter output:%d: filtered feature with no geometry: ", jp->line);
json_context(j);
json_free(j);
exit(EXIT_JSON);
}
json_object *properties = json_hash_get(j, "properties");
if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
json_object_ptr properties = json_hash_get(j, "properties");
if (properties == nullptr || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
fprintf(stderr, "Filter output:%d: feature without properties hash: ", jp->line);
json_context(j);
json_free(j);
exit(EXIT_JSON);
}
json_object *geometry_type = json_hash_get(geometry, "type");
if (geometry_type == NULL) {
json_object_ptr geometry_type = json_hash_get(geometry, "type");
if (geometry_type == nullptr) {
fprintf(stderr, "Filter output:%d: null geometry (additional not reported): ", jp->line);
json_context(j);
exit(EXIT_JSON);
@@ -203,8 +199,8 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
exit(EXIT_JSON);
}
json_object *coordinates = json_hash_get(geometry, "coordinates");
if (coordinates == NULL || coordinates->type != JSON_ARRAY) {
json_object_ptr coordinates = json_hash_get(geometry, "coordinates");
if (coordinates == nullptr || coordinates->type != JSON_ARRAY) {
fprintf(stderr, "Filter output:%d: feature without coordinates array: ", jp->line);
json_context(j);
exit(EXIT_JSON);
@@ -212,12 +208,12 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
int t;
for (t = 0; t < GEOM_TYPES; t++) {
if (strcmp(geometry_type->value.string.string, geometry_names[t]) == 0) {
if (geometry_type->value.string.string == geometry_names[t]) {
break;
}
}
if (t >= GEOM_TYPES) {
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->value.string.string);
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->value.string.string.c_str());
json_context(j);
exit(EXIT_JSON);
}
@@ -252,30 +248,30 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
sf.has_id = false;
std::string layername = "unknown";
json_object *tippecanoe = json_hash_get(j, "tippecanoe");
if (tippecanoe != NULL) {
json_object *layer = json_hash_get(tippecanoe, "layer");
if (layer != NULL && layer->type == JSON_STRING) {
layername = std::string(layer->value.string.string);
json_object_ptr tippecanoe = json_hash_get(j, "tippecanoe");
if (tippecanoe != nullptr) {
json_object_ptr layer = json_hash_get(tippecanoe, "layer");
if (layer != nullptr && layer->type == JSON_STRING) {
layername = layer->value.string.string;
}
json_object *index = json_hash_get(tippecanoe, "index");
if (index != NULL && index->type == JSON_NUMBER) {
json_object_ptr index = json_hash_get(tippecanoe, "index");
if (index != nullptr && index->type == JSON_NUMBER) {
sf.index = index->value.number.number;
}
json_object *sequence = json_hash_get(tippecanoe, "sequence");
if (sequence != NULL && sequence->type == JSON_NUMBER) {
json_object_ptr sequence = json_hash_get(tippecanoe, "sequence");
if (sequence != nullptr && sequence->type == JSON_NUMBER) {
sf.seq = sequence->value.number.number;
}
json_object *extent = json_hash_get(tippecanoe, "extent");
if (extent != NULL && extent->type == JSON_NUMBER) {
json_object_ptr extent = json_hash_get(tippecanoe, "extent");
if (extent != nullptr && extent->type == JSON_NUMBER) {
sf.extent = extent->value.number.number;
}
json_object *dropped = json_hash_get(tippecanoe, "dropped");
if (dropped != NULL && dropped->type == JSON_TRUE) {
json_object_ptr dropped = json_hash_get(tippecanoe, "dropped");
if (dropped != nullptr && dropped->type == JSON_TRUE) {
sf.dropped = FEATURE_DROPPED; // dropped
} else {
sf.dropped = FEATURE_KEPT; // kept
@@ -299,8 +295,8 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
}
}
json_object *id = json_hash_get(j, "id");
if (id != NULL && id->type == JSON_NUMBER) {
json_object_ptr id = json_hash_get(j, "id");
if (id != nullptr && id->type == JSON_NUMBER) {
sf.id = id->value.number.number;
if (id->value.number.large_unsigned > 0) {
sf.id = id->value.number.large_unsigned;
@@ -347,27 +343,24 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
}
}
for (size_t i = 0; i < properties->value.object.length; i++) {
for (size_t i = 0; i < properties->value.object.keys.size(); i++) {
serial_val v = stringify_value(properties->value.object.values[i], "Filter output", jp->line, j);
// Nulls can be excluded here because the expression evaluation filter
// would have already run before prefiltering
if (v.type != mvt_null) {
sf.full_keys.push_back(key_pool.pool(std::string(properties->value.object.keys[i]->value.string.string)));
sf.full_keys.push_back(key_pool.pool(properties->value.object.keys[i]->value.string.string));
sf.full_values.push_back(v);
if (!postfilter) {
add_to_tilestats(ts->second.tilestats, std::string(properties->value.object.keys[i]->value.string.string), v);
add_to_tilestats(ts->second.tilestats, properties->value.object.keys[i]->value.string.string, v);
}
}
}
json_free(j);
return sf;
}
json_free(j);
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
struct key_pool;
std::vector<mvt_layer> filter_layers(const char *filter, std::vector<mvt_layer> &layer, unsigned z, unsigned x, unsigned y, std::vector<std::map<std::string, layermap_entry>> *layermaps, size_t tiling_seg, std::vector<std::vector<std::string>> *layer_unmaps, int extent);
void setup_filter(const char *filter, int *write_to, int *read_from, pid_t *pid, unsigned z, unsigned x, unsigned y);
serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::vector<std::map<std::string, layermap_entry>> *layermaps, size_t tiling_seg, std::vector<std::vector<std::string>> *layer_unmaps, bool filters, key_pool &key_pool);
serial_feature parse_feature(json_pull_ptr jp, int z, unsigned x, unsigned y, std::vector<std::map<std::string, layermap_entry>> *layermaps, size_t tiling_seg, std::vector<std::vector<std::string>> *layer_unmaps, bool filters, key_pool &key_pool);
+16 -17
View File
@@ -397,9 +397,9 @@ sqlite3 *pmtilesmeta2tmp(const char *fname, const char *pmtiles_map) {
exit(EXIT_OPEN);
}
json_pull *jp = json_begin_string(decompressed_json.c_str());
json_object *o = json_read_tree(jp);
if (o == NULL) {
json_pull_ptr jp = json_begin_string(decompressed_json.c_str());
json_object_ptr o = json_read_tree(jp);
if (o == nullptr) {
fprintf(stderr, "%s: metadata parsing error: %s\n", fname, jp->error);
exit(EXIT_JSON);
}
@@ -415,45 +415,44 @@ sqlite3 *pmtilesmeta2tmp(const char *fname, const char *pmtiles_map) {
state.nospace = true;
state.json_write_hash();
for (size_t i = 0; i < o->value.object.length; i++) {
const char *key = o->value.object.keys[i]->value.string.string;
if (strcmp(key, "vector_layers") == 0 && o->value.object.values[i]->type == JSON_ARRAY) {
for (size_t i = 0; i < o->value.object.keys.size(); i++) {
const std::string &key = o->value.object.keys[i]->value.string.string;
if (key == "vector_layers" && o->value.object.values[i]->type == JSON_ARRAY) {
has_json = true;
state.nospace = true;
state.json_write_string("vector_layers");
state.nospace = true;
state.json_write_json(json_stringify(o->value.object.values[i]));
} else if (strcmp(key, "tilestats") == 0 && o->value.object.values[i]->type == JSON_HASH) {
} else if (key == "tilestats" && o->value.object.values[i]->type == JSON_HASH) {
has_json = true;
state.nospace = true;
state.json_write_string("tilestats");
state.nospace = true;
state.json_write_json(json_stringify(o->value.object.values[i]));
} else if (strcmp(key, "strategies") == 0 && o->value.object.values[i]->type == JSON_ARRAY) {
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('strategies', %Q);", json_stringify(o->value.object.values[i]));
} else if (key == "strategies" && o->value.object.values[i]->type == JSON_ARRAY) {
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('strategies', %Q);", json_stringify(o->value.object.values[i]).c_str());
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set %s in metadata: %s\n", key, err);
fprintf(stderr, "set %s in metadata: %s\n", key.c_str(), err);
}
sqlite3_free(sql);
} else if (strcmp(key, "tippecanoe_decisions") == 0 && o->value.object.values[i]->type == JSON_HASH) {
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('tippecanoe_decisions', %Q);", json_stringify(o->value.object.values[i]));
} else if (key == "tippecanoe_decisions" && o->value.object.values[i]->type == JSON_HASH) {
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('tippecanoe_decisions', %Q);", json_stringify(o->value.object.values[i]).c_str());
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set %s in metadata: %s\n", key, err);
fprintf(stderr, "set %s in metadata: %s\n", key.c_str(), err);
}
sqlite3_free(sql);
} else if (o->value.object.keys[i]->type != JSON_STRING || o->value.object.values[i]->type != JSON_STRING) {
fprintf(stderr, "%s\n", key);
fprintf(stderr, "%s\n", key.c_str());
fprintf(stderr, "%s: non-string in metadata\n", fname);
} else {
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", key, o->value.object.values[i]->value.string.string);
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", key.c_str(), o->value.object.values[i]->value.string.string.c_str());
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set %s in metadata: %s\n", key, err);
fprintf(stderr, "set %s in metadata: %s\n", key.c_str(), err);
}
sqlite3_free(sql);
}
}
json_end(jp);
state.nospace = true;
state.json_end_hash();
+43 -51
View File
@@ -42,19 +42,19 @@ int mb_geometry[GEOM_TYPES] = {
VT_POLYGON,
};
void json_context(json_object *j) {
char *s = json_stringify(j);
void json_context(json_object_ptr j) {
std::string s = json_stringify(j);
if (strlen(s) >= 500) {
snprintf(s + 497, strlen(s) + 1 - 497, "...");
if (s.size() >= 500) {
s.resize(497);
s.append("...");
}
fprintf(stderr, "in JSON object %s\n", s);
free(s); // stringify
fprintf(stderr, "in JSON object %s\n", s.c_str());
}
void parse_coordinates(int t, json_object *j, drawvec &out, int op, const char *fname, int line, json_object *feature) {
if (j == NULL || j->type != JSON_ARRAY) {
void parse_coordinates(int t, json_object_ptr j, drawvec &out, int op, const char *fname, int line, json_object_ptr feature) {
if (j == nullptr || j->type != JSON_ARRAY) {
fprintf(stderr, "%s:%d: expected array for geometry type %d: ", fname, line, t);
json_context(feature);
return;
@@ -63,7 +63,7 @@ void parse_coordinates(int t, json_object *j, drawvec &out, int op, const char *
int within = geometry_within[t];
if (within >= 0) {
size_t i;
for (i = 0; i < j->value.array.length; i++) {
for (i = 0; i < j->value.array.array.size(); i++) {
if (within == GEOM_POINT) {
if (i == 0 || mb_geometry[t] == VT_POINT) {
op = VT_MOVETO;
@@ -75,13 +75,13 @@ void parse_coordinates(int t, json_object *j, drawvec &out, int op, const char *
parse_coordinates(within, j->value.array.array[i], out, op, fname, line, feature);
}
} else {
if (j->value.array.length >= 2 && j->value.array.array[0]->type == JSON_NUMBER && j->value.array.array[1]->type == JSON_NUMBER) {
if (j->value.array.array.size() >= 2 && j->value.array.array[0]->type == JSON_NUMBER && j->value.array.array[1]->type == JSON_NUMBER) {
long long x, y;
double lon = j->value.array.array[0]->value.number.number;
double lat = j->value.array.array[1]->value.number.number;
projection->project(lon, lat, 32, &x, &y);
if (j->value.array.length > 2) {
if (j->value.array.array.size() > 2) {
static int warned = 0;
if (!warned) {
@@ -121,10 +121,10 @@ void parse_coordinates(int t, json_object *j, drawvec &out, int op, const char *
// type and stringified value. All numeric values, even if they are integers,
// even integers that are too large to fit in a double but will still be
// stringified with their original precision, are recorded here as mvt_double.
serial_val stringify_value(json_object *value, const char *reading, int line, json_object *feature) {
serial_val stringify_value(json_object_ptr value, const char *reading, int line, json_object_ptr feature) {
serial_val sv;
if (value != NULL) {
if (value != nullptr) {
int vt = value->type;
if (vt == JSON_STRING) {
@@ -158,9 +158,7 @@ serial_val stringify_value(json_object *value, const char *reading, int line, js
sv.s = "null";
} else {
sv.type = mvt_string;
const char *v = json_stringify(value);
sv.s = std::string(v);
free((void *) v); // stringify
sv.s = json_stringify(value);
}
}
@@ -178,10 +176,10 @@ static std::vector<mvt_geometry> to_feature(drawvec &geom) {
return out;
}
std::pair<int, drawvec> parse_geometry(json_object *geometry, json_pull *jp, json_object *j,
std::pair<int, drawvec> parse_geometry(json_object_ptr geometry, json_pull_ptr jp, json_object_ptr j,
int z, int x, int y, long long extent, bool fix_longitudes, bool mvt_style) {
json_object *geometry_type = json_hash_get(geometry, "type");
if (geometry_type == NULL) {
json_object_ptr geometry_type = json_hash_get(geometry, "type");
if (geometry_type == nullptr) {
fprintf(stderr, "Filter output:%d: null geometry (additional not reported): ", jp->line);
json_context(j);
exit(EXIT_JSON);
@@ -193,8 +191,8 @@ std::pair<int, drawvec> parse_geometry(json_object *geometry, json_pull *jp, jso
exit(EXIT_JSON);
}
json_object *coordinates = json_hash_get(geometry, "coordinates");
if (coordinates == NULL || coordinates->type != JSON_ARRAY) {
json_object_ptr coordinates = json_hash_get(geometry, "coordinates");
if (coordinates == nullptr || coordinates->type != JSON_ARRAY) {
fprintf(stderr, "Filter output:%d: geometry without coordinates array: ", jp->line);
json_context(j);
exit(EXIT_JSON);
@@ -202,12 +200,12 @@ std::pair<int, drawvec> parse_geometry(json_object *geometry, json_pull *jp, jso
int t;
for (t = 0; t < GEOM_TYPES; t++) {
if (strcmp(geometry_type->value.string.string, geometry_names[t]) == 0) {
if (geometry_type->value.string.string == geometry_names[t]) {
break;
}
}
if (t >= GEOM_TYPES) {
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->value.string.string);
fprintf(stderr, "Filter output:%d: Can't handle geometry type %s: ", jp->line, geometry_type->value.string.string.c_str());
json_context(j);
exit(EXIT_JSON);
}
@@ -305,13 +303,13 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
std::map<std::string, mvt_layer> ret;
std::shared_ptr<std::string> tile_stringpool = std::make_shared<std::string>();
json_pull *jp = json_begin_file(fp);
json_pull_ptr jp = json_begin_file(fp);
while (1) {
json_object *j = json_read(jp);
if (j == NULL) {
if (jp->error != NULL) {
json_object_ptr j = json_read(jp);
if (j == nullptr) {
if (jp->error != nullptr) {
fprintf(stderr, "Filter output:%d: %s: ", jp->line, jp->error);
if (jp->root != NULL) {
if (jp->root != nullptr) {
json_context(jp->root);
} else {
fprintf(stderr, "\n");
@@ -319,33 +317,32 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
exit(EXIT_JSON);
}
json_free(jp->root);
jp->root.reset();
break;
}
json_object *type = json_hash_get(j, "type");
if (type == NULL || type->type != JSON_STRING) {
json_object_ptr type = json_hash_get(j, "type");
if (type == nullptr || type->type != JSON_STRING) {
continue;
}
if (strcmp(type->value.string.string, "Feature") != 0) {
if (type->value.string.string != "Feature") {
continue;
}
json_object *properties = json_hash_get(j, "properties");
if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
json_object_ptr properties = json_hash_get(j, "properties");
if (properties == nullptr || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
fprintf(stderr, "Filter output:%d: feature without properties hash: ", jp->line);
json_context(j);
json_free(j);
exit(EXIT_JSON);
}
std::string layername = "unknown";
json_object *tippecanoe = json_hash_get(j, "tippecanoe");
json_object *layer = NULL;
if (tippecanoe != NULL) {
json_object_ptr tippecanoe = json_hash_get(j, "tippecanoe");
json_object_ptr layer;
if (tippecanoe != nullptr) {
layer = json_hash_get(tippecanoe, "layer");
if (layer != NULL && layer->type == JSON_STRING) {
layername = std::string(layer->value.string.string);
if (layer != nullptr && layer->type == JSON_STRING) {
layername = layer->value.string.string;
}
}
@@ -359,11 +356,10 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
}
auto l = ret.find(layername);
json_object *geometry = json_hash_get(j, "geometry");
if (geometry == NULL) {
json_object_ptr geometry = json_hash_get(j, "geometry");
if (geometry == nullptr) {
fprintf(stderr, "Filter output:%d: filtered feature with no geometry: ", jp->line);
json_context(j);
json_free(j);
exit(EXIT_JSON);
}
@@ -377,8 +373,8 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
feature.type = mb_geometry[t];
feature.geometry = to_feature(dv);
json_object *id = json_hash_get(j, "id");
if (id != NULL && id->type == JSON_NUMBER) {
json_object_ptr id = json_hash_get(j, "id");
if (id != nullptr && id->type == JSON_NUMBER) {
feature.id = id->value.number.number;
if (id->value.number.large_unsigned > 0) {
feature.id = id->value.number.large_unsigned;
@@ -386,7 +382,7 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
feature.has_id = true;
}
for (size_t i = 0; i < properties->value.object.length; i++) {
for (size_t i = 0; i < properties->value.object.keys.size(); i++) {
serial_val sv = stringify_value(properties->value.object.values[i], "Filter output", jp->line, j);
// Nulls can be excluded here because this is the postfilter
@@ -394,18 +390,14 @@ std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int
if (sv.type != mvt_null) {
mvt_value v = stringified_to_mvt_value(sv.type, sv.s.c_str(), tile_stringpool);
l->second.tag(feature, std::string(properties->value.object.keys[i]->value.string.string), v);
l->second.tag(feature, properties->value.object.keys[i]->value.string.string, v);
}
}
l->second.features.push_back(feature);
}
json_free(j);
}
json_end(jp);
std::vector<mvt_layer> final;
for (auto a : ret) {
final.push_back(a.second);
+4 -4
View File
@@ -10,10 +10,10 @@ extern const char *geometry_names[GEOM_TYPES];
extern int geometry_within[GEOM_TYPES];
extern int mb_geometry[GEOM_TYPES];
void json_context(json_object *j);
void parse_coordinates(int t, json_object *j, drawvec &out, int op, const char *fname, int line, json_object *feature);
std::pair<int, drawvec> parse_geometry(json_object *geometry, json_pull *jp, json_object *j,
void json_context(json_object_ptr j);
void parse_coordinates(int t, json_object_ptr j, drawvec &out, int op, const char *fname, int line, json_object_ptr feature);
std::pair<int, drawvec> parse_geometry(json_object_ptr geometry, json_pull_ptr jp, json_object_ptr j,
int z, int x, int y, long long extent, bool fix_longitudes, bool mvt_style);
std::vector<mvt_layer> parse_layers(FILE *fp, int z, unsigned x, unsigned y, int extent, bool fix_longitudes);
serial_val stringify_value(json_object *value, const char *reading, int line, json_object *feature);
serial_val stringify_value(json_object_ptr value, const char *reading, int line, json_object_ptr feature);
+44 -51
View File
@@ -89,7 +89,7 @@ struct arg {
std::set<std::string> *keep_layers = NULL;
std::set<std::string> *remove_layers = NULL;
int ifmatched = 0;
json_object *filter = NULL;
json_object_ptr filter;
struct tileset_reader *readers = NULL;
double minlat, minlon;
@@ -97,7 +97,7 @@ struct arg {
double minlon2, maxlon2;
};
void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<std::string, layermap_entry> &layermap, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 * /* db */, std::set<std::string> &exclude, std::set<std::string> &include, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, int ifmatched, mvt_tile &outtile, json_object *filter, struct arg *a) {
void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<std::string, layermap_entry> &layermap, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 * /* db */, std::set<std::string> &exclude, std::set<std::string> &include, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, int ifmatched, mvt_tile &outtile, json_object_ptr filter, struct arg *a) {
mvt_tile tile;
int features_added = 0;
bool was_compressed;
@@ -891,7 +891,7 @@ void *join_worker(void *v) {
return NULL;
}
void dispatch_tasks(std::map<zxy, std::vector<std::string>> &tasks, std::vector<std::map<std::string, layermap_entry>> &layermaps, sqlite3 *outdb, const char *outdir, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 *db, std::set<std::string> &exclude, std::set<std::string> &include, int ifmatched, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, json_object *filter, struct tileset_reader *readers, double *minlat, double *minlon, double *maxlat, double *maxlon, double *minlon2, double *maxlon2) {
void dispatch_tasks(std::map<zxy, std::vector<std::string>> &tasks, std::vector<std::map<std::string, layermap_entry>> &layermaps, sqlite3 *outdb, const char *outdir, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 *db, std::set<std::string> &exclude, std::set<std::string> &include, int ifmatched, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, json_object_ptr filter, struct tileset_reader *readers, double *minlat, double *minlon, double *maxlat, double *maxlon, double *minlon2, double *maxlon2) {
pthread_t pthreads[CPUS];
std::vector<arg> args;
@@ -965,16 +965,16 @@ void dispatch_tasks(std::map<zxy, std::vector<std::string>> &tasks, std::vector<
}
void handle_strategies(const unsigned char *s, std::vector<strategy> *st) {
json_pull *jp = json_begin_string((const char *) s);
json_object *o = json_read_tree(jp);
json_pull_ptr jp = json_begin_string((const char *) s);
json_object_ptr o = json_read_tree(jp);
if (o != NULL && o->type == JSON_ARRAY) {
for (size_t i = 0; i < o->value.array.length; i++) {
json_object *h = o->value.array.array[i];
if (o != nullptr && o->type == JSON_ARRAY) {
for (size_t i = 0; i < o->value.array.array.size(); i++) {
json_object_ptr h = o->value.array.array[i];
if (h->type == JSON_HASH) {
for (size_t j = 0; j < h->value.object.length; j++) {
json_object *k = h->value.object.keys[j];
json_object *v = h->value.object.values[j];
for (size_t j = 0; j < h->value.object.keys.size(); j++) {
json_object_ptr k = h->value.object.keys[j];
json_object_ptr v = h->value.object.values[j];
if (k->type != JSON_STRING) {
fprintf(stderr, "Key %zu of %zu is not a string: %s\n", j, i, s);
@@ -985,23 +985,24 @@ void handle_strategies(const unsigned char *s, std::vector<strategy> *st) {
st->resize(i + 1);
}
if (strcmp(k->value.string.string, "dropped_by_rate") == 0) {
const std::string &key = k->value.string.string;
if (key == "dropped_by_rate") {
(*st)[i].dropped_by_rate += v->value.number.number;
} else if (strcmp(k->value.string.string, "dropped_by_gamma") == 0) {
} else if (key == "dropped_by_gamma") {
(*st)[i].dropped_by_gamma += v->value.number.number;
} else if (strcmp(k->value.string.string, "dropped_as_needed") == 0) {
} else if (key == "dropped_as_needed") {
(*st)[i].dropped_as_needed += v->value.number.number;
} else if (strcmp(k->value.string.string, "coalesced_as_needed") == 0) {
} else if (key == "coalesced_as_needed") {
(*st)[i].coalesced_as_needed += v->value.number.number;
} else if (strcmp(k->value.string.string, "truncated_zooms") == 0) {
} else if (key == "truncated_zooms") {
(*st)[i].truncated_zooms += v->value.number.number;
} else if (strcmp(k->value.string.string, "detail_reduced") == 0) {
} else if (key == "detail_reduced") {
(*st)[i].detail_reduced += v->value.number.number;
} else if (strcmp(k->value.string.string, "tiny_polygons") == 0) {
} else if (key == "tiny_polygons") {
(*st)[i].tiny_polygons += v->value.number.number;
} else if (strcmp(k->value.string.string, "tile_size_desired") == 0) {
} else if (key == "tile_size_desired") {
(*st)[i].tile_size += v->value.number.number;
} else if (strcmp(k->value.string.string, "feature_count_desired") == 0) {
} else if (key == "feature_count_desired") {
(*st)[i].feature_count += v->value.number.number;
}
}
@@ -1010,22 +1011,19 @@ void handle_strategies(const unsigned char *s, std::vector<strategy> *st) {
fprintf(stderr, "Element %zu is not a hash: %s\n", i, s);
}
}
json_free(o);
}
json_end(jp);
}
void handle_vector_layers(json_object *vector_layers, std::map<std::string, layermap_entry> &layermap, std::map<std::string, std::string> &attribute_descriptions) {
if (vector_layers != NULL && vector_layers->type == JSON_ARRAY) {
for (size_t i = 0; i < vector_layers->value.array.length; i++) {
void handle_vector_layers(json_object_ptr vector_layers, std::map<std::string, layermap_entry> &layermap, std::map<std::string, std::string> &attribute_descriptions) {
if (vector_layers != nullptr && vector_layers->type == JSON_ARRAY) {
for (size_t i = 0; i < vector_layers->value.array.array.size(); i++) {
if (vector_layers->value.array.array[i]->type == JSON_HASH) {
json_object *id = json_hash_get(vector_layers->value.array.array[i], "id");
json_object *desc = json_hash_get(vector_layers->value.array.array[i], "description");
json_object_ptr id = json_hash_get(vector_layers->value.array.array[i], "id");
json_object_ptr desc = json_hash_get(vector_layers->value.array.array[i], "description");
if (id != NULL && desc != NULL && id->type == JSON_STRING && desc->type == JSON_STRING) {
std::string sid = id->value.string.string;
std::string sdesc = desc->value.string.string;
if (id != nullptr && desc != nullptr && id->type == JSON_STRING && desc->type == JSON_STRING) {
const std::string &sid = id->value.string.string;
const std::string &sdesc = desc->value.string.string;
if (sdesc.size() != 0) {
auto f = layermap.find(sid);
@@ -1035,16 +1033,16 @@ void handle_vector_layers(json_object *vector_layers, std::map<std::string, laye
}
}
json_object *fields = json_hash_get(vector_layers->value.array.array[i], "fields");
if (fields != NULL && fields->type == JSON_HASH) {
for (size_t j = 0; j < fields->value.object.length; j++) {
json_object_ptr fields = json_hash_get(vector_layers->value.array.array[i], "fields");
if (fields != nullptr && fields->type == JSON_HASH) {
for (size_t j = 0; j < fields->value.object.keys.size(); j++) {
if (fields->value.object.keys[j]->type == JSON_STRING && fields->value.object.values[j]->type) {
const char *desc2 = fields->value.object.values[j]->value.string.string;
const std::string &desc2 = fields->value.object.values[j]->value.string.string;
if (strcmp(desc2, "Number") != 0 &&
strcmp(desc2, "String") != 0 &&
strcmp(desc2, "Boolean") != 0 &&
strcmp(desc2, "Mixed") != 0) {
if (desc2 != "Number" &&
desc2 != "String" &&
desc2 != "Boolean" &&
desc2 != "Mixed") {
attribute_descriptions.insert(std::pair<std::string, std::string>(fields->value.object.keys[j]->value.string.string, desc2));
}
}
@@ -1055,7 +1053,7 @@ void handle_vector_layers(json_object *vector_layers, std::map<std::string, laye
}
}
void decode(struct tileset_reader *readers, std::map<std::string, layermap_entry> &layermap, sqlite3 *outdb, const char *outdir, struct stats *st, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 *db, std::set<std::string> &exclude, std::set<std::string> &include, int ifmatched, std::string &attribution, std::string &description, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, std::string &name, json_object *filter, std::map<std::string, std::string> &attribute_descriptions, std::string &generator_options, std::vector<strategy> *strategies) {
void decode(struct tileset_reader *readers, std::map<std::string, layermap_entry> &layermap, sqlite3 *outdb, const char *outdir, struct stats *st, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 *db, std::set<std::string> &exclude, std::set<std::string> &include, int ifmatched, std::string &attribution, std::string &description, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, std::string &name, json_object_ptr filter, std::map<std::string, std::string> &attribute_descriptions, std::string &generator_options, std::vector<strategy> *strategies) {
std::vector<std::map<std::string, layermap_entry>> layermaps;
for (size_t i = 0; i < CPUS; i++) {
layermaps.push_back(std::map<std::string, layermap_entry>());
@@ -1205,17 +1203,14 @@ void decode(struct tileset_reader *readers, std::map<std::string, layermap_entry
const unsigned char *s = sqlite3_column_text(stmt, 0);
if (s != NULL) {
json_pull *jp = json_begin_string((const char *) s);
json_object *o = json_read_tree(jp);
json_pull_ptr jp = json_begin_string((const char *) s);
json_object_ptr o = json_read_tree(jp);
if (o != NULL && o->type == JSON_HASH) {
json_object *vector_layers = json_hash_get(o, "vector_layers");
if (o != nullptr && o->type == JSON_HASH) {
json_object_ptr vector_layers = json_hash_get(o, "vector_layers");
handle_vector_layers(vector_layers, layermap, attribute_descriptions);
json_free(o);
}
json_end(jp);
}
}
@@ -1266,7 +1261,7 @@ int main(int argc, char **argv) {
int force = 0;
int ifmatched = 0;
int filearg = 0;
json_object *filter = NULL;
json_object_ptr filter;
std::string join_sqlite_fname;
@@ -1648,9 +1643,7 @@ int main(int argc, char **argv) {
mbtiles_close(outdb, argv[0]);
}
if (filter != NULL) {
json_free(filter);
}
filter.reset();
if (pmtiles_has_suffix(out_mbtiles)) {
mbtiles_map_image_to_pmtiles(out_mbtiles, m, !pC, quiet, false);
+6 -6
View File
@@ -941,7 +941,7 @@ struct write_tile_args {
bool still_dropping = false;
int wrote_zoom = 0;
size_t tiling_seg = 0;
json_object *filter = NULL;
json_object_ptr filter;
std::vector<std::string> const *unidecode_data;
std::atomic<size_t> *dropped_count = NULL;
atomic_strategy *strategy = NULL;
@@ -1102,7 +1102,7 @@ struct next_feature_state {
// This function is called repeatedly from write_tile() to retrieve the next feature
// from the input stream. If the stream is at an end, it returns a feature with the
// geometry type set to -2.
static serial_feature next_feature(decompressor *geoms, std::atomic<long long> *geompos_in, int z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y, long long *original_features, long long *unclipped_features, int nextzoom, int maxzoom, int minzoom, int max_zoom_increment, size_t pass, std::atomic<long long> *along, long long alongminus, int buffer, std::atomic<bool> *within, compressor **geomfile, std::atomic<long long> *geompos, long long start_geompos[], std::atomic<double> *oprogress, double todo, const char *fname, int child_shards, json_object *filter, const char *global_stringpool, long long *pool_off, std::vector<std::vector<std::string>> *layer_unmaps, bool first_time, bool compressed, multiplier_state *multiplier_state, std::shared_ptr<std::string> &tile_stringpool, std::vector<std::string> const &unidecode_data, next_feature_state &next_feature_state, double droprate) {
static serial_feature next_feature(decompressor *geoms, std::atomic<long long> *geompos_in, int z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y, long long *original_features, long long *unclipped_features, int nextzoom, int maxzoom, int minzoom, int max_zoom_increment, size_t pass, std::atomic<long long> *along, long long alongminus, int buffer, std::atomic<bool> *within, compressor **geomfile, std::atomic<long long> *geompos, long long start_geompos[], std::atomic<double> *oprogress, double todo, const char *fname, int child_shards, json_object_ptr filter, const char *global_stringpool, long long *pool_off, std::vector<std::vector<std::string>> *layer_unmaps, bool first_time, bool compressed, multiplier_state *multiplier_state, std::shared_ptr<std::string> &tile_stringpool, std::vector<std::string> const &unidecode_data, next_feature_state &next_feature_state, double droprate) {
double extra_multiplier_zooms = log(retain_points_multiplier) / log(droprate);
while (1) {
@@ -1350,7 +1350,7 @@ struct run_prefilter_args {
char *global_stringpool = NULL;
long long *pool_off = NULL;
FILE *prefilter_fp = NULL;
json_object *filter = NULL;
json_object_ptr filter;
std::vector<std::string> const *unidecode_data;
bool first_time = false;
bool compressed = false;
@@ -1641,7 +1641,7 @@ void skip_tile(decompressor *geoms, std::atomic<long long> *geompos_in, bool com
}
}
long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, char *global_stringpool, int z, const unsigned tx, const unsigned ty, const int detail, int min_detail, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, compressor **geomfile, std::atomic<long long> *geompos, int minzoom, int maxzoom, double todo, std::atomic<long long> *along, long long alongminus, double gamma, int child_shards, long long *pool_off, unsigned *initial_x, unsigned *initial_y, std::atomic<int> *running, double simplification, std::vector<std::map<std::string, layermap_entry>> *layermaps, std::vector<std::vector<std::string>> *layer_unmaps, size_t tiling_seg, size_t pass, unsigned long long mingap, long long minextent, unsigned long long mindrop_sequence, double minattribute, const char *prefilter, const char *postfilter, json_object *filter, write_tile_args *arg, atomic_strategy *strategy_out, bool compressed_input, node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, std::vector<std::string> const &unidecode_data, long long estimated_complexity, std::set<zxy> &skip_children_out) {
long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, char *global_stringpool, int z, const unsigned tx, const unsigned ty, const int detail, int min_detail, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, compressor **geomfile, std::atomic<long long> *geompos, int minzoom, int maxzoom, double todo, std::atomic<long long> *along, long long alongminus, double gamma, int child_shards, long long *pool_off, unsigned *initial_x, unsigned *initial_y, std::atomic<int> *running, double simplification, std::vector<std::map<std::string, layermap_entry>> *layermaps, std::vector<std::vector<std::string>> *layer_unmaps, size_t tiling_seg, size_t pass, unsigned long long mingap, long long minextent, unsigned long long mindrop_sequence, double minattribute, const char *prefilter, const char *postfilter, json_object_ptr filter, write_tile_args *arg, atomic_strategy *strategy_out, bool compressed_input, node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, std::vector<std::string> const &unidecode_data, long long estimated_complexity, std::set<zxy> &skip_children_out) {
double merge_fraction = 1;
double mingap_fraction = 1;
double minextent_fraction = 1;
@@ -1775,7 +1775,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
pthread_t prefilter_writer;
run_prefilter_args rpa; // here so it stays in scope until joined
FILE *prefilter_read_fp = NULL;
json_pull *prefilter_jp = NULL;
json_pull_ptr prefilter_jp;
if (z < minzoom) {
prefilter = NULL;
@@ -3213,7 +3213,7 @@ exit(EXIT_IMPOSSIBLE);
return err_or_null;
}
int traverse_zooms(int *geomfd, off_t *geom_size, char *global_stringpool, std::atomic<unsigned> *midx, std::atomic<unsigned> *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, double maxzoom_simplification, std::vector<std::map<std::string, layermap_entry>> &layermaps, const char *prefilter, const char *postfilter, std::unordered_map<std::string, attribute_op> const *attribute_accum, json_object *filter, std::vector<strategy> &strategies, int iz, node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, int basezoom, double droprate, std::vector<std::string> const &unidecode_data, std::string const *drop_by_attribute_as_needed_attribute, bool drop_by_attribute_descending) {
int traverse_zooms(int *geomfd, off_t *geom_size, char *global_stringpool, std::atomic<unsigned> *midx, std::atomic<unsigned> *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, double maxzoom_simplification, std::vector<std::map<std::string, layermap_entry>> &layermaps, const char *prefilter, const char *postfilter, std::unordered_map<std::string, attribute_op> const *attribute_accum, json_object_ptr filter, std::vector<strategy> &strategies, int iz, node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, int basezoom, double droprate, std::vector<std::string> const &unidecode_data, std::string const *drop_by_attribute_as_needed_attribute, bool drop_by_attribute_descending) {
last_progress = 0;
// The existing layermaps are one table per input thread.
+1 -1
View File
@@ -62,7 +62,7 @@ struct strategy {
// long long write_tile(char **geom, char *stringpool, unsigned *file_bbox, int z, unsigned x, unsigned y, int detail, int min_detail, int basezoom, sqlite3 *outdb, const char *outdir, double droprate, int buffer, const char *fname, FILE **geomfile, int file_minzoom, int file_maxzoom, double todo, char *geomstart, long long along, double gamma, int nlayers, std::atomic<strategy> *strategy);
int traverse_zooms(int *geomfd, off_t *geom_size, char *stringpool, std::atomic<unsigned> *midx, std::atomic<unsigned> *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, double maxzoom_simplification, std::vector<std::map<std::string, layermap_entry> > &layermap, const char *prefilter, const char *postfilter, std::unordered_map<std::string, attribute_op> const *attribute_accum, struct json_object *filter, std::vector<strategy> &strategies, int iz, struct node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, int basezoom, double droprate, std::vector<std::string> const &unidecode_data, std::string const *drop_by_attribute_as_needed_attribute, bool drop_by_attribute_descending);
int traverse_zooms(int *geomfd, off_t *geom_size, char *stringpool, std::atomic<unsigned> *midx, std::atomic<unsigned> *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, double maxzoom_simplification, std::vector<std::map<std::string, layermap_entry> > &layermap, const char *prefilter, const char *postfilter, std::unordered_map<std::string, attribute_op> const *attribute_accum, json_object_ptr filter, std::vector<strategy> &strategies, int iz, struct node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, int basezoom, double droprate, std::vector<std::string> const &unidecode_data, std::string const *drop_by_attribute_as_needed_attribute, bool drop_by_attribute_descending);
int manage_gap(unsigned long long index, unsigned long long *previndex, double scale, double gamma, double *gap);