"Fossies" - the Fresh Open Source Software Archive 
Member "jansson-2.14/src/dump.c" (26 Jan 2021, 13990 Bytes) of package /linux/www/jansson-2.14.tar.bz2:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "dump.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.13.1_vs_2.14.
1 /*
2 * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
3 *
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 */
7
8 #ifndef _GNU_SOURCE
9 #define _GNU_SOURCE
10 #endif
11
12 #include "jansson_private.h"
13
14 #include <assert.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
21
22 #include "jansson.h"
23 #include "strbuffer.h"
24 #include "utf.h"
25
26 #define MAX_INTEGER_STR_LENGTH 100
27 #define MAX_REAL_STR_LENGTH 100
28
29 #define FLAGS_TO_INDENT(f) ((f)&0x1F)
30 #define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
31
32 struct buffer {
33 const size_t size;
34 size_t used;
35 char *data;
36 };
37
38 static int dump_to_strbuffer(const char *buffer, size_t size, void *data) {
39 return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
40 }
41
42 static int dump_to_buffer(const char *buffer, size_t size, void *data) {
43 struct buffer *buf = (struct buffer *)data;
44
45 if (buf->used + size <= buf->size)
46 memcpy(&buf->data[buf->used], buffer, size);
47
48 buf->used += size;
49 return 0;
50 }
51
52 static int dump_to_file(const char *buffer, size_t size, void *data) {
53 FILE *dest = (FILE *)data;
54 if (fwrite(buffer, size, 1, dest) != 1)
55 return -1;
56 return 0;
57 }
58
59 static int dump_to_fd(const char *buffer, size_t size, void *data) {
60 #ifdef HAVE_UNISTD_H
61 int *dest = (int *)data;
62 if (write(*dest, buffer, size) == (ssize_t)size)
63 return 0;
64 #endif
65 return -1;
66 }
67
68 /* 32 spaces (the maximum indentation size) */
69 static const char whitespace[] = " ";
70
71 static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump,
72 void *data) {
73 if (FLAGS_TO_INDENT(flags) > 0) {
74 unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count;
75
76 if (dump("\n", 1, data))
77 return -1;
78
79 while (n_spaces > 0) {
80 int cur_n =
81 n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
82
83 if (dump(whitespace, cur_n, data))
84 return -1;
85
86 n_spaces -= cur_n;
87 }
88 } else if (space && !(flags & JSON_COMPACT)) {
89 return dump(" ", 1, data);
90 }
91 return 0;
92 }
93
94 static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data,
95 size_t flags) {
96 const char *pos, *end, *lim;
97 int32_t codepoint = 0;
98
99 if (dump("\"", 1, data))
100 return -1;
101
102 end = pos = str;
103 lim = str + len;
104 while (1) {
105 const char *text;
106 char seq[13];
107 int length;
108
109 while (end < lim) {
110 end = utf8_iterate(pos, lim - pos, &codepoint);
111 if (!end)
112 return -1;
113
114 /* mandatory escape or control char */
115 if (codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
116 break;
117
118 /* slash */
119 if ((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
120 break;
121
122 /* non-ASCII */
123 if ((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
124 break;
125
126 pos = end;
127 }
128
129 if (pos != str) {
130 if (dump(str, pos - str, data))
131 return -1;
132 }
133
134 if (end == pos)
135 break;
136
137 /* handle \, /, ", and control codes */
138 length = 2;
139 switch (codepoint) {
140 case '\\':
141 text = "\\\\";
142 break;
143 case '\"':
144 text = "\\\"";
145 break;
146 case '\b':
147 text = "\\b";
148 break;
149 case '\f':
150 text = "\\f";
151 break;
152 case '\n':
153 text = "\\n";
154 break;
155 case '\r':
156 text = "\\r";
157 break;
158 case '\t':
159 text = "\\t";
160 break;
161 case '/':
162 text = "\\/";
163 break;
164 default: {
165 /* codepoint is in BMP */
166 if (codepoint < 0x10000) {
167 snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint);
168 length = 6;
169 }
170
171 /* not in BMP -> construct a UTF-16 surrogate pair */
172 else {
173 int32_t first, last;
174
175 codepoint -= 0x10000;
176 first = 0xD800 | ((codepoint & 0xffc00) >> 10);
177 last = 0xDC00 | (codepoint & 0x003ff);
178
179 snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first,
180 (unsigned int)last);
181 length = 12;
182 }
183
184 text = seq;
185 break;
186 }
187 }
188
189 if (dump(text, length, data))
190 return -1;
191
192 str = pos = end;
193 }
194
195 return dump("\"", 1, data);
196 }
197
198 struct key_len {
199 const char *key;
200 int len;
201 };
202
203 static int compare_keys(const void *key1, const void *key2) {
204 const struct key_len *k1 = key1;
205 const struct key_len *k2 = key2;
206 const size_t min_size = k1->len < k2->len ? k1->len : k2->len;
207 int res = memcmp(k1->key, k2->key, min_size);
208
209 if (res)
210 return res;
211
212 return k1->len - k2->len;
213 }
214
215 static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents,
216 json_dump_callback_t dump, void *data) {
217 int embed = flags & JSON_EMBED;
218
219 flags &= ~JSON_EMBED;
220
221 if (!json)
222 return -1;
223
224 switch (json_typeof(json)) {
225 case JSON_NULL:
226 return dump("null", 4, data);
227
228 case JSON_TRUE:
229 return dump("true", 4, data);
230
231 case JSON_FALSE:
232 return dump("false", 5, data);
233
234 case JSON_INTEGER: {
235 char buffer[MAX_INTEGER_STR_LENGTH];
236 int size;
237
238 size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%" JSON_INTEGER_FORMAT,
239 json_integer_value(json));
240 if (size < 0 || size >= MAX_INTEGER_STR_LENGTH)
241 return -1;
242
243 return dump(buffer, size, data);
244 }
245
246 case JSON_REAL: {
247 char buffer[MAX_REAL_STR_LENGTH];
248 int size;
249 double value = json_real_value(json);
250
251 size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
252 FLAGS_TO_PRECISION(flags));
253 if (size < 0)
254 return -1;
255
256 return dump(buffer, size, data);
257 }
258
259 case JSON_STRING:
260 return dump_string(json_string_value(json), json_string_length(json), dump,
261 data, flags);
262
263 case JSON_ARRAY: {
264 size_t n;
265 size_t i;
266 /* Space for "0x", double the sizeof a pointer for the hex and a
267 * terminator. */
268 char key[2 + (sizeof(json) * 2) + 1];
269 size_t key_len;
270
271 /* detect circular references */
272 if (jsonp_loop_check(parents, json, key, sizeof(key), &key_len))
273 return -1;
274
275 n = json_array_size(json);
276
277 if (!embed && dump("[", 1, data))
278 return -1;
279 if (n == 0) {
280 hashtable_del(parents, key, key_len);
281 return embed ? 0 : dump("]", 1, data);
282 }
283 if (dump_indent(flags, depth + 1, 0, dump, data))
284 return -1;
285
286 for (i = 0; i < n; ++i) {
287 if (do_dump(json_array_get(json, i), flags, depth + 1, parents, dump,
288 data))
289 return -1;
290
291 if (i < n - 1) {
292 if (dump(",", 1, data) ||
293 dump_indent(flags, depth + 1, 1, dump, data))
294 return -1;
295 } else {
296 if (dump_indent(flags, depth, 0, dump, data))
297 return -1;
298 }
299 }
300
301 hashtable_del(parents, key, key_len);
302 return embed ? 0 : dump("]", 1, data);
303 }
304
305 case JSON_OBJECT: {
306 void *iter;
307 const char *separator;
308 int separator_length;
309 char loop_key[LOOP_KEY_LEN];
310 size_t loop_key_len;
311
312 if (flags & JSON_COMPACT) {
313 separator = ":";
314 separator_length = 1;
315 } else {
316 separator = ": ";
317 separator_length = 2;
318 }
319
320 /* detect circular references */
321 if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key),
322 &loop_key_len))
323 return -1;
324
325 iter = json_object_iter((json_t *)json);
326
327 if (!embed && dump("{", 1, data))
328 return -1;
329 if (!iter) {
330 hashtable_del(parents, loop_key, loop_key_len);
331 return embed ? 0 : dump("}", 1, data);
332 }
333 if (dump_indent(flags, depth + 1, 0, dump, data))
334 return -1;
335
336 if (flags & JSON_SORT_KEYS) {
337 struct key_len *keys;
338 size_t size, i;
339
340 size = json_object_size(json);
341 keys = jsonp_malloc(size * sizeof(struct key_len));
342 if (!keys)
343 return -1;
344
345 i = 0;
346 while (iter) {
347 struct key_len *keylen = &keys[i];
348
349 keylen->key = json_object_iter_key(iter);
350 keylen->len = json_object_iter_key_len(iter);
351
352 iter = json_object_iter_next((json_t *)json, iter);
353 i++;
354 }
355 assert(i == size);
356
357 qsort(keys, size, sizeof(struct key_len), compare_keys);
358
359 for (i = 0; i < size; i++) {
360 const struct key_len *key;
361 json_t *value;
362
363 key = &keys[i];
364 value = json_object_getn(json, key->key, key->len);
365 assert(value);
366
367 dump_string(key->key, key->len, dump, data, flags);
368 if (dump(separator, separator_length, data) ||
369 do_dump(value, flags, depth + 1, parents, dump, data)) {
370 jsonp_free(keys);
371 return -1;
372 }
373
374 if (i < size - 1) {
375 if (dump(",", 1, data) ||
376 dump_indent(flags, depth + 1, 1, dump, data)) {
377 jsonp_free(keys);
378 return -1;
379 }
380 } else {
381 if (dump_indent(flags, depth, 0, dump, data)) {
382 jsonp_free(keys);
383 return -1;
384 }
385 }
386 }
387
388 jsonp_free(keys);
389 } else {
390 /* Don't sort keys */
391
392 while (iter) {
393 void *next = json_object_iter_next((json_t *)json, iter);
394 const char *key = json_object_iter_key(iter);
395 const size_t key_len = json_object_iter_key_len(iter);
396
397 dump_string(key, key_len, dump, data, flags);
398 if (dump(separator, separator_length, data) ||
399 do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
400 dump, data))
401 return -1;
402
403 if (next) {
404 if (dump(",", 1, data) ||
405 dump_indent(flags, depth + 1, 1, dump, data))
406 return -1;
407 } else {
408 if (dump_indent(flags, depth, 0, dump, data))
409 return -1;
410 }
411
412 iter = next;
413 }
414 }
415
416 hashtable_del(parents, loop_key, loop_key_len);
417 return embed ? 0 : dump("}", 1, data);
418 }
419
420 default:
421 /* not reached */
422 return -1;
423 }
424 }
425
426 char *json_dumps(const json_t *json, size_t flags) {
427 strbuffer_t strbuff;
428 char *result;
429
430 if (strbuffer_init(&strbuff))
431 return NULL;
432
433 if (json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
434 result = NULL;
435 else
436 result = jsonp_strdup(strbuffer_value(&strbuff));
437
438 strbuffer_close(&strbuff);
439 return result;
440 }
441
442 size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) {
443 struct buffer buf = {size, 0, buffer};
444
445 if (json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
446 return 0;
447
448 return buf.used;
449 }
450
451 int json_dumpf(const json_t *json, FILE *output, size_t flags) {
452 return json_dump_callback(json, dump_to_file, (void *)output, flags);
453 }
454
455 int json_dumpfd(const json_t *json, int output, size_t flags) {
456 return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
457 }
458
459 int json_dump_file(const json_t *json, const char *path, size_t flags) {
460 int result;
461
462 FILE *output = fopen(path, "w");
463 if (!output)
464 return -1;
465
466 result = json_dumpf(json, output, flags);
467
468 if (fclose(output) != 0)
469 return -1;
470
471 return result;
472 }
473
474 int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data,
475 size_t flags) {
476 int res;
477 hashtable_t parents_set;
478
479 if (!(flags & JSON_ENCODE_ANY)) {
480 if (!json_is_array(json) && !json_is_object(json))
481 return -1;
482 }
483
484 if (hashtable_init(&parents_set))
485 return -1;
486 res = do_dump(json, flags, 0, &parents_set, callback, data);
487 hashtable_close(&parents_set);
488
489 return res;
490 }