Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tpruvot
GitHub Repository: tpruvot/cpuminer-multi
Path: blob/linux/compat/jansson/dump.c
1201 views
1
/*
2
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
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 <stdio.h>
13
#include <stdlib.h>
14
#include <string.h>
15
#include <assert.h>
16
17
#include "jansson.h"
18
#include "jansson_private.h"
19
#include "strbuffer.h"
20
#include "utf.h"
21
22
#define MAX_INTEGER_STR_LENGTH 100
23
#define MAX_REAL_STR_LENGTH 100
24
25
struct object_key {
26
size_t serial;
27
const char *key;
28
};
29
30
static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
31
{
32
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
33
}
34
35
static int dump_to_file(const char *buffer, size_t size, void *data)
36
{
37
FILE *dest = (FILE *)data;
38
if(fwrite(buffer, size, 1, dest) != 1)
39
return -1;
40
return 0;
41
}
42
43
/* 32 spaces (the maximum indentation size) */
44
static const char whitespace[] = " ";
45
46
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
47
{
48
if(JSON_INDENT(flags) > 0)
49
{
50
int i, ws_count = JSON_INDENT(flags);
51
52
if(dump("\n", 1, data))
53
return -1;
54
55
for(i = 0; i < depth; i++)
56
{
57
if(dump(whitespace, ws_count, data))
58
return -1;
59
}
60
}
61
else if(space && !(flags & JSON_COMPACT))
62
{
63
return dump(" ", 1, data);
64
}
65
return 0;
66
}
67
68
static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags)
69
{
70
const char *pos, *end;
71
int32_t codepoint;
72
73
if(dump("\"", 1, data))
74
return -1;
75
76
end = pos = str;
77
while(1)
78
{
79
const char *text;
80
char seq[13];
81
int length;
82
83
while(*end)
84
{
85
end = utf8_iterate(pos, &codepoint);
86
if(!end)
87
return -1;
88
89
/* mandatory escape or control char */
90
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
91
break;
92
93
/* slash */
94
if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
95
break;
96
97
/* non-ASCII */
98
if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
99
break;
100
101
pos = end;
102
}
103
104
if(pos != str) {
105
if(dump(str, pos - str, data))
106
return -1;
107
}
108
109
if(end == pos)
110
break;
111
112
/* handle \, /, ", and control codes */
113
length = 2;
114
switch(codepoint)
115
{
116
case '\\': text = "\\\\"; break;
117
case '\"': text = "\\\""; break;
118
case '\b': text = "\\b"; break;
119
case '\f': text = "\\f"; break;
120
case '\n': text = "\\n"; break;
121
case '\r': text = "\\r"; break;
122
case '\t': text = "\\t"; break;
123
case '/': text = "\\/"; break;
124
default:
125
{
126
/* codepoint is in BMP */
127
if(codepoint < 0x10000)
128
{
129
sprintf(seq, "\\u%04x", codepoint);
130
length = 6;
131
}
132
133
/* not in BMP -> construct a UTF-16 surrogate pair */
134
else
135
{
136
int32_t first, last;
137
138
codepoint -= 0x10000;
139
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
140
last = 0xDC00 | (codepoint & 0x003ff);
141
142
sprintf(seq, "\\u%04x\\u%04x", first, last);
143
length = 12;
144
}
145
146
text = seq;
147
break;
148
}
149
}
150
151
if(dump(text, length, data))
152
return -1;
153
154
str = pos = end;
155
}
156
157
return dump("\"", 1, data);
158
}
159
160
static int object_key_compare_keys(const void *key1, const void *key2)
161
{
162
return strcmp(((const struct object_key *)key1)->key,
163
((const struct object_key *)key2)->key);
164
}
165
166
static int object_key_compare_serials(const void *key1, const void *key2)
167
{
168
size_t a = ((const struct object_key *)key1)->serial;
169
size_t b = ((const struct object_key *)key2)->serial;
170
171
return a < b ? -1 : a == b ? 0 : 1;
172
}
173
174
static int do_dump(const json_t *json, size_t flags, int depth,
175
json_dump_callback_t dump, void *data)
176
{
177
if(!json)
178
return -1;
179
180
switch(json_typeof(json)) {
181
case JSON_NULL:
182
return dump("null", 4, data);
183
184
case JSON_TRUE:
185
return dump("true", 4, data);
186
187
case JSON_FALSE:
188
return dump("false", 5, data);
189
190
case JSON_INTEGER:
191
{
192
char buffer[MAX_INTEGER_STR_LENGTH];
193
int size;
194
195
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
196
"%" JSON_INTEGER_FORMAT,
197
json_integer_value(json));
198
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
199
return -1;
200
201
return dump(buffer, size, data);
202
}
203
204
case JSON_REAL:
205
{
206
char buffer[MAX_REAL_STR_LENGTH];
207
int size;
208
double value = json_real_value(json);
209
210
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
211
if(size < 0)
212
return -1;
213
214
return dump(buffer, size, data);
215
}
216
217
case JSON_STRING:
218
return dump_string(json_string_value(json), dump, data, flags);
219
220
case JSON_ARRAY:
221
{
222
int i;
223
int n;
224
json_array_t *array;
225
226
/* detect circular references */
227
array = json_to_array(json);
228
if(array->visited)
229
goto array_error;
230
array->visited = 1;
231
232
n = json_array_size(json);
233
234
if(dump("[", 1, data))
235
goto array_error;
236
if(n == 0) {
237
array->visited = 0;
238
return dump("]", 1, data);
239
}
240
if(dump_indent(flags, depth + 1, 0, dump, data))
241
goto array_error;
242
243
for(i = 0; i < n; ++i) {
244
if(do_dump(json_array_get(json, i), flags, depth + 1,
245
dump, data))
246
goto array_error;
247
248
if(i < n - 1)
249
{
250
if(dump(",", 1, data) ||
251
dump_indent(flags, depth + 1, 1, dump, data))
252
goto array_error;
253
}
254
else
255
{
256
if(dump_indent(flags, depth, 0, dump, data))
257
goto array_error;
258
}
259
}
260
261
array->visited = 0;
262
return dump("]", 1, data);
263
264
array_error:
265
array->visited = 0;
266
return -1;
267
}
268
269
case JSON_OBJECT:
270
{
271
json_object_t *object;
272
void *iter;
273
const char *separator;
274
int separator_length;
275
276
if(flags & JSON_COMPACT) {
277
separator = ":";
278
separator_length = 1;
279
}
280
else {
281
separator = ": ";
282
separator_length = 2;
283
}
284
285
/* detect circular references */
286
object = json_to_object(json);
287
if(object->visited)
288
goto object_error;
289
object->visited = 1;
290
291
iter = json_object_iter((json_t *)json);
292
293
if(dump("{", 1, data))
294
goto object_error;
295
if(!iter) {
296
object->visited = 0;
297
return dump("}", 1, data);
298
}
299
if(dump_indent(flags, depth + 1, 0, dump, data))
300
goto object_error;
301
302
if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
303
{
304
struct object_key *keys;
305
size_t size, i;
306
int (*cmp_func)(const void *, const void *);
307
308
size = json_object_size(json);
309
keys = jsonp_malloc(size * sizeof(struct object_key));
310
if(!keys)
311
goto object_error;
312
313
i = 0;
314
while(iter)
315
{
316
keys[i].serial = hashtable_iter_serial(iter);
317
keys[i].key = json_object_iter_key(iter);
318
iter = json_object_iter_next((json_t *)json, iter);
319
i++;
320
}
321
assert(i == size);
322
323
if(flags & JSON_SORT_KEYS)
324
cmp_func = object_key_compare_keys;
325
else
326
cmp_func = object_key_compare_serials;
327
328
qsort(keys, size, sizeof(struct object_key), cmp_func);
329
330
for(i = 0; i < size; i++)
331
{
332
const char *key;
333
json_t *value;
334
335
key = keys[i].key;
336
value = json_object_get(json, key);
337
assert(value);
338
339
dump_string(key, dump, data, flags);
340
if(dump(separator, separator_length, data) ||
341
do_dump(value, flags, depth + 1, dump, data))
342
{
343
jsonp_free(keys);
344
goto object_error;
345
}
346
347
if(i < size - 1)
348
{
349
if(dump(",", 1, data) ||
350
dump_indent(flags, depth + 1, 1, dump, data))
351
{
352
jsonp_free(keys);
353
goto object_error;
354
}
355
}
356
else
357
{
358
if(dump_indent(flags, depth, 0, dump, data))
359
{
360
jsonp_free(keys);
361
goto object_error;
362
}
363
}
364
}
365
366
jsonp_free(keys);
367
}
368
else
369
{
370
/* Don't sort keys */
371
372
while(iter)
373
{
374
void *next = json_object_iter_next((json_t *)json, iter);
375
376
dump_string(json_object_iter_key(iter), dump, data, flags);
377
if(dump(separator, separator_length, data) ||
378
do_dump(json_object_iter_value(iter), flags, depth + 1,
379
dump, data))
380
goto object_error;
381
382
if(next)
383
{
384
if(dump(",", 1, data) ||
385
dump_indent(flags, depth + 1, 1, dump, data))
386
goto object_error;
387
}
388
else
389
{
390
if(dump_indent(flags, depth, 0, dump, data))
391
goto object_error;
392
}
393
394
iter = next;
395
}
396
}
397
398
object->visited = 0;
399
return dump("}", 1, data);
400
401
object_error:
402
object->visited = 0;
403
return -1;
404
}
405
406
default:
407
/* not reached */
408
return -1;
409
}
410
}
411
412
char *json_dumps(const json_t *json, size_t flags)
413
{
414
strbuffer_t strbuff;
415
char *result;
416
417
if(strbuffer_init(&strbuff))
418
return NULL;
419
420
if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
421
result = NULL;
422
else
423
result = jsonp_strdup(strbuffer_value(&strbuff));
424
425
strbuffer_close(&strbuff);
426
return result;
427
}
428
429
int json_dumpf(const json_t *json, FILE *output, size_t flags)
430
{
431
return json_dump_callback(json, dump_to_file, (void *)output, flags);
432
}
433
434
int json_dump_file(const json_t *json, const char *path, size_t flags)
435
{
436
int result;
437
438
FILE *output = fopen(path, "w");
439
if(!output)
440
return -1;
441
442
result = json_dumpf(json, output, flags);
443
444
fclose(output);
445
return result;
446
}
447
448
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
449
{
450
if(!(flags & JSON_ENCODE_ANY)) {
451
if(!json_is_array(json) && !json_is_object(json))
452
return -1;
453
}
454
455
return do_dump(json, flags, 0, callback, data);
456
}
457
458