JSON can be written to either a FILE or a string

This commit is contained in:
Eric Fischer 2018-03-16 14:20:52 -07:00
parent 1c4aa57ffd
commit 08fc2f281e
2 changed files with 72 additions and 31 deletions

View File

@ -13,38 +13,38 @@ void json_writer::json_adjust() {
if (state.size() == 0) { if (state.size() == 0) {
state.push_back(JSON_WRITE_TOP); state.push_back(JSON_WRITE_TOP);
} else if (state[state.size() - 1] == JSON_WRITE_TOP) { } else if (state[state.size() - 1] == JSON_WRITE_TOP) {
fprintf(f, "\n"); addc('\n');
state[state.size() - 1] = JSON_WRITE_TOP; state[state.size() - 1] = JSON_WRITE_TOP;
} else if (state[state.size() - 1] == JSON_WRITE_HASH) { } else if (state[state.size() - 1] == JSON_WRITE_HASH) {
if (!nospace) { if (!nospace) {
fprintf(f, " "); addc(' ');
} }
nospace = false; nospace = false;
state[state.size() - 1] = JSON_WRITE_HASH_KEY; state[state.size() - 1] = JSON_WRITE_HASH_KEY;
} else if (state[state.size() - 1] == JSON_WRITE_HASH_KEY) { } else if (state[state.size() - 1] == JSON_WRITE_HASH_KEY) {
fprintf(f, ": "); adds(": ");
state[state.size() - 1] = JSON_WRITE_HASH_VALUE; state[state.size() - 1] = JSON_WRITE_HASH_VALUE;
} else if (state[state.size() - 1] == JSON_WRITE_HASH_VALUE) { } else if (state[state.size() - 1] == JSON_WRITE_HASH_VALUE) {
if (wantnl) { if (wantnl) {
fprintf(f, ",\n"); adds(",\n");
nospace = false; nospace = false;
} else { } else {
fprintf(f, ", "); adds(", ");
} }
wantnl = false; wantnl = false;
state[state.size() - 1] = JSON_WRITE_HASH_KEY; state[state.size() - 1] = JSON_WRITE_HASH_KEY;
} else if (state[state.size() - 1] == JSON_WRITE_ARRAY) { } else if (state[state.size() - 1] == JSON_WRITE_ARRAY) {
if (!nospace) { if (!nospace) {
fprintf(f, " "); addc(' ');
} }
nospace = false; nospace = false;
state[state.size() - 1] = JSON_WRITE_ARRAY_ELEMENT; state[state.size() - 1] = JSON_WRITE_ARRAY_ELEMENT;
} else if (state[state.size() - 1] == JSON_WRITE_ARRAY_ELEMENT) { } else if (state[state.size() - 1] == JSON_WRITE_ARRAY_ELEMENT) {
if (wantnl) { if (wantnl) {
fprintf(f, ",\n"); adds(",\n");
nospace = false; nospace = false;
} else { } else {
fprintf(f, ", "); adds(", ");
} }
wantnl = false; wantnl = false;
state[state.size() - 1] = JSON_WRITE_ARRAY_ELEMENT; state[state.size() - 1] = JSON_WRITE_ARRAY_ELEMENT;
@ -56,7 +56,7 @@ void json_writer::json_adjust() {
void json_writer::json_write_array() { void json_writer::json_write_array() {
json_adjust(); json_adjust();
fprintf(f, "["); addc('[');
state.push_back(JSON_WRITE_ARRAY); state.push_back(JSON_WRITE_ARRAY);
} }
@ -72,10 +72,10 @@ void json_writer::json_end_array() {
if (tok == JSON_WRITE_ARRAY || tok == JSON_WRITE_ARRAY_ELEMENT) { if (tok == JSON_WRITE_ARRAY || tok == JSON_WRITE_ARRAY_ELEMENT) {
if (!nospace) { if (!nospace) {
fprintf(f, " "); addc(' ');
} }
nospace = false; nospace = false;
fprintf(f, "]"); addc(']');
} else { } else {
fprintf(stderr, "End JSON array with unexpected state\n"); fprintf(stderr, "End JSON array with unexpected state\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -84,7 +84,7 @@ void json_writer::json_end_array() {
void json_writer::json_write_hash() { void json_writer::json_write_hash() {
json_adjust(); json_adjust();
fprintf(f, "{"); addc('{');
state.push_back(JSON_WRITE_HASH); state.push_back(JSON_WRITE_HASH);
} }
@ -100,16 +100,16 @@ void json_writer::json_end_hash() {
if (tok == JSON_WRITE_HASH) { if (tok == JSON_WRITE_HASH) {
if (!nospace) { if (!nospace) {
fprintf(f, " "); // Preserve accidental extra space from before adds(" "); // Preserve accidental extra space from before
} }
nospace = false; nospace = false;
fprintf(f, "}"); addc('}');
} else if (tok == JSON_WRITE_HASH_VALUE) { } else if (tok == JSON_WRITE_HASH_VALUE) {
if (!nospace) { if (!nospace) {
fprintf(f, " "); addc(' ');
} }
nospace = false; nospace = false;
fprintf(f, "}"); addc('}');
} else { } else {
fprintf(stderr, "End JSON hash with unexpected state\n"); fprintf(stderr, "End JSON hash with unexpected state\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -119,68 +119,68 @@ void json_writer::json_end_hash() {
void json_writer::json_write_string(std::string const &s) { void json_writer::json_write_string(std::string const &s) {
json_adjust(); json_adjust();
putc('"', f); addc('"');
for (size_t i = 0; i < s.size(); i++) { for (size_t i = 0; i < s.size(); i++) {
if (s[i] == '\\' || s[i] == '"') { if (s[i] == '\\' || s[i] == '"') {
fprintf(f, "\\%c", s[i]); aprintf("\\%c", s[i]);
} else if ((unsigned char) s[i] < ' ') { } else if ((unsigned char) s[i] < ' ') {
fprintf(f, "\\u%04x", s[i]); aprintf("\\u%04x", s[i]);
} else { } else {
putc(s[i], f); addc(s[i]);
} }
} }
putc('"', f); addc('"');
} }
void json_writer::json_write_number(double d) { void json_writer::json_write_number(double d) {
json_adjust(); json_adjust();
fputs(milo::dtoa_milo(d).c_str(), f); adds(milo::dtoa_milo(d).c_str());
} }
// Just to avoid json_writer:: changing expected output format // Just to avoid json_writer:: changing expected output format
void json_writer::json_write_float(double d) { void json_writer::json_write_float(double d) {
json_adjust(); json_adjust();
fprintf(f, "%f", d); aprintf("%f", d);
} }
void json_writer::json_write_unsigned(unsigned long long v) { void json_writer::json_write_unsigned(unsigned long long v) {
json_adjust(); json_adjust();
fprintf(f, "%llu", v); aprintf("%llu", v);
} }
void json_writer::json_write_signed(long long v) { void json_writer::json_write_signed(long long v) {
json_adjust(); json_adjust();
fprintf(f, "%lld", v); aprintf("%lld", v);
} }
void json_writer::json_write_stringified(std::string const &s) { void json_writer::json_write_stringified(std::string const &s) {
json_adjust(); json_adjust();
fputs(s.c_str(), f); adds(s);
} }
void json_writer::json_write_bool(bool b) { void json_writer::json_write_bool(bool b) {
json_adjust(); json_adjust();
if (b) { if (b) {
fputs("true", f); adds("true");
} else { } else {
fputs("false", f); adds("false");
} }
} }
void json_writer::json_write_null() { void json_writer::json_write_null() {
json_adjust(); json_adjust();
fputs("null", f); adds("null");
} }
void json_writer::json_write_newline() { void json_writer::json_write_newline() {
putc('\n', f); addc('\n');
nospace = true; nospace = true;
} }
@ -188,6 +188,37 @@ void json_writer::json_comma_newline() {
wantnl = true; wantnl = true;
} }
void json_writer::aprintf(const char *format, ...) {
va_list ap;
char *tmp;
va_start(ap, format);
if (vasprintf(&tmp, format, ap) < 0) {
fprintf(stderr, "memory allocation failure\n");
exit(EXIT_FAILURE);
}
va_end(ap);
adds(std::string(tmp, strlen(tmp)));
free(tmp);
}
void json_writer::addc(char c) {
if (f != NULL) {
putc(c, f);
} else if (s != NULL) {
s->push_back(c);
}
}
void json_writer::adds(std::string const &str) {
if (f != NULL) {
fputs(str.c_str(), f);
} else if (s != NULL) {
s->append(str);
}
}
struct lonlat { struct lonlat {
int op; int op;
double lon; double lon;

View File

@ -18,7 +18,8 @@ struct json_writer {
std::vector<json_write_tok> state; std::vector<json_write_tok> state;
bool nospace = false; bool nospace = false;
bool wantnl = false; bool wantnl = false;
FILE *f; FILE *f = NULL;
std::string *s = NULL;
~json_writer() { ~json_writer() {
if (state.size() > 0) { if (state.size() > 0) {
@ -33,6 +34,10 @@ struct json_writer {
f = fp; f = fp;
} }
json_writer(std::string *out) {
s = out;
}
void json_write_array(); void json_write_array();
void json_end_array(); void json_end_array();
void json_write_hash(); void json_write_hash();
@ -47,7 +52,12 @@ struct json_writer {
void json_write_null(); void json_write_null();
void json_write_newline(); void json_write_newline();
void json_comma_newline(); void json_comma_newline();
private:
void json_adjust(); void json_adjust();
void aprintf(const char *format, ...);
void addc(char c);
void adds(std::string const &s);
}; };
void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, bool zoom, bool dropped, unsigned long long index, long long sequence, long long extent, bool complain, json_writer &state); void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, bool zoom, bool dropped, unsigned long long index, long long sequence, long long extent, bool complain, json_writer &state);