diff options
Diffstat (limited to 'src/jansson/dump.c')
-rw-r--r-- | src/jansson/dump.c | 212 |
1 files changed, 129 insertions, 83 deletions
diff --git a/src/jansson/dump.c b/src/jansson/dump.c index 7eddd5a..89802c6 100644 --- a/src/jansson/dump.c +++ b/src/jansson/dump.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -9,22 +9,30 @@ #define _GNU_SOURCE #endif +#include "jansson_private.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif #include "jansson.h" -#include "jansson_private.h" #include "strbuffer.h" #include "utf.h" #define MAX_INTEGER_STR_LENGTH 100 #define MAX_REAL_STR_LENGTH 100 -struct object_key { - size_t serial; - const char *key; +#define FLAGS_TO_INDENT(f) ((f) & 0x1F) +#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F) + +struct buffer { + const size_t size; + size_t used; + char *data; }; static int dump_to_strbuffer(const char *buffer, size_t size, void *data) @@ -32,6 +40,17 @@ static int dump_to_strbuffer(const char *buffer, size_t size, void *data) return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); } +static int dump_to_buffer(const char *buffer, size_t size, void *data) +{ + struct buffer *buf = (struct buffer *)data; + + if(buf->used + size <= buf->size) + memcpy(&buf->data[buf->used], buffer, size); + + buf->used += size; + return 0; +} + static int dump_to_file(const char *buffer, size_t size, void *data) { FILE *dest = (FILE *)data; @@ -40,22 +59,36 @@ static int dump_to_file(const char *buffer, size_t size, void *data) return 0; } +static int dump_to_fd(const char *buffer, size_t size, void *data) +{ +#ifdef HAVE_UNISTD_H + int *dest = (int *)data; + if(write(*dest, buffer, size) == (ssize_t)size) + return 0; +#endif + return -1; +} + /* 32 spaces (the maximum indentation size) */ static const char whitespace[] = " "; static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) { - if(JSON_INDENT(flags) > 0) + if(FLAGS_TO_INDENT(flags) > 0) { - int i, ws_count = JSON_INDENT(flags); + unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count; if(dump("\n", 1, data)) return -1; - for(i = 0; i < depth; i++) + while(n_spaces > 0) { - if(dump(whitespace, ws_count, data)) + int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1; + + if(dump(whitespace, cur_n, data)) return -1; + + n_spaces -= cur_n; } } else if(space && !(flags & JSON_COMPACT)) @@ -68,7 +101,7 @@ static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags) { const char *pos, *end, *lim; - int32_t codepoint; + int32_t codepoint = 0; if(dump("\"", 1, data)) return -1; @@ -127,7 +160,7 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v /* codepoint is in BMP */ if(codepoint < 0x10000) { - sprintf(seq, "\\u%04X", codepoint); + snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint); length = 6; } @@ -140,7 +173,7 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v first = 0xD800 | ((codepoint & 0xffc00) >> 10); last = 0xDC00 | (codepoint & 0x003ff); - sprintf(seq, "\\u%04X\\u%04X", first, last); + snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last); length = 12; } @@ -158,23 +191,27 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v return dump("\"", 1, data); } -static int object_key_compare_keys(const void *key1, const void *key2) +static int compare_keys(const void *key1, const void *key2) { - return strcmp(((const struct object_key *)key1)->key, - ((const struct object_key *)key2)->key); + return strcmp(*(const char **)key1, *(const char **)key2); } -static int object_key_compare_serials(const void *key1, const void *key2) +static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size) { - size_t a = ((const struct object_key *)key1)->serial; - size_t b = ((const struct object_key *)key2)->serial; + snprintf(key, key_size, "%p", json); + if (hashtable_get(parents, key)) + return -1; - return a < b ? -1 : a == b ? 0 : 1; + return hashtable_set(parents, key, json_null()); } static int do_dump(const json_t *json, size_t flags, int depth, - json_dump_callback_t dump, void *data) + hashtable_t *parents, json_dump_callback_t dump, void *data) { + int embed = flags & JSON_EMBED; + + flags &= ~JSON_EMBED; + if(!json) return -1; @@ -208,7 +245,8 @@ static int do_dump(const json_t *json, size_t flags, int depth, int size; double value = json_real_value(json); - size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value); + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value, + FLAGS_TO_PRECISION(flags)); if(size < 0) return -1; @@ -220,59 +258,55 @@ static int do_dump(const json_t *json, size_t flags, int depth, case JSON_ARRAY: { - int i; - int n; - json_array_t *array; + size_t n; + size_t i; + /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ + char key[2 + (sizeof(json) * 2) + 1]; /* detect circular references */ - array = json_to_array(json); - if(array->visited) - goto array_error; - array->visited = 1; + if (loop_check(parents, json, key, sizeof(key))) + return -1; n = json_array_size(json); - if(dump("[", 1, data)) - goto array_error; + if(!embed && dump("[", 1, data)) + return -1; if(n == 0) { - array->visited = 0; - return dump("]", 1, data); + hashtable_del(parents, key); + return embed ? 0 : dump("]", 1, data); } if(dump_indent(flags, depth + 1, 0, dump, data)) - goto array_error; + return -1; for(i = 0; i < n; ++i) { if(do_dump(json_array_get(json, i), flags, depth + 1, - dump, data)) - goto array_error; + parents, dump, data)) + return -1; if(i < n - 1) { if(dump(",", 1, data) || dump_indent(flags, depth + 1, 1, dump, data)) - goto array_error; + return -1; } else { if(dump_indent(flags, depth, 0, dump, data)) - goto array_error; + return -1; } } - array->visited = 0; - return dump("]", 1, data); - - array_error: - array->visited = 0; - return -1; + hashtable_del(parents, key); + return embed ? 0 : dump("]", 1, data); } case JSON_OBJECT: { - json_object_t *object; void *iter; const char *separator; int separator_length; + /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ + char loop_key[2 + (sizeof(json) * 2) + 1]; if(flags & JSON_COMPACT) { separator = ":"; @@ -284,65 +318,56 @@ static int do_dump(const json_t *json, size_t flags, int depth, } /* detect circular references */ - object = json_to_object(json); - if(object->visited) - goto object_error; - object->visited = 1; + if (loop_check(parents, json, loop_key, sizeof(loop_key))) + return -1; iter = json_object_iter((json_t *)json); - if(dump("{", 1, data)) - goto object_error; + if(!embed && dump("{", 1, data)) + return -1; if(!iter) { - object->visited = 0; - return dump("}", 1, data); + hashtable_del(parents, loop_key); + return embed ? 0 : dump("}", 1, data); } if(dump_indent(flags, depth + 1, 0, dump, data)) - goto object_error; + return -1; - if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) + if(flags & JSON_SORT_KEYS) { - struct object_key *keys; + const char **keys; size_t size, i; - int (*cmp_func)(const void *, const void *); size = json_object_size(json); - keys = jsonp_malloc(size * sizeof(struct object_key)); + keys = jsonp_malloc(size * sizeof(const char *)); if(!keys) - goto object_error; + return -1; i = 0; while(iter) { - keys[i].serial = hashtable_iter_serial(iter); - keys[i].key = json_object_iter_key(iter); + keys[i] = json_object_iter_key(iter); iter = json_object_iter_next((json_t *)json, iter); i++; } assert(i == size); - if(flags & JSON_SORT_KEYS) - cmp_func = object_key_compare_keys; - else - cmp_func = object_key_compare_serials; - - qsort(keys, size, sizeof(struct object_key), cmp_func); + qsort(keys, size, sizeof(const char *), compare_keys); for(i = 0; i < size; i++) { const char *key; json_t *value; - key = keys[i].key; + key = keys[i]; value = json_object_get(json, key); assert(value); dump_string(key, strlen(key), dump, data, flags); if(dump(separator, separator_length, data) || - do_dump(value, flags, depth + 1, dump, data)) + do_dump(value, flags, depth + 1, parents, dump, data)) { jsonp_free(keys); - goto object_error; + return -1; } if(i < size - 1) @@ -351,7 +376,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, dump_indent(flags, depth + 1, 1, dump, data)) { jsonp_free(keys); - goto object_error; + return -1; } } else @@ -359,7 +384,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, if(dump_indent(flags, depth, 0, dump, data)) { jsonp_free(keys); - goto object_error; + return -1; } } } @@ -378,31 +403,27 @@ static int do_dump(const json_t *json, size_t flags, int depth, dump_string(key, strlen(key), dump, data, flags); if(dump(separator, separator_length, data) || do_dump(json_object_iter_value(iter), flags, depth + 1, - dump, data)) - goto object_error; + parents, dump, data)) + return -1; if(next) { if(dump(",", 1, data) || dump_indent(flags, depth + 1, 1, dump, data)) - goto object_error; + return -1; } else { if(dump_indent(flags, depth, 0, dump, data)) - goto object_error; + return -1; } iter = next; } } - object->visited = 0; - return dump("}", 1, data); - - object_error: - object->visited = 0; - return -1; + hashtable_del(parents, loop_key); + return embed ? 0 : dump("}", 1, data); } default: @@ -428,11 +449,26 @@ char *json_dumps(const json_t *json, size_t flags) return result; } +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) +{ + struct buffer buf = { size, 0, buffer }; + + if(json_dump_callback(json, dump_to_buffer, (void *)&buf, flags)) + return 0; + + return buf.used; +} + int json_dumpf(const json_t *json, FILE *output, size_t flags) { return json_dump_callback(json, dump_to_file, (void *)output, flags); } +int json_dumpfd(const json_t *json, int output, size_t flags) +{ + return json_dump_callback(json, dump_to_fd, (void *)&output, flags); +} + int json_dump_file(const json_t *json, const char *path, size_t flags) { int result; @@ -443,16 +479,26 @@ int json_dump_file(const json_t *json, const char *path, size_t flags) result = json_dumpf(json, output, flags); - fclose(output); + if(fclose(output) != 0) + return -1; + return result; } int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) { + int res; + hashtable_t parents_set; + if(!(flags & JSON_ENCODE_ANY)) { if(!json_is_array(json) && !json_is_object(json)) return -1; } - return do_dump(json, flags, 0, callback, data); + if (hashtable_init(&parents_set)) + return -1; + res = do_dump(json, flags, 0, &parents_set, callback, data); + hashtable_close(&parents_set); + + return res; } |