diff --git a/CHANGELOG.md b/CHANGELOG.md index 4757d7f..dd7cf81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.7.2 + +* Feature properties that are arrays or hashes get stringified + rather than being left out with a warning. + ## 1.7.1 * Make clipping behavior with no buffer consistent with Mapnik. diff --git a/geojson.c b/geojson.c index 09e74dc..85f5894 100644 --- a/geojson.c +++ b/geojson.c @@ -517,6 +517,7 @@ int serialize_geometry(json_object *geometry, json_object *properties, const cha char *metakey[nprop]; char *metaval[nprop]; int metatype[nprop]; + int mustfree[nprop]; int m = 0; int i; @@ -531,6 +532,7 @@ int serialize_geometry(json_object *geometry, json_object *properties, const cha } metakey[m] = properties->keys[i]->string; + mustfree[m] = 0; if (properties->values[i] != NULL && properties->values[i]->type == JSON_STRING) { metatype[m] = VT_STRING; @@ -547,8 +549,10 @@ int serialize_geometry(json_object *geometry, json_object *properties, const cha } else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_NULL)) { ; } else { - fprintf(stderr, "%s:%d: Unsupported property type for %s\n", reading, line, properties->keys[i]->string); - continue; + metatype[m] = VT_STRING; + metaval[m] = json_stringify(properties->values[i]); + mustfree[m] = 1; + m++; } } } @@ -557,6 +561,10 @@ int serialize_geometry(json_object *geometry, json_object *properties, const cha for (i = 0; i < m; i++) { serialize_long_long(metafile, addpool(poolfile, treefile, metakey[i], VT_STRING), metapos, fname); serialize_long_long(metafile, addpool(poolfile, treefile, metaval[i], metatype[i]), metapos, fname); + + if (mustfree[i]) { + free(metaval[i]); + } } long long geomstart = *geompos; diff --git a/jsonpull.c b/jsonpull.c index de2eaae..9d87e82 100644 --- a/jsonpull.c +++ b/jsonpull.c @@ -194,6 +194,21 @@ static void string_append(struct string *s, char c) { s->buf[s->n] = '\0'; } +static void string_append_string(struct string *s, char *add) { + int len = strlen(add); + + if (s->n + len + 1 >= s->nalloc) { + s->nalloc += 500 + len; + s->buf = realloc(s->buf, s->nalloc); + } + + for (; *add != '\0'; add++) { + s->buf[s->n++] = *add; + } + + s->buf[s->n] = '\0'; +} + static void string_free(struct string *s) { free(s->buf); } @@ -621,3 +636,85 @@ void json_disconnect(json_object *o) { o->parent = NULL; } + +static void json_print_one(struct string *val, json_object *o) { + if (o == NULL) { + string_append_string(val, "NULL"); + } else if (o->type == JSON_STRING) { + string_append(val, '\"'); + + char *cp; + for (cp = o->string; *cp != '\0'; cp++) { + if (*cp == '\\' || *cp == '"') { + string_append(val, '\\'); + string_append(val, *cp); + } else if (*cp >= 0 && *cp < ' ') { + char *s; + if (asprintf(&s, "\\u%04x", *cp) >= 0) { + string_append_string(val, s); + free(s); + } + } else { + string_append(val, *cp); + } + } + + string_append(val, '\"'); + } else if (o->type == JSON_NUMBER) { + char *s; + if (asprintf(&s, "%f", o->number) >= 0) { + string_append_string(val, s); + free(s); + } + } else if (o->type == JSON_NULL) { + string_append_string(val, "null"); + } else if (o->type == JSON_TRUE) { + string_append_string(val, "true"); + } else if (o->type == JSON_FALSE) { + string_append_string(val, "false"); + } else if (o->type == JSON_HASH) { + string_append(val, '}'); + } else if (o->type == JSON_ARRAY) { + string_append(val, ']'); + } +} + +static void json_print(struct string *val, json_object *o) { + if (o == NULL) { + // Hash value in incompletely read hash + string_append_string(val, "NULL"); + } else if (o->type == JSON_HASH) { + string_append(val, '{'); + + int i; + for (i = 0; i < o->length; i++) { + json_print(val, o->keys[i]); + string_append(val, ':'); + json_print(val, o->values[i]); + if (i + 1 < o->length) { + string_append(val, ','); + } + } + string_append(val, '}'); + } else if (o->type == JSON_ARRAY) { + string_append(val, '['); + int i; + for (i = 0; i < o->length; i++) { + json_print(val, o->array[i]); + if (i + 1 < o->length) { + string_append(val, ','); + } + } + string_append(val, ']'); + } else { + json_print_one(val, o); + } +} + +char *json_stringify(json_object *o) { + struct string val; + string_init(&val); + json_print(&val, o); + + return val.buf; +} diff --git a/jsonpull.h b/jsonpull.h index 645f47c..d5cc5aa 100644 --- a/jsonpull.h +++ b/jsonpull.h @@ -62,3 +62,5 @@ void json_free(json_object *j); void json_disconnect(json_object *j); json_object *json_hash_get(json_object *o, const char *s); + +char *json_stringify(json_object *o); diff --git a/version.h b/version.h index d7ec1c3..4b42f6d 100644 --- a/version.h +++ b/version.h @@ -1 +1 @@ -#define VERSION "tippecanoe v1.7.1\n" +#define VERSION "tippecanoe v1.7.2\n"