Merge pull request #969 from pwpiwi/gcc10_fixes
[legacy-proxmark3.git] / client / jansson / dump.c
blob89802c65dc65a35bf8cdf7b571f12710a8b4213a
1 /*
2 * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
4 * Jansson is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
8 #ifndef _GNU_SOURCE
9 #define _GNU_SOURCE
10 #endif
12 #include "jansson_private.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <assert.h>
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
22 #include "jansson.h"
23 #include "strbuffer.h"
24 #include "utf.h"
26 #define MAX_INTEGER_STR_LENGTH 100
27 #define MAX_REAL_STR_LENGTH 100
29 #define FLAGS_TO_INDENT(f) ((f) & 0x1F)
30 #define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
32 struct buffer {
33 const size_t size;
34 size_t used;
35 char *data;
38 static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
40 return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
43 static int dump_to_buffer(const char *buffer, size_t size, void *data)
45 struct buffer *buf = (struct buffer *)data;
47 if(buf->used + size <= buf->size)
48 memcpy(&buf->data[buf->used], buffer, size);
50 buf->used += size;
51 return 0;
54 static int dump_to_file(const char *buffer, size_t size, void *data)
56 FILE *dest = (FILE *)data;
57 if(fwrite(buffer, size, 1, dest) != 1)
58 return -1;
59 return 0;
62 static int dump_to_fd(const char *buffer, size_t size, void *data)
64 #ifdef HAVE_UNISTD_H
65 int *dest = (int *)data;
66 if(write(*dest, buffer, size) == (ssize_t)size)
67 return 0;
68 #endif
69 return -1;
72 /* 32 spaces (the maximum indentation size) */
73 static const char whitespace[] = " ";
75 static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
77 if(FLAGS_TO_INDENT(flags) > 0)
79 unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count;
81 if(dump("\n", 1, data))
82 return -1;
84 while(n_spaces > 0)
86 int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
88 if(dump(whitespace, cur_n, data))
89 return -1;
91 n_spaces -= cur_n;
94 else if(space && !(flags & JSON_COMPACT))
96 return dump(" ", 1, data);
98 return 0;
101 static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
103 const char *pos, *end, *lim;
104 int32_t codepoint = 0;
106 if(dump("\"", 1, data))
107 return -1;
109 end = pos = str;
110 lim = str + len;
111 while(1)
113 const char *text;
114 char seq[13];
115 int length;
117 while(end < lim)
119 end = utf8_iterate(pos, lim - pos, &codepoint);
120 if(!end)
121 return -1;
123 /* mandatory escape or control char */
124 if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
125 break;
127 /* slash */
128 if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
129 break;
131 /* non-ASCII */
132 if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
133 break;
135 pos = end;
138 if(pos != str) {
139 if(dump(str, pos - str, data))
140 return -1;
143 if(end == pos)
144 break;
146 /* handle \, /, ", and control codes */
147 length = 2;
148 switch(codepoint)
150 case '\\': text = "\\\\"; break;
151 case '\"': text = "\\\""; break;
152 case '\b': text = "\\b"; break;
153 case '\f': text = "\\f"; break;
154 case '\n': text = "\\n"; break;
155 case '\r': text = "\\r"; break;
156 case '\t': text = "\\t"; break;
157 case '/': text = "\\/"; break;
158 default:
160 /* codepoint is in BMP */
161 if(codepoint < 0x10000)
163 snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint);
164 length = 6;
167 /* not in BMP -> construct a UTF-16 surrogate pair */
168 else
170 int32_t first, last;
172 codepoint -= 0x10000;
173 first = 0xD800 | ((codepoint & 0xffc00) >> 10);
174 last = 0xDC00 | (codepoint & 0x003ff);
176 snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last);
177 length = 12;
180 text = seq;
181 break;
185 if(dump(text, length, data))
186 return -1;
188 str = pos = end;
191 return dump("\"", 1, data);
194 static int compare_keys(const void *key1, const void *key2)
196 return strcmp(*(const char **)key1, *(const char **)key2);
199 static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size)
201 snprintf(key, key_size, "%p", json);
202 if (hashtable_get(parents, key))
203 return -1;
205 return hashtable_set(parents, key, json_null());
208 static int do_dump(const json_t *json, size_t flags, int depth,
209 hashtable_t *parents, json_dump_callback_t dump, void *data)
211 int embed = flags & JSON_EMBED;
213 flags &= ~JSON_EMBED;
215 if(!json)
216 return -1;
218 switch(json_typeof(json)) {
219 case JSON_NULL:
220 return dump("null", 4, data);
222 case JSON_TRUE:
223 return dump("true", 4, data);
225 case JSON_FALSE:
226 return dump("false", 5, data);
228 case JSON_INTEGER:
230 char buffer[MAX_INTEGER_STR_LENGTH];
231 int size;
233 size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
234 "%" JSON_INTEGER_FORMAT,
235 json_integer_value(json));
236 if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
237 return -1;
239 return dump(buffer, size, data);
242 case JSON_REAL:
244 char buffer[MAX_REAL_STR_LENGTH];
245 int size;
246 double value = json_real_value(json);
248 size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
249 FLAGS_TO_PRECISION(flags));
250 if(size < 0)
251 return -1;
253 return dump(buffer, size, data);
256 case JSON_STRING:
257 return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
259 case JSON_ARRAY:
261 size_t n;
262 size_t i;
263 /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
264 char key[2 + (sizeof(json) * 2) + 1];
266 /* detect circular references */
267 if (loop_check(parents, json, key, sizeof(key)))
268 return -1;
270 n = json_array_size(json);
272 if(!embed && dump("[", 1, data))
273 return -1;
274 if(n == 0) {
275 hashtable_del(parents, key);
276 return embed ? 0 : dump("]", 1, data);
278 if(dump_indent(flags, depth + 1, 0, dump, data))
279 return -1;
281 for(i = 0; i < n; ++i) {
282 if(do_dump(json_array_get(json, i), flags, depth + 1,
283 parents, dump, data))
284 return -1;
286 if(i < n - 1)
288 if(dump(",", 1, data) ||
289 dump_indent(flags, depth + 1, 1, dump, data))
290 return -1;
292 else
294 if(dump_indent(flags, depth, 0, dump, data))
295 return -1;
299 hashtable_del(parents, key);
300 return embed ? 0 : dump("]", 1, data);
303 case JSON_OBJECT:
305 void *iter;
306 const char *separator;
307 int separator_length;
308 /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
309 char loop_key[2 + (sizeof(json) * 2) + 1];
311 if(flags & JSON_COMPACT) {
312 separator = ":";
313 separator_length = 1;
315 else {
316 separator = ": ";
317 separator_length = 2;
320 /* detect circular references */
321 if (loop_check(parents, json, loop_key, sizeof(loop_key)))
322 return -1;
324 iter = json_object_iter((json_t *)json);
326 if(!embed && dump("{", 1, data))
327 return -1;
328 if(!iter) {
329 hashtable_del(parents, loop_key);
330 return embed ? 0 : dump("}", 1, data);
332 if(dump_indent(flags, depth + 1, 0, dump, data))
333 return -1;
335 if(flags & JSON_SORT_KEYS)
337 const char **keys;
338 size_t size, i;
340 size = json_object_size(json);
341 keys = jsonp_malloc(size * sizeof(const char *));
342 if(!keys)
343 return -1;
345 i = 0;
346 while(iter)
348 keys[i] = json_object_iter_key(iter);
349 iter = json_object_iter_next((json_t *)json, iter);
350 i++;
352 assert(i == size);
354 qsort(keys, size, sizeof(const char *), compare_keys);
356 for(i = 0; i < size; i++)
358 const char *key;
359 json_t *value;
361 key = keys[i];
362 value = json_object_get(json, key);
363 assert(value);
365 dump_string(key, strlen(key), dump, data, flags);
366 if(dump(separator, separator_length, data) ||
367 do_dump(value, flags, depth + 1, parents, dump, data))
369 jsonp_free(keys);
370 return -1;
373 if(i < size - 1)
375 if(dump(",", 1, data) ||
376 dump_indent(flags, depth + 1, 1, dump, data))
378 jsonp_free(keys);
379 return -1;
382 else
384 if(dump_indent(flags, depth, 0, dump, data))
386 jsonp_free(keys);
387 return -1;
392 jsonp_free(keys);
394 else
396 /* Don't sort keys */
398 while(iter)
400 void *next = json_object_iter_next((json_t *)json, iter);
401 const char *key = json_object_iter_key(iter);
403 dump_string(key, strlen(key), dump, data, flags);
404 if(dump(separator, separator_length, data) ||
405 do_dump(json_object_iter_value(iter), flags, depth + 1,
406 parents, dump, data))
407 return -1;
409 if(next)
411 if(dump(",", 1, data) ||
412 dump_indent(flags, depth + 1, 1, dump, data))
413 return -1;
415 else
417 if(dump_indent(flags, depth, 0, dump, data))
418 return -1;
421 iter = next;
425 hashtable_del(parents, loop_key);
426 return embed ? 0 : dump("}", 1, data);
429 default:
430 /* not reached */
431 return -1;
435 char *json_dumps(const json_t *json, size_t flags)
437 strbuffer_t strbuff;
438 char *result;
440 if(strbuffer_init(&strbuff))
441 return NULL;
443 if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
444 result = NULL;
445 else
446 result = jsonp_strdup(strbuffer_value(&strbuff));
448 strbuffer_close(&strbuff);
449 return result;
452 size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags)
454 struct buffer buf = { size, 0, buffer };
456 if(json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
457 return 0;
459 return buf.used;
462 int json_dumpf(const json_t *json, FILE *output, size_t flags)
464 return json_dump_callback(json, dump_to_file, (void *)output, flags);
467 int json_dumpfd(const json_t *json, int output, size_t flags)
469 return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
472 int json_dump_file(const json_t *json, const char *path, size_t flags)
474 int result;
476 FILE *output = fopen(path, "w");
477 if(!output)
478 return -1;
480 result = json_dumpf(json, output, flags);
482 if(fclose(output) != 0)
483 return -1;
485 return result;
488 int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
490 int res;
491 hashtable_t parents_set;
493 if(!(flags & JSON_ENCODE_ANY)) {
494 if(!json_is_array(json) && !json_is_object(json))
495 return -1;
498 if (hashtable_init(&parents_set))
499 return -1;
500 res = do_dump(json, flags, 0, &parents_set, callback, data);
501 hashtable_close(&parents_set);
503 return res;