"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.
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 }