Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <locale.h>
5 : : #include <math.h>
6 : : #include <stdarg.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : : #include <sys/types.h>
10 : :
11 : : #include "sd-messages.h"
12 : :
13 : : #include "alloc-util.h"
14 : : #include "errno-util.h"
15 : : #include "fd-util.h"
16 : : #include "fileio.h"
17 : : #include "float.h"
18 : : #include "hexdecoct.h"
19 : : #include "json-internal.h"
20 : : #include "json.h"
21 : : #include "macro.h"
22 : : #include "memory-util.h"
23 : : #include "string-table.h"
24 : : #include "string-util.h"
25 : : #include "strv.h"
26 : : #include "terminal-util.h"
27 : : #include "utf8.h"
28 : :
29 : : /* Refuse putting together variants with a larger depth than 4K by default (as a protection against overflowing stacks
30 : : * if code processes JSON objects recursively. Note that we store the depth in an uint16_t, hence make sure this
31 : : * remains under 2^16.
32 : : * The value was 16k, but it was discovered to be too high on llvm/x86-64. See also the issue #10738. */
33 : : #define DEPTH_MAX (4U*1024U)
34 : : assert_cc(DEPTH_MAX <= UINT16_MAX);
35 : :
36 : : typedef struct JsonSource {
37 : : /* When we parse from a file or similar, encodes the filename, to indicate the source of a json variant */
38 : : size_t n_ref;
39 : : unsigned max_line;
40 : : unsigned max_column;
41 : : char name[];
42 : : } JsonSource;
43 : :
44 : : /* On x86-64 this whole structure should have a size of 6 * 64 bit = 48 bytes */
45 : : struct JsonVariant {
46 : : union {
47 : : /* We either maintain a reference counter for this variant itself, or we are embedded into an
48 : : * array/object, in which case only that surrounding object is ref-counted. (If 'embedded' is false,
49 : : * see below.) */
50 : : size_t n_ref;
51 : :
52 : : /* If this JsonVariant is part of an array/object, then this field points to the surrounding
53 : : * JSON_VARIANT_ARRAY/JSON_VARIANT_OBJECT object. (If 'embedded' is true, see below.) */
54 : : JsonVariant *parent;
55 : : };
56 : :
57 : : /* If this was parsed from some file or buffer, this stores where from, as well as the source line/column */
58 : : JsonSource *source;
59 : : unsigned line, column;
60 : :
61 : : JsonVariantType type:5;
62 : :
63 : : /* A marker whether this variant is embedded into in array/object or not. If true, the 'parent' pointer above
64 : : * is valid. If false, the 'n_ref' field above is valid instead. */
65 : : bool is_embedded:1;
66 : :
67 : : /* In some conditions (for example, if this object is part of an array of strings or objects), we don't store
68 : : * any data inline, but instead simply reference an external object and act as surrogate of it. In that case
69 : : * this bool is set, and the external object is referenced through the .reference field below. */
70 : : bool is_reference:1;
71 : :
72 : : /* While comparing two arrays, we use this for marking what we already have seen */
73 : : bool is_marked:1;
74 : :
75 : : /* The current 'depth' of the JsonVariant, i.e. how many levels of member variants this has */
76 : : uint16_t depth;
77 : :
78 : : union {
79 : : /* For simple types we store the value in-line. */
80 : : JsonValue value;
81 : :
82 : : /* For objects and arrays we store the number of elements immediately following */
83 : : size_t n_elements;
84 : :
85 : : /* If is_reference as indicated above is set, this is where the reference object is actually stored. */
86 : : JsonVariant *reference;
87 : :
88 : : /* Strings are placed immediately after the structure. Note that when this is a JsonVariant embedded
89 : : * into an array we might encode strings up to INLINE_STRING_LENGTH characters directly inside the
90 : : * element, while longer strings are stored as references. When this object is not embedded into an
91 : : * array, but stand-alone we allocate the right size for the whole structure, i.e. the array might be
92 : : * much larger than INLINE_STRING_LENGTH.
93 : : *
94 : : * Note that because we want to allocate arrays of the JsonVariant structure we specify [0] here,
95 : : * rather than the prettier []. If we wouldn't, then this char array would have undefined size, and so
96 : : * would the union and then the struct this is included in. And of structures with undefined size we
97 : : * can't allocate arrays (at least not easily). */
98 : : char string[0];
99 : : };
100 : : };
101 : :
102 : : /* Inside string arrays we have a series of JasonVariant structures one after the other. In this case, strings longer
103 : : * than INLINE_STRING_MAX are stored as references, and all shorter ones inline. (This means — on x86-64 — strings up
104 : : * to 15 chars are stored within the array elements, and all others in separate allocations) */
105 : : #define INLINE_STRING_MAX (sizeof(JsonVariant) - offsetof(JsonVariant, string) - 1U)
106 : :
107 : : /* Let's make sure this structure isn't increased in size accidentally. This check is only for our most relevant arch
108 : : * (x86-64). */
109 : : #ifdef __x86_64__
110 : : assert_cc(sizeof(JsonVariant) == 48U);
111 : : assert_cc(INLINE_STRING_MAX == 15U);
112 : : #endif
113 : :
114 : 4 : static JsonSource* json_source_new(const char *name) {
115 : : JsonSource *s;
116 : :
117 [ - + ]: 4 : assert(name);
118 : :
119 : 4 : s = malloc(offsetof(JsonSource, name) + strlen(name) + 1);
120 [ - + ]: 4 : if (!s)
121 : 0 : return NULL;
122 : :
123 : 4 : *s = (JsonSource) {
124 : : .n_ref = 1,
125 : : };
126 : 4 : strcpy(s->name, name);
127 : :
128 : 4 : return s;
129 : : }
130 : :
131 [ + + - + : 114640 : DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(JsonSource, json_source, mfree);
+ + ]
132 : :
133 : 4772 : static bool json_source_equal(JsonSource *a, JsonSource *b) {
134 [ + + ]: 4772 : if (a == b)
135 : 4704 : return true;
136 : :
137 [ - + # # ]: 68 : if (!a || !b)
138 : 68 : return false;
139 : :
140 : 0 : return streq(a->name, b->name);
141 : : }
142 : :
143 [ + - ]: 4 : DEFINE_TRIVIAL_CLEANUP_FUNC(JsonSource*, json_source_unref);
144 : :
145 : : /* There are four kind of JsonVariant* pointers:
146 : : *
147 : : * 1. NULL
148 : : * 2. A 'regular' one, i.e. pointing to malloc() memory
149 : : * 3. A 'magic' one, i.e. one of the special JSON_VARIANT_MAGIC_XYZ values, that encode a few very basic values directly in the pointer.
150 : : * 4. A 'const string' one, i.e. a pointer to a const string.
151 : : *
152 : : * The four kinds of pointers can be discerned like this:
153 : : *
154 : : * Detecting #1 is easy, just compare with NULL. Detecting #3 is similarly easy: all magic pointers are below
155 : : * _JSON_VARIANT_MAGIC_MAX (which is pretty low, within the first memory page, which is special on Linux and other
156 : : * OSes, as it is a faulting page). In order to discern #2 and #4 we check the lowest bit. If it's off it's #2,
157 : : * otherwise #4. This makes use of the fact that malloc() will return "maximum aligned" memory, which definitely
158 : : * means the pointer is even. This means we can use the uneven pointers to reference static strings, as long as we
159 : : * make sure that all static strings used like this are aligned to 2 (or higher), and that we mask the bit on
160 : : * access. The JSON_VARIANT_STRING_CONST() macro encodes strings as JsonVariant* pointers, with the bit set. */
161 : :
162 : 51668 : static bool json_variant_is_magic(const JsonVariant *v) {
163 [ - + ]: 51668 : if (!v)
164 : 0 : return false;
165 : :
166 : 51668 : return v < _JSON_VARIANT_MAGIC_MAX;
167 : : }
168 : :
169 : 210448 : static bool json_variant_is_const_string(const JsonVariant *v) {
170 : :
171 [ + + ]: 210448 : if (v < _JSON_VARIANT_MAGIC_MAX)
172 : 4112 : return false;
173 : :
174 : : /* A proper JsonVariant is aligned to whatever malloc() aligns things too, which is definitely not uneven. We
175 : : * hence use all uneven pointers as indicators for const strings. */
176 : :
177 : 206336 : return (((uintptr_t) v) & 1) != 0;
178 : : }
179 : :
180 : 597752 : static bool json_variant_is_regular(const JsonVariant *v) {
181 : :
182 [ + + ]: 597752 : if (v < _JSON_VARIANT_MAGIC_MAX)
183 : 8688 : return false;
184 : :
185 : 589064 : return (((uintptr_t) v) & 1) == 0;
186 : : }
187 : :
188 : 179072 : static JsonVariant *json_variant_dereference(JsonVariant *v) {
189 : :
190 : : /* Recursively dereference variants that are references to other variants */
191 : :
192 [ - + ]: 179072 : if (!v)
193 : 0 : return NULL;
194 : :
195 [ + + ]: 179072 : if (!json_variant_is_regular(v))
196 : 27620 : return v;
197 : :
198 [ + + ]: 151452 : if (!v->is_reference)
199 : 132400 : return v;
200 : :
201 : 19052 : return json_variant_dereference(v->reference);
202 : : }
203 : :
204 : 40500 : static uint16_t json_variant_depth(JsonVariant *v) {
205 : :
206 : 40500 : v = json_variant_dereference(v);
207 [ - + ]: 40500 : if (!v)
208 : 0 : return 0;
209 : :
210 [ + + ]: 40500 : if (!json_variant_is_regular(v))
211 : 9592 : return 0;
212 : :
213 : 30908 : return v->depth;
214 : : }
215 : :
216 : 55852 : static JsonVariant *json_variant_normalize(JsonVariant *v) {
217 : :
218 : : /* Converts json variants to their normalized form, i.e. fully dereferenced and wherever possible converted to
219 : : * the "magic" version if there is one */
220 : :
221 [ - + ]: 55852 : if (!v)
222 : 0 : return NULL;
223 : :
224 : 55852 : v = json_variant_dereference(v);
225 : :
226 [ + + + + : 55852 : switch (json_variant_type(v)) {
+ + + +
- ]
227 : :
228 : 1352 : case JSON_VARIANT_BOOLEAN:
229 [ + - ]: 1352 : return json_variant_boolean(v) ? JSON_VARIANT_MAGIC_TRUE : JSON_VARIANT_MAGIC_FALSE;
230 : :
231 : 112 : case JSON_VARIANT_NULL:
232 : 112 : return JSON_VARIANT_MAGIC_NULL;
233 : :
234 : 1512 : case JSON_VARIANT_INTEGER:
235 [ + + ]: 1512 : return json_variant_integer(v) == 0 ? JSON_VARIANT_MAGIC_ZERO_INTEGER : v;
236 : :
237 : 204 : case JSON_VARIANT_UNSIGNED:
238 [ + + ]: 204 : return json_variant_unsigned(v) == 0 ? JSON_VARIANT_MAGIC_ZERO_UNSIGNED : v;
239 : :
240 : 1364 : case JSON_VARIANT_REAL:
241 : : #pragma GCC diagnostic push
242 : : #pragma GCC diagnostic ignored "-Wfloat-equal"
243 [ + + ]: 1364 : return json_variant_real(v) == 0.0 ? JSON_VARIANT_MAGIC_ZERO_REAL : v;
244 : : #pragma GCC diagnostic pop
245 : :
246 : 15568 : case JSON_VARIANT_STRING:
247 [ + - ]: 15568 : return isempty(json_variant_string(v)) ? JSON_VARIANT_MAGIC_EMPTY_STRING : v;
248 : :
249 : 16488 : case JSON_VARIANT_ARRAY:
250 [ + - ]: 16488 : return json_variant_elements(v) == 0 ? JSON_VARIANT_MAGIC_EMPTY_ARRAY : v;
251 : :
252 : 19252 : case JSON_VARIANT_OBJECT:
253 [ + + ]: 19252 : return json_variant_elements(v) == 0 ? JSON_VARIANT_MAGIC_EMPTY_OBJECT : v;
254 : :
255 : 0 : default:
256 : 0 : return v;
257 : : }
258 : : }
259 : :
260 : 59728 : static JsonVariant *json_variant_conservative_normalize(JsonVariant *v) {
261 : :
262 : : /* Much like json_variant_normalize(), but won't simplify if the variant has a source/line location attached to
263 : : * it, in order not to lose context */
264 : :
265 [ - + ]: 59728 : if (!v)
266 : 0 : return NULL;
267 : :
268 [ + + ]: 59728 : if (!json_variant_is_regular(v))
269 : 12 : return v;
270 : :
271 [ + + + + : 59716 : if (v->source || v->line > 0 || v->column > 0)
- + ]
272 : 6216 : return v;
273 : :
274 : 53500 : return json_variant_normalize(v);
275 : : }
276 : :
277 : 11804 : static int json_variant_new(JsonVariant **ret, JsonVariantType type, size_t space) {
278 : : JsonVariant *v;
279 : :
280 [ - + - + ]: 11804 : assert_return(ret, -EINVAL);
281 : :
282 : 11804 : v = malloc0(MAX(sizeof(JsonVariant),
283 : : offsetof(JsonVariant, value) + space));
284 [ - + ]: 11804 : if (!v)
285 : 0 : return -ENOMEM;
286 : :
287 : 11804 : v->n_ref = 1;
288 : 11804 : v->type = type;
289 : :
290 : 11804 : *ret = v;
291 : 11804 : return 0;
292 : : }
293 : :
294 : 1384 : int json_variant_new_integer(JsonVariant **ret, intmax_t i) {
295 : : JsonVariant *v;
296 : : int r;
297 : :
298 [ - + - + ]: 1384 : assert_return(ret, -EINVAL);
299 : :
300 [ + + ]: 1384 : if (i == 0) {
301 : 20 : *ret = JSON_VARIANT_MAGIC_ZERO_INTEGER;
302 : 20 : return 0;
303 : : }
304 : :
305 : 1364 : r = json_variant_new(&v, JSON_VARIANT_INTEGER, sizeof(i));
306 [ - + ]: 1364 : if (r < 0)
307 : 0 : return r;
308 : :
309 : 1364 : v->value.integer = i;
310 : 1364 : *ret = v;
311 : :
312 : 1364 : return 0;
313 : : }
314 : :
315 : 640 : int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u) {
316 : : JsonVariant *v;
317 : : int r;
318 : :
319 [ - + - + ]: 640 : assert_return(ret, -EINVAL);
320 [ + + ]: 640 : if (u == 0) {
321 : 16 : *ret = JSON_VARIANT_MAGIC_ZERO_UNSIGNED;
322 : 16 : return 0;
323 : : }
324 : :
325 : 624 : r = json_variant_new(&v, JSON_VARIANT_UNSIGNED, sizeof(u));
326 [ - + ]: 624 : if (r < 0)
327 : 0 : return r;
328 : :
329 : 624 : v->value.unsig = u;
330 : 624 : *ret = v;
331 : :
332 : 624 : return 0;
333 : : }
334 : :
335 : 176 : int json_variant_new_real(JsonVariant **ret, long double d) {
336 : : JsonVariant *v;
337 : : int r;
338 : :
339 [ - + - + ]: 176 : assert_return(ret, -EINVAL);
340 : :
341 : : #pragma GCC diagnostic push
342 : : #pragma GCC diagnostic ignored "-Wfloat-equal"
343 [ + + ]: 176 : if (d == 0.0) {
344 : : #pragma GCC diagnostic pop
345 : 136 : *ret = JSON_VARIANT_MAGIC_ZERO_REAL;
346 : 136 : return 0;
347 : : }
348 : :
349 : 40 : r = json_variant_new(&v, JSON_VARIANT_REAL, sizeof(d));
350 [ - + ]: 40 : if (r < 0)
351 : 0 : return r;
352 : :
353 : 40 : v->value.real = d;
354 : 40 : *ret = v;
355 : :
356 : 40 : return 0;
357 : : }
358 : :
359 : 1872 : int json_variant_new_boolean(JsonVariant **ret, bool b) {
360 [ - + - + ]: 1872 : assert_return(ret, -EINVAL);
361 : :
362 [ + + ]: 1872 : if (b)
363 : 1868 : *ret = JSON_VARIANT_MAGIC_TRUE;
364 : : else
365 : 4 : *ret = JSON_VARIANT_MAGIC_FALSE;
366 : :
367 : 1872 : return 0;
368 : : }
369 : :
370 : 56 : int json_variant_new_null(JsonVariant **ret) {
371 [ - + - + ]: 56 : assert_return(ret, -EINVAL);
372 : :
373 : 56 : *ret = JSON_VARIANT_MAGIC_NULL;
374 : 56 : return 0;
375 : : }
376 : :
377 : 9780 : int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n) {
378 : : JsonVariant *v;
379 : : int r;
380 : :
381 [ - + - + ]: 9780 : assert_return(ret, -EINVAL);
382 [ + + ]: 9780 : if (!s) {
383 [ + - - + : 4 : assert_return(IN_SET(n, 0, (size_t) -1), -EINVAL);
- + ]
384 : 4 : return json_variant_new_null(ret);
385 : : }
386 [ + - ]: 9776 : if (n == (size_t) -1) /* determine length automatically */
387 : 9776 : n = strlen(s);
388 [ # # ]: 0 : else if (memchr(s, 0, n)) /* don't allow embedded NUL, as we can't express that in JSON */
389 : 0 : return -EINVAL;
390 [ - + ]: 9776 : if (n == 0) {
391 : 0 : *ret = JSON_VARIANT_MAGIC_EMPTY_STRING;
392 : 0 : return 0;
393 : : }
394 : :
395 : 9776 : r = json_variant_new(&v, JSON_VARIANT_STRING, n + 1);
396 [ - + ]: 9776 : if (r < 0)
397 : 0 : return r;
398 : :
399 : 9776 : memcpy(v->string, s, n);
400 : 9776 : v->string[n] = 0;
401 : :
402 : 9776 : *ret = v;
403 : 9776 : return 0;
404 : : }
405 : :
406 : 40496 : static void json_variant_set(JsonVariant *a, JsonVariant *b) {
407 [ - + ]: 40496 : assert(a);
408 : :
409 : 40496 : b = json_variant_dereference(b);
410 [ - + ]: 40496 : if (!b) {
411 : 0 : a->type = JSON_VARIANT_NULL;
412 : 0 : return;
413 : : }
414 : :
415 : 40496 : a->type = json_variant_type(b);
416 [ + + + + : 40496 : switch (a->type) {
+ + + - ]
417 : :
418 : 1384 : case JSON_VARIANT_INTEGER:
419 : 1384 : a->value.integer = json_variant_integer(b);
420 : 1384 : break;
421 : :
422 : 640 : case JSON_VARIANT_UNSIGNED:
423 : 640 : a->value.unsig = json_variant_unsigned(b);
424 : 640 : break;
425 : :
426 : 168 : case JSON_VARIANT_REAL:
427 : 168 : a->value.real = json_variant_real(b);
428 : 168 : break;
429 : :
430 : 1872 : case JSON_VARIANT_BOOLEAN:
431 : 1872 : a->value.boolean = json_variant_boolean(b);
432 : 1872 : break;
433 : :
434 : 17972 : case JSON_VARIANT_STRING: {
435 : : const char *s;
436 : :
437 [ - + ]: 17972 : assert_se(s = json_variant_string(b));
438 : :
439 : : /* Short strings we can store inline */
440 [ + + ]: 17972 : if (strnlen(s, INLINE_STRING_MAX+1) <= INLINE_STRING_MAX) {
441 : 17904 : strcpy(a->string, s);
442 : 17904 : break;
443 : : }
444 : :
445 : : /* For longer strings, use a reference… */
446 : : _fallthrough_;
447 : : }
448 : :
449 : : case JSON_VARIANT_ARRAY:
450 : : case JSON_VARIANT_OBJECT:
451 : 18464 : a->is_reference = true;
452 : 18464 : a->reference = json_variant_ref(json_variant_conservative_normalize(b));
453 : 18464 : break;
454 : :
455 : 64 : case JSON_VARIANT_NULL:
456 : 64 : break;
457 : :
458 : 0 : default:
459 : 0 : assert_not_reached("Unexpected variant type");
460 : : }
461 : : }
462 : :
463 : 40496 : static void json_variant_copy_source(JsonVariant *v, JsonVariant *from) {
464 [ - + ]: 40496 : assert(v);
465 [ - + ]: 40496 : assert(from);
466 : :
467 [ + + ]: 40496 : if (!json_variant_is_regular(from))
468 : 9584 : return;
469 : :
470 : 30912 : v->line = from->line;
471 : 30912 : v->column = from->column;
472 : 30912 : v->source = json_source_ref(from->source);
473 : : }
474 : :
475 : 8268 : int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n) {
476 : 8268 : _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
477 : :
478 [ - + - + ]: 8268 : assert_return(ret, -EINVAL);
479 [ - + ]: 8268 : if (n == 0) {
480 : 0 : *ret = JSON_VARIANT_MAGIC_EMPTY_ARRAY;
481 : 0 : return 0;
482 : : }
483 [ - + - + ]: 8268 : assert_return(array, -EINVAL);
484 : :
485 : 8268 : v = new(JsonVariant, n + 1);
486 [ - + ]: 8268 : if (!v)
487 : 0 : return -ENOMEM;
488 : :
489 : 8268 : *v = (JsonVariant) {
490 : : .n_ref = 1,
491 : : .type = JSON_VARIANT_ARRAY,
492 : : };
493 : :
494 [ + + ]: 16856 : for (v->n_elements = 0; v->n_elements < n; v->n_elements++) {
495 : 8588 : JsonVariant *w = v + 1 + v->n_elements,
496 : 8588 : *c = array[v->n_elements];
497 : : uint16_t d;
498 : :
499 : 8588 : d = json_variant_depth(c);
500 [ - + ]: 8588 : if (d >= DEPTH_MAX) /* Refuse too deep nesting */
501 : 0 : return -ELNRNG;
502 [ + + ]: 8588 : if (d >= v->depth)
503 : 8280 : v->depth = d + 1;
504 : :
505 : 8588 : *w = (JsonVariant) {
506 : : .is_embedded = true,
507 : : .parent = v,
508 : : };
509 : :
510 : 8588 : json_variant_set(w, c);
511 : 8588 : json_variant_copy_source(w, c);
512 : : }
513 : :
514 : 8268 : *ret = TAKE_PTR(v);
515 : 8268 : return 0;
516 : : }
517 : :
518 : 0 : int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n) {
519 : : JsonVariant *v;
520 : : size_t i;
521 : :
522 [ # # # # ]: 0 : assert_return(ret, -EINVAL);
523 [ # # ]: 0 : if (n == 0) {
524 : 0 : *ret = JSON_VARIANT_MAGIC_EMPTY_ARRAY;
525 : 0 : return 0;
526 : : }
527 [ # # # # ]: 0 : assert_return(p, -EINVAL);
528 : :
529 : 0 : v = new(JsonVariant, n + 1);
530 [ # # ]: 0 : if (!v)
531 : 0 : return -ENOMEM;
532 : :
533 : 0 : *v = (JsonVariant) {
534 : : .n_ref = 1,
535 : : .type = JSON_VARIANT_ARRAY,
536 : : .n_elements = n,
537 : : .depth = 1,
538 : : };
539 : :
540 [ # # ]: 0 : for (i = 0; i < n; i++) {
541 : 0 : JsonVariant *w = v + 1 + i;
542 : :
543 : 0 : *w = (JsonVariant) {
544 : : .is_embedded = true,
545 : : .parent = v,
546 : : .type = JSON_VARIANT_UNSIGNED,
547 : 0 : .value.unsig = ((const uint8_t*) p)[i],
548 : : };
549 : : }
550 : :
551 : 0 : *ret = v;
552 : 0 : return 0;
553 : : }
554 : :
555 : 4 : int json_variant_new_array_strv(JsonVariant **ret, char **l) {
556 : 4 : _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
557 : : size_t n;
558 : : int r;
559 : :
560 [ - + ]: 4 : assert(ret);
561 : :
562 : 4 : n = strv_length(l);
563 [ - + ]: 4 : if (n == 0) {
564 : 0 : *ret = JSON_VARIANT_MAGIC_EMPTY_ARRAY;
565 : 0 : return 0;
566 : : }
567 : :
568 : 4 : v = new(JsonVariant, n + 1);
569 [ - + ]: 4 : if (!v)
570 : 0 : return -ENOMEM;
571 : :
572 : 4 : *v = (JsonVariant) {
573 : : .n_ref = 1,
574 : : .type = JSON_VARIANT_ARRAY,
575 : : .depth = 1,
576 : : };
577 : :
578 [ + + ]: 20 : for (v->n_elements = 0; v->n_elements < n; v->n_elements++) {
579 : 16 : JsonVariant *w = v + 1 + v->n_elements;
580 : : size_t k;
581 : :
582 : 16 : *w = (JsonVariant) {
583 : : .is_embedded = true,
584 : : .parent = v,
585 : : .type = JSON_VARIANT_STRING,
586 : : };
587 : :
588 : 16 : k = strlen(l[v->n_elements]);
589 : :
590 [ - + ]: 16 : if (k > INLINE_STRING_MAX) {
591 : : /* If string is too long, store it as reference. */
592 : :
593 : 0 : r = json_variant_new_string(&w->reference, l[v->n_elements]);
594 [ # # ]: 0 : if (r < 0)
595 : 0 : return r;
596 : :
597 : 0 : w->is_reference = true;
598 : : } else
599 : 16 : memcpy(w->string, l[v->n_elements], k+1);
600 : : }
601 : :
602 : 4 : *ret = TAKE_PTR(v);
603 : 4 : return 0;
604 : : }
605 : :
606 : 12116 : int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n) {
607 : 12116 : _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
608 : :
609 [ - + - + ]: 12116 : assert_return(ret, -EINVAL);
610 [ + + ]: 12116 : if (n == 0) {
611 : 12 : *ret = JSON_VARIANT_MAGIC_EMPTY_OBJECT;
612 : 12 : return 0;
613 : : }
614 [ - + - + ]: 12104 : assert_return(array, -EINVAL);
615 [ - + - + ]: 12104 : assert_return(n % 2 == 0, -EINVAL);
616 : :
617 : 12104 : v = new(JsonVariant, n + 1);
618 [ - + ]: 12104 : if (!v)
619 : 0 : return -ENOMEM;
620 : :
621 : 12104 : *v = (JsonVariant) {
622 : : .n_ref = 1,
623 : : .type = JSON_VARIANT_OBJECT,
624 : : };
625 : :
626 [ + + ]: 44012 : for (v->n_elements = 0; v->n_elements < n; v->n_elements++) {
627 : 31912 : JsonVariant *w = v + 1 + v->n_elements,
628 : 31912 : *c = array[v->n_elements];
629 : : uint16_t d;
630 : :
631 [ + + ]: 31912 : if ((v->n_elements & 1) == 0 &&
632 [ - + ]: 15956 : !json_variant_is_string(c))
633 : 0 : return -EINVAL; /* Every second one needs to be a string, as it is the key name */
634 : :
635 : 31912 : d = json_variant_depth(c);
636 [ + + ]: 31912 : if (d >= DEPTH_MAX) /* Refuse too deep nesting */
637 : 4 : return -ELNRNG;
638 [ + + ]: 31908 : if (d >= v->depth)
639 : 22240 : v->depth = d + 1;
640 : :
641 : 31908 : *w = (JsonVariant) {
642 : : .is_embedded = true,
643 : : .parent = v,
644 : : };
645 : :
646 : 31908 : json_variant_set(w, c);
647 : 31908 : json_variant_copy_source(w, c);
648 : : }
649 : :
650 : 12100 : *ret = TAKE_PTR(v);
651 : 12100 : return 0;
652 : : }
653 : :
654 : 73436 : static void json_variant_free_inner(JsonVariant *v) {
655 [ - + ]: 73436 : assert(v);
656 : :
657 [ - + ]: 73436 : if (!json_variant_is_regular(v))
658 : 0 : return;
659 : :
660 : 73436 : json_source_unref(v->source);
661 : :
662 [ + + ]: 73436 : if (v->is_reference) {
663 : 18472 : json_variant_unref(v->reference);
664 : 18472 : return;
665 : : }
666 : :
667 [ + + + + ]: 54964 : if (IN_SET(v->type, JSON_VARIANT_ARRAY, JSON_VARIANT_OBJECT)) {
668 : : size_t i;
669 : :
670 [ + + ]: 60888 : for (i = 0; i < v->n_elements; i++)
671 : 40512 : json_variant_free_inner(v + 1 + i);
672 : : }
673 : : }
674 : :
675 : 24308 : JsonVariant *json_variant_ref(JsonVariant *v) {
676 [ - + ]: 24308 : if (!v)
677 : 0 : return NULL;
678 [ + + ]: 24308 : if (!json_variant_is_regular(v))
679 : 32 : return v;
680 : :
681 [ + + ]: 24276 : if (v->is_embedded)
682 : 544 : json_variant_ref(v->parent); /* ref the compounding variant instead */
683 : : else {
684 [ - + ]: 23732 : assert(v->n_ref > 0);
685 : 23732 : v->n_ref++;
686 : : }
687 : :
688 : 24276 : return v;
689 : : }
690 : :
691 : 66824 : JsonVariant *json_variant_unref(JsonVariant *v) {
692 [ + + ]: 66824 : if (!v)
693 : 7472 : return NULL;
694 [ + + ]: 59352 : if (!json_variant_is_regular(v))
695 : 2152 : return NULL;
696 : :
697 [ + + ]: 57200 : if (v->is_embedded)
698 : 544 : json_variant_unref(v->parent);
699 : : else {
700 [ - + ]: 56656 : assert(v->n_ref > 0);
701 : 56656 : v->n_ref--;
702 : :
703 [ + + ]: 56656 : if (v->n_ref == 0) {
704 : 32924 : json_variant_free_inner(v);
705 : 32924 : free(v);
706 : : }
707 : : }
708 : :
709 : 57200 : return NULL;
710 : : }
711 : :
712 : 7368 : void json_variant_unref_many(JsonVariant **array, size_t n) {
713 : : size_t i;
714 : :
715 [ + + - + ]: 7368 : assert(array || n == 0);
716 : :
717 [ + + ]: 26656 : for (i = 0; i < n; i++)
718 : 19288 : json_variant_unref(array[i]);
719 : 7368 : }
720 : :
721 : 51484 : const char *json_variant_string(JsonVariant *v) {
722 [ + + ]: 51484 : if (!v)
723 : 4 : return NULL;
724 [ - + ]: 51480 : if (v == JSON_VARIANT_MAGIC_EMPTY_STRING)
725 : 0 : return "";
726 [ - + ]: 51480 : if (json_variant_is_magic(v))
727 : 0 : goto mismatch;
728 [ + + ]: 51480 : if (json_variant_is_const_string(v)) {
729 : 8208 : uintptr_t p = (uintptr_t) v;
730 : :
731 [ - + ]: 8208 : assert((p & 1) != 0);
732 : 8208 : return (const char*) (p ^ 1U);
733 : : }
734 : :
735 [ + + ]: 43272 : if (v->is_reference)
736 : 56 : return json_variant_string(v->reference);
737 [ - + ]: 43216 : if (v->type != JSON_VARIANT_STRING)
738 : 0 : goto mismatch;
739 : :
740 : 43216 : return v->string;
741 : :
742 : 0 : mismatch:
743 [ # # ]: 0 : log_debug("Non-string JSON variant requested as string, returning NULL.");
744 : 0 : return NULL;
745 : : }
746 : :
747 : 5632 : bool json_variant_boolean(JsonVariant *v) {
748 [ - + ]: 5632 : if (!v)
749 : 0 : goto mismatch;
750 [ + + ]: 5632 : if (v == JSON_VARIANT_MAGIC_TRUE)
751 : 3212 : return true;
752 [ + + ]: 2420 : if (v == JSON_VARIANT_MAGIC_FALSE)
753 : 4 : return false;
754 [ - + ]: 2416 : if (!json_variant_is_regular(v))
755 : 0 : goto mismatch;
756 [ - + ]: 2416 : if (v->type != JSON_VARIANT_BOOLEAN)
757 : 0 : goto mismatch;
758 [ - + ]: 2416 : if (v->is_reference)
759 : 0 : return json_variant_boolean(v->reference);
760 : :
761 : 2416 : return v->value.boolean;
762 : :
763 : 0 : mismatch:
764 [ # # ]: 0 : log_debug("Non-boolean JSON variant requested as boolean, returning false.");
765 : 0 : return false;
766 : : }
767 : :
768 : 4500 : intmax_t json_variant_integer(JsonVariant *v) {
769 [ - + ]: 4500 : if (!v)
770 : 0 : goto mismatch;
771 [ + + + + ]: 4500 : if (v == JSON_VARIANT_MAGIC_ZERO_INTEGER ||
772 [ + + ]: 4416 : v == JSON_VARIANT_MAGIC_ZERO_UNSIGNED ||
773 : : v == JSON_VARIANT_MAGIC_ZERO_REAL)
774 : 132 : return 0;
775 [ - + ]: 4368 : if (!json_variant_is_regular(v))
776 : 0 : goto mismatch;
777 [ - + ]: 4368 : if (v->is_reference)
778 : 0 : return json_variant_integer(v->reference);
779 : :
780 [ + + + - ]: 4368 : switch (v->type) {
781 : :
782 : 4268 : case JSON_VARIANT_INTEGER:
783 : 4268 : return v->value.integer;
784 : :
785 : 52 : case JSON_VARIANT_UNSIGNED:
786 [ + - ]: 52 : if (v->value.unsig <= INTMAX_MAX)
787 : 52 : return (intmax_t) v->value.unsig;
788 : :
789 [ # # ]: 0 : log_debug("Unsigned integer %ju requested as signed integer and out of range, returning 0.", v->value.unsig);
790 : 0 : return 0;
791 : :
792 : 48 : case JSON_VARIANT_REAL: {
793 : : intmax_t converted;
794 : :
795 : 48 : converted = (intmax_t) v->value.real;
796 : :
797 : : #pragma GCC diagnostic push
798 : : #pragma GCC diagnostic ignored "-Wfloat-equal"
799 : 48 : if ((long double) converted == v->value.real)
800 : : #pragma GCC diagnostic pop
801 : 48 : return converted;
802 : :
803 : : log_debug("Real %Lg requested as integer, and cannot be converted losslessly, returning 0.", v->value.real);
804 : : return 0;
805 : : }
806 : :
807 : 0 : default:
808 : 0 : break;
809 : : }
810 : :
811 : 0 : mismatch:
812 [ # # ]: 0 : log_debug("Non-integer JSON variant requested as integer, returning 0.");
813 : 0 : return 0;
814 : : }
815 : :
816 : 1252 : uintmax_t json_variant_unsigned(JsonVariant *v) {
817 [ - + ]: 1252 : if (!v)
818 : 0 : goto mismatch;
819 [ + + + + ]: 1252 : if (v == JSON_VARIANT_MAGIC_ZERO_INTEGER ||
820 [ + + ]: 1184 : v == JSON_VARIANT_MAGIC_ZERO_UNSIGNED ||
821 : : v == JSON_VARIANT_MAGIC_ZERO_REAL)
822 : 112 : return 0;
823 [ - + ]: 1140 : if (!json_variant_is_regular(v))
824 : 0 : goto mismatch;
825 [ - + ]: 1140 : if (v->is_reference)
826 : 0 : return json_variant_integer(v->reference);
827 : :
828 [ + + + - ]: 1140 : switch (v->type) {
829 : :
830 : 4 : case JSON_VARIANT_INTEGER:
831 [ + - ]: 4 : if (v->value.integer >= 0)
832 : 4 : return (uintmax_t) v->value.integer;
833 : :
834 [ # # ]: 0 : log_debug("Signed integer %ju requested as unsigned integer and out of range, returning 0.", v->value.integer);
835 : 0 : return 0;
836 : :
837 : 1092 : case JSON_VARIANT_UNSIGNED:
838 : 1092 : return v->value.unsig;
839 : :
840 : 44 : case JSON_VARIANT_REAL: {
841 : : uintmax_t converted;
842 : :
843 : 44 : converted = (uintmax_t) v->value.real;
844 : :
845 : : #pragma GCC diagnostic push
846 : : #pragma GCC diagnostic ignored "-Wfloat-equal"
847 : 44 : if ((long double) converted == v->value.real)
848 : : #pragma GCC diagnostic pop
849 : 44 : return converted;
850 : :
851 : : log_debug("Real %Lg requested as unsigned integer, and cannot be converted losslessly, returning 0.", v->value.real);
852 : : return 0;
853 : : }
854 : :
855 : 0 : default:
856 : 0 : break;
857 : : }
858 : :
859 : 0 : mismatch:
860 [ # # ]: 0 : log_debug("Non-integer JSON variant requested as unsigned, returning 0.");
861 : 0 : return 0;
862 : : }
863 : :
864 : 2132 : long double json_variant_real(JsonVariant *v) {
865 [ - + ]: 2132 : if (!v)
866 : 0 : return 0.0;
867 [ + + + + ]: 2132 : if (v == JSON_VARIANT_MAGIC_ZERO_INTEGER ||
868 [ + + ]: 2044 : v == JSON_VARIANT_MAGIC_ZERO_UNSIGNED ||
869 : : v == JSON_VARIANT_MAGIC_ZERO_REAL)
870 : 316 : return 0.0;
871 [ - + ]: 1816 : if (!json_variant_is_regular(v))
872 : 0 : goto mismatch;
873 [ - + ]: 1816 : if (v->is_reference)
874 : 0 : return json_variant_real(v->reference);
875 : :
876 [ + + + - ]: 1816 : switch (v->type) {
877 : :
878 : 1804 : case JSON_VARIANT_REAL:
879 : 1804 : return v->value.real;
880 : :
881 : 8 : case JSON_VARIANT_INTEGER: {
882 : : long double converted;
883 : :
884 : 8 : converted = (long double) v->value.integer;
885 : :
886 [ + - ]: 8 : if ((intmax_t) converted == v->value.integer)
887 : 8 : return converted;
888 : :
889 [ # # ]: 0 : log_debug("Signed integer %ji requested as real, and cannot be converted losslessly, returning 0.", v->value.integer);
890 : 0 : return 0.0;
891 : : }
892 : :
893 : 4 : case JSON_VARIANT_UNSIGNED: {
894 : : long double converted;
895 : :
896 : 4 : converted = (long double) v->value.unsig;
897 : :
898 [ + - ]: 4 : if ((uintmax_t) converted == v->value.unsig)
899 : 4 : return converted;
900 : :
901 [ # # ]: 0 : log_debug("Unsigned integer %ju requested as real, and cannot be converted losslessly, returning 0.", v->value.unsig);
902 : 0 : return 0.0;
903 : : }
904 : :
905 : 0 : default:
906 : 0 : break;
907 : : }
908 : :
909 : 0 : mismatch:
910 [ # # ]: 0 : log_debug("Non-integer JSON variant requested as integer, returning 0.");
911 : 0 : return 0.0;
912 : : }
913 : :
914 : 52 : bool json_variant_is_negative(JsonVariant *v) {
915 [ - + ]: 52 : if (!v)
916 : 0 : goto mismatch;
917 [ + - + - ]: 52 : if (v == JSON_VARIANT_MAGIC_ZERO_INTEGER ||
918 [ - + ]: 52 : v == JSON_VARIANT_MAGIC_ZERO_UNSIGNED ||
919 : : v == JSON_VARIANT_MAGIC_ZERO_REAL)
920 : 0 : return false;
921 [ - + ]: 52 : if (!json_variant_is_regular(v))
922 : 0 : goto mismatch;
923 [ - + ]: 52 : if (v->is_reference)
924 : 0 : return json_variant_is_negative(v->reference);
925 : :
926 : : /* This function is useful as checking whether numbers are negative is pretty complex since we have three types
927 : : * of numbers. And some JSON code (OCI for example) uses negative numbers to mark "not defined" numeric
928 : : * values. */
929 : :
930 [ + + + - ]: 52 : switch (v->type) {
931 : :
932 : 44 : case JSON_VARIANT_REAL:
933 : 44 : return v->value.real < 0;
934 : :
935 : 4 : case JSON_VARIANT_INTEGER:
936 : 4 : return v->value.integer < 0;
937 : :
938 : 4 : case JSON_VARIANT_UNSIGNED:
939 : 4 : return false;
940 : :
941 : 0 : default:
942 : 0 : break;
943 : : }
944 : :
945 : 0 : mismatch:
946 [ # # ]: 0 : log_debug("Non-integer JSON variant tested for negativity, returning false.");
947 : 0 : return false;
948 : : }
949 : :
950 : 158592 : JsonVariantType json_variant_type(JsonVariant *v) {
951 : :
952 [ - + ]: 158592 : if (!v)
953 : 0 : return _JSON_VARIANT_TYPE_INVALID;
954 : :
955 [ + + ]: 158592 : if (json_variant_is_const_string(v))
956 : 16404 : return JSON_VARIANT_STRING;
957 : :
958 [ + + + + ]: 142188 : if (v == JSON_VARIANT_MAGIC_TRUE || v == JSON_VARIANT_MAGIC_FALSE)
959 : 3216 : return JSON_VARIANT_BOOLEAN;
960 : :
961 [ + + ]: 138972 : if (v == JSON_VARIANT_MAGIC_NULL)
962 : 104 : return JSON_VARIANT_NULL;
963 : :
964 [ + + ]: 138868 : if (v == JSON_VARIANT_MAGIC_ZERO_INTEGER)
965 : 128 : return JSON_VARIANT_INTEGER;
966 : :
967 [ + + ]: 138740 : if (v == JSON_VARIANT_MAGIC_ZERO_UNSIGNED)
968 : 112 : return JSON_VARIANT_UNSIGNED;
969 : :
970 [ + + ]: 138628 : if (v == JSON_VARIANT_MAGIC_ZERO_REAL)
971 : 320 : return JSON_VARIANT_REAL;
972 : :
973 [ - + ]: 138308 : if (v == JSON_VARIANT_MAGIC_EMPTY_STRING)
974 : 0 : return JSON_VARIANT_STRING;
975 : :
976 [ - + ]: 138308 : if (v == JSON_VARIANT_MAGIC_EMPTY_ARRAY)
977 : 0 : return JSON_VARIANT_ARRAY;
978 : :
979 [ + + ]: 138308 : if (v == JSON_VARIANT_MAGIC_EMPTY_OBJECT)
980 : 44 : return JSON_VARIANT_OBJECT;
981 : :
982 : 138264 : return v->type;
983 : : }
984 : :
985 : 23072 : bool json_variant_has_type(JsonVariant *v, JsonVariantType type) {
986 : : JsonVariantType rt;
987 : :
988 : 23072 : v = json_variant_dereference(v);
989 [ - + ]: 23072 : if (!v)
990 : 0 : return false;
991 : :
992 : 23072 : rt = json_variant_type(v);
993 [ + + ]: 23072 : if (rt == type)
994 : 22696 : return true;
995 : :
996 : : /* If it's a const string, then it only can be a string, and if it is not, it's not */
997 [ - + ]: 376 : if (json_variant_is_const_string(v))
998 : 0 : return false;
999 : :
1000 : : /* All three magic zeroes qualify as integer, unsigned and as real */
1001 [ + + + + : 376 : if ((v == JSON_VARIANT_MAGIC_ZERO_INTEGER || v == JSON_VARIANT_MAGIC_ZERO_UNSIGNED || v == JSON_VARIANT_MAGIC_ZERO_REAL) &&
+ + ]
1002 [ + - + - ]: 188 : IN_SET(type, JSON_VARIANT_INTEGER, JSON_VARIANT_UNSIGNED, JSON_VARIANT_REAL, JSON_VARIANT_NUMBER))
1003 : 188 : return true;
1004 : :
1005 : : /* All other magic variant types are only equal to themselves */
1006 [ - + ]: 188 : if (json_variant_is_magic(v))
1007 : 0 : return false;
1008 : :
1009 : : /* Handle the "number" pseudo type */
1010 [ + + ]: 188 : if (type == JSON_VARIANT_NUMBER)
1011 [ + - ]: 52 : return IN_SET(rt, JSON_VARIANT_INTEGER, JSON_VARIANT_UNSIGNED, JSON_VARIANT_REAL);
1012 : :
1013 : : /* Integer conversions are OK in many cases */
1014 [ + + + + ]: 136 : if (rt == JSON_VARIANT_INTEGER && type == JSON_VARIANT_UNSIGNED)
1015 : 4 : return v->value.integer >= 0;
1016 [ + + + + ]: 132 : if (rt == JSON_VARIANT_UNSIGNED && type == JSON_VARIANT_INTEGER)
1017 : 28 : return v->value.unsig <= INTMAX_MAX;
1018 : :
1019 : : /* Any integer that can be converted lossley to a real and back may also be considered a real */
1020 [ + + + - ]: 104 : if (rt == JSON_VARIANT_INTEGER && type == JSON_VARIANT_REAL)
1021 : 8 : return (intmax_t) (long double) v->value.integer == v->value.integer;
1022 [ + + + - ]: 96 : if (rt == JSON_VARIANT_UNSIGNED && type == JSON_VARIANT_REAL)
1023 : 4 : return (uintmax_t) (long double) v->value.unsig == v->value.unsig;
1024 : :
1025 : : #pragma GCC diagnostic push
1026 : : #pragma GCC diagnostic ignored "-Wfloat-equal"
1027 : : /* Any real that can be converted losslessly to an integer and back may also be considered an integer */
1028 [ + - + + ]: 92 : if (rt == JSON_VARIANT_REAL && type == JSON_VARIANT_INTEGER)
1029 : 48 : return (long double) (intmax_t) v->value.real == v->value.real;
1030 [ + - + - ]: 44 : if (rt == JSON_VARIANT_REAL && type == JSON_VARIANT_UNSIGNED)
1031 : 44 : return (long double) (uintmax_t) v->value.real == v->value.real;
1032 : : #pragma GCC diagnostic pop
1033 : :
1034 : 0 : return false;
1035 : : }
1036 : :
1037 : 58348 : size_t json_variant_elements(JsonVariant *v) {
1038 [ - + ]: 58348 : if (!v)
1039 : 0 : return 0;
1040 [ + - + + ]: 58348 : if (v == JSON_VARIANT_MAGIC_EMPTY_ARRAY ||
1041 : : v == JSON_VARIANT_MAGIC_EMPTY_OBJECT)
1042 : 24 : return 0;
1043 [ - + ]: 58324 : if (!json_variant_is_regular(v))
1044 : 0 : goto mismatch;
1045 [ + - - + ]: 58324 : if (!IN_SET(v->type, JSON_VARIANT_ARRAY, JSON_VARIANT_OBJECT))
1046 : 0 : goto mismatch;
1047 [ + + ]: 58324 : if (v->is_reference)
1048 : 132 : return json_variant_elements(v->reference);
1049 : :
1050 : 58192 : return v->n_elements;
1051 : :
1052 : 0 : mismatch:
1053 [ # # ]: 0 : log_debug("Number of elements in non-array/non-object JSON variant requested, returning 0.");
1054 : 0 : return 0;
1055 : : }
1056 : :
1057 : 41528 : JsonVariant *json_variant_by_index(JsonVariant *v, size_t idx) {
1058 [ - + ]: 41528 : if (!v)
1059 : 0 : return NULL;
1060 [ + - - + ]: 41528 : if (v == JSON_VARIANT_MAGIC_EMPTY_ARRAY ||
1061 : : v == JSON_VARIANT_MAGIC_EMPTY_OBJECT)
1062 : 0 : return NULL;
1063 [ - + ]: 41528 : if (!json_variant_is_regular(v))
1064 : 0 : goto mismatch;
1065 [ + - - + ]: 41528 : if (!IN_SET(v->type, JSON_VARIANT_ARRAY, JSON_VARIANT_OBJECT))
1066 : 0 : goto mismatch;
1067 [ + + ]: 41528 : if (v->is_reference)
1068 : 332 : return json_variant_by_index(v->reference, idx);
1069 [ - + ]: 41196 : if (idx >= v->n_elements)
1070 : 0 : return NULL;
1071 : :
1072 : 41196 : return json_variant_conservative_normalize(v + 1 + idx);
1073 : :
1074 : 0 : mismatch:
1075 [ # # ]: 0 : log_debug("Element in non-array/non-object JSON variant requested by index, returning NULL.");
1076 : 0 : return NULL;
1077 : : }
1078 : :
1079 : 108 : JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVariant **ret_key) {
1080 : : size_t i;
1081 : :
1082 [ - + ]: 108 : if (!v)
1083 : 0 : goto not_found;
1084 [ - + ]: 108 : if (!key)
1085 : 0 : goto not_found;
1086 [ - + ]: 108 : if (v == JSON_VARIANT_MAGIC_EMPTY_OBJECT)
1087 : 0 : goto not_found;
1088 [ - + ]: 108 : if (!json_variant_is_regular(v))
1089 : 0 : goto mismatch;
1090 [ - + ]: 108 : if (v->type != JSON_VARIANT_OBJECT)
1091 : 0 : goto mismatch;
1092 [ + + ]: 108 : if (v->is_reference)
1093 : 36 : return json_variant_by_key(v->reference, key);
1094 : :
1095 [ + + ]: 104 : for (i = 0; i < v->n_elements; i += 2) {
1096 : : JsonVariant *p;
1097 : :
1098 : 100 : p = json_variant_dereference(v + 1 + i);
1099 : :
1100 [ - + ]: 100 : if (!json_variant_has_type(p, JSON_VARIANT_STRING))
1101 : 0 : continue;
1102 : :
1103 [ + + ]: 100 : if (streq(json_variant_string(p), key)) {
1104 : :
1105 [ - + ]: 68 : if (ret_key)
1106 : 0 : *ret_key = json_variant_conservative_normalize(v + 1 + i);
1107 : :
1108 : 68 : return json_variant_conservative_normalize(v + 1 + i + 1);
1109 : : }
1110 : : }
1111 : :
1112 : 4 : not_found:
1113 [ - + ]: 4 : if (ret_key)
1114 : 0 : *ret_key = NULL;
1115 : :
1116 : 4 : return NULL;
1117 : :
1118 : 0 : mismatch:
1119 [ # # ]: 0 : log_debug("Element in non-object JSON variant requested by key, returning NULL.");
1120 [ # # ]: 0 : if (ret_key)
1121 : 0 : *ret_key = NULL;
1122 : :
1123 : 0 : return NULL;
1124 : : }
1125 : :
1126 : 108 : JsonVariant *json_variant_by_key(JsonVariant *v, const char *key) {
1127 : 108 : return json_variant_by_key_full(v, key, NULL);
1128 : : }
1129 : :
1130 : 1172 : bool json_variant_equal(JsonVariant *a, JsonVariant *b) {
1131 : : JsonVariantType t;
1132 : :
1133 : 1172 : a = json_variant_normalize(a);
1134 : 1172 : b = json_variant_normalize(b);
1135 : :
1136 [ + + ]: 1172 : if (a == b)
1137 : 640 : return true;
1138 : :
1139 : 532 : t = json_variant_type(a);
1140 [ - + ]: 532 : if (!json_variant_has_type(b, t))
1141 : 0 : return false;
1142 : :
1143 [ + + + + : 532 : switch (t) {
- - + +
- ]
1144 : :
1145 : 184 : case JSON_VARIANT_STRING:
1146 : 184 : return streq(json_variant_string(a), json_variant_string(b));
1147 : :
1148 : 60 : case JSON_VARIANT_INTEGER:
1149 : 60 : return json_variant_integer(a) == json_variant_integer(b);
1150 : :
1151 : 88 : case JSON_VARIANT_UNSIGNED:
1152 : 88 : return json_variant_unsigned(a) == json_variant_unsigned(b);
1153 : :
1154 : 100 : case JSON_VARIANT_REAL:
1155 : : #pragma GCC diagnostic push
1156 : : #pragma GCC diagnostic ignored "-Wfloat-equal"
1157 : 100 : return json_variant_real(a) == json_variant_real(b);
1158 : : #pragma GCC diagnostic pop
1159 : :
1160 : 0 : case JSON_VARIANT_BOOLEAN:
1161 : 0 : return json_variant_boolean(a) == json_variant_boolean(b);
1162 : :
1163 : 0 : case JSON_VARIANT_NULL:
1164 : 0 : return true;
1165 : :
1166 : 44 : case JSON_VARIANT_ARRAY: {
1167 : : size_t i, n;
1168 : :
1169 : 44 : n = json_variant_elements(a);
1170 [ - + ]: 44 : if (n != json_variant_elements(b))
1171 : 0 : return false;
1172 : :
1173 [ + + ]: 276 : for (i = 0; i < n; i++) {
1174 [ - + ]: 232 : if (!json_variant_equal(json_variant_by_index(a, i), json_variant_by_index(b, i)))
1175 : 0 : return false;
1176 : : }
1177 : :
1178 : 44 : return true;
1179 : : }
1180 : :
1181 : 56 : case JSON_VARIANT_OBJECT: {
1182 : : size_t i, n;
1183 : :
1184 : 56 : n = json_variant_elements(a);
1185 [ - + ]: 56 : if (n != json_variant_elements(b))
1186 : 0 : return false;
1187 : :
1188 : : /* Iterate through all keys in 'a' */
1189 [ + + ]: 156 : for (i = 0; i < n; i += 2) {
1190 : 100 : bool found = false;
1191 : : size_t j;
1192 : :
1193 : : /* Match them against all keys in 'b' */
1194 [ + + ]: 252 : for (j = 0; j < n; j += 2) {
1195 : : JsonVariant *key_b;
1196 : :
1197 : 196 : key_b = json_variant_by_index(b, j);
1198 : :
1199 : : /* During the first iteration unmark everything */
1200 [ + + ]: 196 : if (i == 0)
1201 : 100 : key_b->is_marked = false;
1202 [ + + ]: 96 : else if (key_b->is_marked) /* In later iterations if we already marked something, don't bother with it again */
1203 : 52 : continue;
1204 : :
1205 [ + + ]: 144 : if (found)
1206 : 36 : continue;
1207 : :
1208 [ + + + - ]: 208 : if (json_variant_equal(json_variant_by_index(a, i), key_b) &&
1209 : 100 : json_variant_equal(json_variant_by_index(a, i+1), json_variant_by_index(b, j+1))) {
1210 : : /* Key and values match! */
1211 : 100 : key_b->is_marked = found = true;
1212 : :
1213 : : /* In the first iteration we continue the inner loop since we want to mark
1214 : : * everything, otherwise exit the loop quickly after we found what we were
1215 : : * looking for. */
1216 [ + + ]: 100 : if (i != 0)
1217 : 44 : break;
1218 : : }
1219 : : }
1220 : :
1221 [ - + ]: 100 : if (!found)
1222 : 0 : return false;
1223 : : }
1224 : :
1225 : 56 : return true;
1226 : : }
1227 : :
1228 : 0 : default:
1229 : 0 : assert_not_reached("Unknown variant type.");
1230 : : }
1231 : : }
1232 : :
1233 : 0 : int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column) {
1234 [ # # # # ]: 0 : assert_return(v, -EINVAL);
1235 : :
1236 [ # # ]: 0 : if (ret_source)
1237 [ # # # # ]: 0 : *ret_source = json_variant_is_regular(v) && v->source ? v->source->name : NULL;
1238 : :
1239 [ # # ]: 0 : if (ret_line)
1240 [ # # ]: 0 : *ret_line = json_variant_is_regular(v) ? v->line : 0;
1241 : :
1242 [ # # ]: 0 : if (ret_column)
1243 [ # # ]: 0 : *ret_column = json_variant_is_regular(v) ? v->column : 0;
1244 : :
1245 : 0 : return 0;
1246 : : }
1247 : :
1248 : 1836 : static int print_source(FILE *f, JsonVariant *v, JsonFormatFlags flags, bool whitespace) {
1249 : : size_t w, k;
1250 : :
1251 [ + + ]: 1836 : if (!FLAGS_SET(flags, JSON_FORMAT_SOURCE|JSON_FORMAT_PRETTY))
1252 : 1760 : return 0;
1253 : :
1254 [ - + ]: 76 : if (!json_variant_is_regular(v))
1255 : 0 : return 0;
1256 : :
1257 [ - + # # : 76 : if (!v->source && v->line == 0 && v->column == 0)
# # ]
1258 : 0 : return 0;
1259 : :
1260 : : /* The max width we need to format the line numbers for this source file */
1261 [ + - ]: 76 : w = (v->source && v->source->max_line > 0) ?
1262 [ + - + + ]: 228 : DECIMAL_STR_WIDTH(v->source->max_line) :
1263 : : DECIMAL_STR_MAX(unsigned)-1;
1264 [ + - ]: 76 : k = (v->source && v->source->max_column > 0) ?
1265 [ + - + + ]: 228 : DECIMAL_STR_WIDTH(v->source->max_column) :
1266 : : DECIMAL_STR_MAX(unsigned) -1;
1267 : :
1268 [ + + ]: 76 : if (whitespace) {
1269 : : size_t i, n;
1270 : :
1271 [ + - ]: 16 : n = 1 + (v->source ? strlen(v->source->name) : 0) +
1272 [ + - - + : 16 : ((v->source && (v->line > 0 || v->column > 0)) ? 1 : 0) +
# # ]
1273 [ + - ]: 16 : (v->line > 0 ? w : 0) +
1274 [ - + # # : 16 : (((v->source || v->line > 0) && v->column > 0) ? 1 : 0) +
+ - ]
1275 [ + - ]: 16 : (v->column > 0 ? k : 0) +
1276 : : 2;
1277 : :
1278 [ + + ]: 240 : for (i = 0; i < n; i++)
1279 : 224 : fputc(' ', f);
1280 : : } else {
1281 : 60 : fputc('[', f);
1282 : :
1283 [ + - ]: 60 : if (v->source)
1284 : 60 : fputs(v->source->name, f);
1285 [ + - - + : 60 : if (v->source && (v->line > 0 || v->column > 0))
# # ]
1286 : 60 : fputc(':', f);
1287 [ + - ]: 60 : if (v->line > 0)
1288 : 60 : fprintf(f, "%*u", (int) w, v->line);
1289 [ - + # # : 60 : if ((v->source || v->line > 0) || v->column > 0)
# # ]
1290 : 60 : fputc(':', f);
1291 [ + - ]: 60 : if (v->column > 0)
1292 : 60 : fprintf(f, "%*u", (int) k, v->column);
1293 : :
1294 : 60 : fputc(']', f);
1295 : 60 : fputc(' ', f);
1296 : : }
1297 : :
1298 : 76 : return 0;
1299 : : }
1300 : :
1301 : 37716 : static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const char *prefix) {
1302 : : int r;
1303 : :
1304 [ - + ]: 37716 : assert(f);
1305 [ - + ]: 37716 : assert(v);
1306 : :
1307 [ + + + + : 37716 : switch (json_variant_type(v)) {
+ + + +
- ]
1308 : :
1309 : 212 : case JSON_VARIANT_REAL: {
1310 : : locale_t loc;
1311 : :
1312 : 212 : loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
1313 [ - + ]: 212 : if (loc == (locale_t) 0)
1314 : 0 : return -errno;
1315 : :
1316 [ + + ]: 212 : if (flags & JSON_FORMAT_COLOR)
1317 : 100 : fputs(ANSI_HIGHLIGHT_BLUE, f);
1318 : :
1319 : 212 : fprintf(f, "%.*Le", DECIMAL_DIG, json_variant_real(v));
1320 : :
1321 [ + + ]: 212 : if (flags & JSON_FORMAT_COLOR)
1322 : 100 : fputs(ANSI_NORMAL, f);
1323 : :
1324 : 212 : freelocale(loc);
1325 : 212 : break;
1326 : : }
1327 : :
1328 : 1376 : case JSON_VARIANT_INTEGER:
1329 [ + + ]: 1376 : if (flags & JSON_FORMAT_COLOR)
1330 : 8 : fputs(ANSI_HIGHLIGHT_BLUE, f);
1331 : :
1332 : 1376 : fprintf(f, "%" PRIdMAX, json_variant_integer(v));
1333 : :
1334 [ + + ]: 1376 : if (flags & JSON_FORMAT_COLOR)
1335 : 8 : fputs(ANSI_NORMAL, f);
1336 : 1376 : break;
1337 : :
1338 : 144 : case JSON_VARIANT_UNSIGNED:
1339 [ + + ]: 144 : if (flags & JSON_FORMAT_COLOR)
1340 : 72 : fputs(ANSI_HIGHLIGHT_BLUE, f);
1341 : :
1342 : 144 : fprintf(f, "%" PRIuMAX, json_variant_unsigned(v));
1343 : :
1344 [ + + ]: 144 : if (flags & JSON_FORMAT_COLOR)
1345 : 72 : fputs(ANSI_NORMAL, f);
1346 : 144 : break;
1347 : :
1348 : 1356 : case JSON_VARIANT_BOOLEAN:
1349 : :
1350 [ + + ]: 1356 : if (flags & JSON_FORMAT_COLOR)
1351 : 8 : fputs(ANSI_HIGHLIGHT, f);
1352 : :
1353 [ + + ]: 1356 : if (json_variant_boolean(v))
1354 : 1348 : fputs("true", f);
1355 : : else
1356 : 8 : fputs("false", f);
1357 : :
1358 [ + + ]: 1356 : if (flags & JSON_FORMAT_COLOR)
1359 : 8 : fputs(ANSI_NORMAL, f);
1360 : :
1361 : 1356 : break;
1362 : :
1363 : 52 : case JSON_VARIANT_NULL:
1364 [ + + ]: 52 : if (flags & JSON_FORMAT_COLOR)
1365 : 16 : fputs(ANSI_HIGHLIGHT, f);
1366 : :
1367 : 52 : fputs("null", f);
1368 : :
1369 [ + + ]: 52 : if (flags & JSON_FORMAT_COLOR)
1370 : 16 : fputs(ANSI_NORMAL, f);
1371 : 52 : break;
1372 : :
1373 : 15260 : case JSON_VARIANT_STRING: {
1374 : : const char *q;
1375 : :
1376 : 15260 : fputc('"', f);
1377 : :
1378 [ + + ]: 15260 : if (flags & JSON_FORMAT_COLOR)
1379 : 120 : fputs(ANSI_GREEN, f);
1380 : :
1381 [ + + ]: 95020 : for (q = json_variant_string(v); *q; q++) {
1382 : :
1383 [ + - - - : 79760 : switch (*q) {
- - - + ]
1384 : :
1385 : 96 : case '"':
1386 : 96 : fputs("\\\"", f);
1387 : 96 : break;
1388 : :
1389 : 0 : case '\\':
1390 : 0 : fputs("\\\\", f);
1391 : 0 : break;
1392 : :
1393 : 0 : case '\b':
1394 : 0 : fputs("\\b", f);
1395 : 0 : break;
1396 : :
1397 : 0 : case '\f':
1398 : 0 : fputs("\\f", f);
1399 : 0 : break;
1400 : :
1401 : 0 : case '\n':
1402 : 0 : fputs("\\n", f);
1403 : 0 : break;
1404 : :
1405 : 0 : case '\r':
1406 : 0 : fputs("\\r", f);
1407 : 0 : break;
1408 : :
1409 : 0 : case '\t':
1410 : 0 : fputs("\\t", f);
1411 : 0 : break;
1412 : :
1413 : 79664 : default:
1414 [ + + - + ]: 79664 : if ((signed char) *q >= 0 && *q < ' ')
1415 : 0 : fprintf(f, "\\u%04x", *q);
1416 : : else
1417 : 79664 : fputc(*q, f);
1418 : 79664 : break;
1419 : : }
1420 : : }
1421 : :
1422 [ + + ]: 15260 : if (flags & JSON_FORMAT_COLOR)
1423 : 120 : fputs(ANSI_NORMAL, f);
1424 : :
1425 : 15260 : fputc('"', f);
1426 : 15260 : break;
1427 : : }
1428 : :
1429 : 8284 : case JSON_VARIANT_ARRAY: {
1430 : : size_t i, n;
1431 : :
1432 : 8284 : n = json_variant_elements(v);
1433 : :
1434 [ - + ]: 8284 : if (n == 0)
1435 : 0 : fputs("[]", f);
1436 : : else {
1437 [ + - ]: 8284 : _cleanup_free_ char *joined = NULL;
1438 : : const char *prefix2;
1439 : :
1440 [ + + ]: 8284 : if (flags & JSON_FORMAT_PRETTY) {
1441 : 40 : joined = strjoin(strempty(prefix), "\t");
1442 [ - + ]: 40 : if (!joined)
1443 : 0 : return -ENOMEM;
1444 : :
1445 : 40 : prefix2 = joined;
1446 : 40 : fputs("[\n", f);
1447 : : } else {
1448 : 8244 : prefix2 = strempty(prefix);
1449 : 8244 : fputc('[', f);
1450 : : }
1451 : :
1452 [ + + ]: 16956 : for (i = 0; i < n; i++) {
1453 : : JsonVariant *e;
1454 : :
1455 [ - + ]: 8672 : assert_se(e = json_variant_by_index(v, i));
1456 : :
1457 [ + + ]: 8672 : if (i > 0) {
1458 [ + + ]: 388 : if (flags & JSON_FORMAT_PRETTY)
1459 : 172 : fputs(",\n", f);
1460 : : else
1461 : 216 : fputc(',', f);
1462 : : }
1463 : :
1464 [ + + ]: 8672 : if (flags & JSON_FORMAT_PRETTY) {
1465 : 212 : print_source(f, e, flags, false);
1466 : 212 : fputs(prefix2, f);
1467 : : }
1468 : :
1469 : 8672 : r = json_format(f, e, flags, prefix2);
1470 [ - + ]: 8672 : if (r < 0)
1471 : 0 : return r;
1472 : : }
1473 : :
1474 [ + + ]: 8284 : if (flags & JSON_FORMAT_PRETTY) {
1475 : 40 : fputc('\n', f);
1476 : 40 : print_source(f, v, flags, true);
1477 : 40 : fputs(strempty(prefix), f);
1478 : : }
1479 : :
1480 : 8284 : fputc(']', f);
1481 : : }
1482 : 8284 : break;
1483 : : }
1484 : :
1485 : 11032 : case JSON_VARIANT_OBJECT: {
1486 : : size_t i, n;
1487 : :
1488 : 11032 : n = json_variant_elements(v);
1489 : :
1490 [ + + ]: 11032 : if (n == 0)
1491 : 12 : fputs("{}", f);
1492 : : else {
1493 [ + - ]: 11020 : _cleanup_free_ char *joined = NULL;
1494 : : const char *prefix2;
1495 : :
1496 [ + + ]: 11020 : if (flags & JSON_FORMAT_PRETTY) {
1497 : 48 : joined = strjoin(strempty(prefix), "\t");
1498 [ - + ]: 48 : if (!joined)
1499 : 0 : return -ENOMEM;
1500 : :
1501 : 48 : prefix2 = joined;
1502 : 48 : fputs("{\n", f);
1503 : : } else {
1504 : 10972 : prefix2 = strempty(prefix);
1505 : 10972 : fputc('{', f);
1506 : : }
1507 : :
1508 [ + + ]: 24816 : for (i = 0; i < n; i += 2) {
1509 : : JsonVariant *e;
1510 : :
1511 : 13796 : e = json_variant_by_index(v, i);
1512 : :
1513 [ + + ]: 13796 : if (i > 0) {
1514 [ + + ]: 2776 : if (flags & JSON_FORMAT_PRETTY)
1515 : 36 : fputs(",\n", f);
1516 : : else
1517 : 2740 : fputc(',', f);
1518 : : }
1519 : :
1520 [ + + ]: 13796 : if (flags & JSON_FORMAT_PRETTY) {
1521 : 84 : print_source(f, e, flags, false);
1522 : 84 : fputs(prefix2, f);
1523 : : }
1524 : :
1525 : 13796 : r = json_format(f, e, flags, prefix2);
1526 [ - + ]: 13796 : if (r < 0)
1527 : 0 : return r;
1528 : :
1529 [ + + ]: 13796 : fputs(flags & JSON_FORMAT_PRETTY ? " : " : ":", f);
1530 : :
1531 : 13796 : r = json_format(f, json_variant_by_index(v, i+1), flags, prefix2);
1532 [ - + ]: 13796 : if (r < 0)
1533 : 0 : return r;
1534 : : }
1535 : :
1536 [ + + ]: 11020 : if (flags & JSON_FORMAT_PRETTY) {
1537 : 48 : fputc('\n', f);
1538 : 48 : print_source(f, v, flags, true);
1539 : 48 : fputs(strempty(prefix), f);
1540 : : }
1541 : :
1542 : 11020 : fputc('}', f);
1543 : : }
1544 : 11032 : break;
1545 : : }
1546 : :
1547 : 0 : default:
1548 : 0 : assert_not_reached("Unexpected variant type.");
1549 : : }
1550 : :
1551 : 37716 : return 0;
1552 : : }
1553 : :
1554 : 1440 : int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
1555 : 1440 : _cleanup_free_ char *s = NULL;
1556 : 1440 : size_t sz = 0;
1557 : : int r;
1558 : :
1559 : : /* Returns the length of the generated string (without the terminating NUL),
1560 : : * or negative on error. */
1561 : :
1562 [ - + - + ]: 1440 : assert_return(v, -EINVAL);
1563 [ - + - + ]: 1440 : assert_return(ret, -EINVAL);
1564 : :
1565 : : {
1566 [ + - ]: 1440 : _cleanup_fclose_ FILE *f = NULL;
1567 : :
1568 : 1440 : f = open_memstream_unlocked(&s, &sz);
1569 [ - + ]: 1440 : if (!f)
1570 : 0 : return -ENOMEM;
1571 : :
1572 : 1440 : json_variant_dump(v, flags, f, NULL);
1573 : :
1574 : : /* Add terminating 0, so that the output buffer is a valid string. */
1575 : 1440 : fputc('\0', f);
1576 : :
1577 : 1440 : r = fflush_and_check(f);
1578 : : }
1579 [ - + ]: 1440 : if (r < 0)
1580 : 0 : return r;
1581 : :
1582 [ - + ]: 1440 : assert(s);
1583 : 1440 : *ret = TAKE_PTR(s);
1584 [ - + ]: 1440 : assert(sz > 0);
1585 : 1440 : return (int) sz - 1;
1586 : : }
1587 : :
1588 : 1452 : void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
1589 [ - + ]: 1452 : if (!v)
1590 : 0 : return;
1591 : :
1592 [ - + ]: 1452 : if (!f)
1593 : 0 : f = stdout;
1594 : :
1595 : 1452 : print_source(f, v, flags, false);
1596 : :
1597 [ - + # # ]: 1452 : if (((flags & (JSON_FORMAT_COLOR_AUTO|JSON_FORMAT_COLOR)) == JSON_FORMAT_COLOR_AUTO) && colors_enabled())
1598 : 0 : flags |= JSON_FORMAT_COLOR;
1599 : :
1600 [ - + ]: 1452 : if (flags & JSON_FORMAT_SSE)
1601 : 0 : fputs("data: ", f);
1602 [ - + ]: 1452 : if (flags & JSON_FORMAT_SEQ)
1603 : 0 : fputc('\x1e', f); /* ASCII Record Separator */
1604 : :
1605 : 1452 : json_format(f, v, flags, prefix);
1606 : :
1607 [ + + ]: 1452 : if (flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_SEQ|JSON_FORMAT_SSE|JSON_FORMAT_NEWLINE))
1608 : 36 : fputc('\n', f);
1609 [ - + ]: 1452 : if (flags & JSON_FORMAT_SSE)
1610 : 0 : fputc('\n', f); /* In case of SSE add a second newline */
1611 : : }
1612 : :
1613 : 744 : static int json_variant_copy(JsonVariant **nv, JsonVariant *v) {
1614 : : JsonVariantType t;
1615 : : JsonVariant *c;
1616 : : JsonValue value;
1617 : : const void *source;
1618 : : size_t k;
1619 : :
1620 [ - + ]: 744 : assert(nv);
1621 [ - + ]: 744 : assert(v);
1622 : :
1623 : : /* Let's copy the simple types literally, and the larger types by references */
1624 : 744 : t = json_variant_type(v);
1625 [ + + + + : 744 : switch (t) {
+ - + ]
1626 : 12 : case JSON_VARIANT_INTEGER:
1627 : 12 : k = sizeof(intmax_t);
1628 : 12 : value.integer = json_variant_integer(v);
1629 : 12 : source = &value;
1630 : 12 : break;
1631 : :
1632 : 16 : case JSON_VARIANT_UNSIGNED:
1633 : 16 : k = sizeof(uintmax_t);
1634 : 16 : value.unsig = json_variant_unsigned(v);
1635 : 16 : source = &value;
1636 : 16 : break;
1637 : :
1638 : 132 : case JSON_VARIANT_REAL:
1639 : 132 : k = sizeof(long double);
1640 : 132 : value.real = json_variant_real(v);
1641 : 132 : source = &value;
1642 : 132 : break;
1643 : :
1644 : 532 : case JSON_VARIANT_BOOLEAN:
1645 : 532 : k = sizeof(bool);
1646 : 532 : value.boolean = json_variant_boolean(v);
1647 : 532 : source = &value;
1648 : 532 : break;
1649 : :
1650 : 44 : case JSON_VARIANT_NULL:
1651 : 44 : k = 0;
1652 : 44 : source = NULL;
1653 : 44 : break;
1654 : :
1655 : 0 : case JSON_VARIANT_STRING:
1656 : 0 : source = json_variant_string(v);
1657 : 0 : k = strnlen(source, INLINE_STRING_MAX + 1);
1658 [ # # ]: 0 : if (k <= INLINE_STRING_MAX) {
1659 : 0 : k ++;
1660 : 0 : break;
1661 : : }
1662 : :
1663 : : _fallthrough_;
1664 : :
1665 : : default:
1666 : : /* Everything else copy by reference */
1667 : :
1668 : 8 : c = malloc0(MAX(sizeof(JsonVariant),
1669 : : offsetof(JsonVariant, reference) + sizeof(JsonVariant*)));
1670 [ - + ]: 8 : if (!c)
1671 : 0 : return -ENOMEM;
1672 : :
1673 : 8 : c->n_ref = 1;
1674 : 8 : c->type = t;
1675 : 8 : c->is_reference = true;
1676 : 8 : c->reference = json_variant_ref(json_variant_normalize(v));
1677 : :
1678 : 8 : *nv = c;
1679 : 8 : return 0;
1680 : : }
1681 : :
1682 : 736 : c = malloc0(MAX(sizeof(JsonVariant),
1683 : : offsetof(JsonVariant, value) + k));
1684 [ - + ]: 736 : if (!c)
1685 : 0 : return -ENOMEM;
1686 : :
1687 : 736 : c->n_ref = 1;
1688 : 736 : c->type = t;
1689 : :
1690 : 736 : memcpy_safe(&c->value, source, k);
1691 : :
1692 : 736 : *nv = c;
1693 : 736 : return 0;
1694 : : }
1695 : :
1696 : 4772 : static bool json_single_ref(JsonVariant *v) {
1697 : :
1698 : : /* Checks whether the caller is the single owner of the object, i.e. can get away with changing it */
1699 : :
1700 [ - + ]: 4772 : if (!json_variant_is_regular(v))
1701 : 0 : return false;
1702 : :
1703 [ - + ]: 4772 : if (v->is_embedded)
1704 : 0 : return json_single_ref(v->parent);
1705 : :
1706 [ - + ]: 4772 : assert(v->n_ref > 0);
1707 : 4772 : return v->n_ref == 1;
1708 : : }
1709 : :
1710 : 5516 : static int json_variant_set_source(JsonVariant **v, JsonSource *source, unsigned line, unsigned column) {
1711 : : JsonVariant *w;
1712 : : int r;
1713 : :
1714 [ - + ]: 5516 : assert(v);
1715 : :
1716 : : /* Patch in source and line/column number. Tries to do this in-place if the caller is the sole referencer of
1717 : : * the object. If not, allocates a new object, possibly a surrogate for the original one */
1718 : :
1719 [ - + ]: 5516 : if (!*v)
1720 : 0 : return 0;
1721 : :
1722 [ + + + + ]: 5516 : if (source && line > source->max_line)
1723 : 32 : source->max_line = line;
1724 [ + + + + ]: 5516 : if (source && column > source->max_column)
1725 : 24 : source->max_column = column;
1726 : :
1727 [ + + ]: 5516 : if (!json_variant_is_regular(*v)) {
1728 : :
1729 [ + + - + : 744 : if (!source && line == 0 && column == 0)
# # ]
1730 : 0 : return 0;
1731 : :
1732 : : } else {
1733 [ + + ]: 4772 : if (json_source_equal((*v)->source, source) &&
1734 [ - + ]: 4704 : (*v)->line == line &&
1735 [ # # ]: 0 : (*v)->column == column)
1736 : 0 : return 0;
1737 : :
1738 [ + - ]: 4772 : if (json_single_ref(*v)) { /* Sole reference? */
1739 : 4772 : json_source_unref((*v)->source);
1740 : 4772 : (*v)->source = json_source_ref(source);
1741 : 4772 : (*v)->line = line;
1742 : 4772 : (*v)->column = column;
1743 : 4772 : return 1;
1744 : : }
1745 : : }
1746 : :
1747 : 744 : r = json_variant_copy(&w, *v);
1748 [ - + ]: 744 : if (r < 0)
1749 : 0 : return r;
1750 : :
1751 [ - + ]: 744 : assert(json_variant_is_regular(w));
1752 [ - + ]: 744 : assert(!w->is_embedded);
1753 [ - + ]: 744 : assert(w->n_ref == 1);
1754 [ - + ]: 744 : assert(!w->source);
1755 : :
1756 : 744 : w->source = json_source_ref(source);
1757 : 744 : w->line = line;
1758 : 744 : w->column = column;
1759 : :
1760 : 744 : json_variant_unref(*v);
1761 : 744 : *v = w;
1762 : :
1763 : 744 : return 1;
1764 : : }
1765 : :
1766 : 22752 : static void inc_lines_columns(unsigned *line, unsigned *column, const char *s, size_t n) {
1767 [ - + ]: 22752 : assert(line);
1768 [ - + ]: 22752 : assert(column);
1769 [ - + # # ]: 22752 : assert(s || n == 0);
1770 : :
1771 [ + + ]: 64616 : while (n > 0) {
1772 [ + + ]: 41864 : if (*s == '\n') {
1773 : 72 : (*line)++;
1774 : 72 : *column = 1;
1775 [ + + + - ]: 41792 : } else if ((signed char) *s >= 0 && *s < 127) /* Process ASCII chars quickly */
1776 : 41780 : (*column)++;
1777 : : else {
1778 : : int w;
1779 : :
1780 : 12 : w = utf8_encoded_valid_unichar(s, n);
1781 [ - + ]: 12 : if (w < 0) /* count invalid unichars as normal characters */
1782 : 0 : w = 1;
1783 [ - + ]: 12 : else if ((size_t) w > n) /* never read more than the specified number of characters */
1784 : 0 : w = (int) n;
1785 : :
1786 : 12 : (*column)++;
1787 : :
1788 : 12 : s += w;
1789 : 12 : n -= w;
1790 : 12 : continue;
1791 : : }
1792 : :
1793 : 41852 : s++;
1794 : 41852 : n--;
1795 : : }
1796 : 22752 : }
1797 : :
1798 : 336 : static int unhex_ucs2(const char *c, uint16_t *ret) {
1799 : : int aa, bb, cc, dd;
1800 : : uint16_t x;
1801 : :
1802 [ - + ]: 336 : assert(c);
1803 [ - + ]: 336 : assert(ret);
1804 : :
1805 : 336 : aa = unhexchar(c[0]);
1806 [ - + ]: 336 : if (aa < 0)
1807 : 0 : return -EINVAL;
1808 : :
1809 : 336 : bb = unhexchar(c[1]);
1810 [ + + ]: 336 : if (bb < 0)
1811 : 4 : return -EINVAL;
1812 : :
1813 : 332 : cc = unhexchar(c[2]);
1814 [ - + ]: 332 : if (cc < 0)
1815 : 0 : return -EINVAL;
1816 : :
1817 : 332 : dd = unhexchar(c[3]);
1818 [ - + ]: 332 : if (dd < 0)
1819 : 0 : return -EINVAL;
1820 : :
1821 : 996 : x = ((uint16_t) aa << 12) |
1822 : 664 : ((uint16_t) bb << 8) |
1823 : 664 : ((uint16_t) cc << 4) |
1824 : 332 : ((uint16_t) dd);
1825 : :
1826 [ - + ]: 332 : if (x <= 0)
1827 : 0 : return -EINVAL;
1828 : :
1829 : 332 : *ret = x;
1830 : :
1831 : 332 : return 0;
1832 : : }
1833 : :
1834 : 2944 : static int json_parse_string(const char **p, char **ret) {
1835 : 2944 : _cleanup_free_ char *s = NULL;
1836 : 2944 : size_t n = 0, allocated = 0;
1837 : : const char *c;
1838 : :
1839 [ - + ]: 2944 : assert(p);
1840 [ - + ]: 2944 : assert(*p);
1841 [ - + ]: 2944 : assert(ret);
1842 : :
1843 : 2944 : c = *p;
1844 : :
1845 [ - + ]: 2944 : if (*c != '"')
1846 : 0 : return -EINVAL;
1847 : :
1848 : 2944 : c++;
1849 : :
1850 : 22272 : for (;;) {
1851 : : int len;
1852 : :
1853 : : /* Check for EOF */
1854 [ - + ]: 25216 : if (*c == 0)
1855 : 0 : return -EINVAL;
1856 : :
1857 : : /* Check for control characters 0x00..0x1f */
1858 [ + + - + ]: 25216 : if (*c > 0 && *c < ' ')
1859 : 0 : return -EINVAL;
1860 : :
1861 : : /* Check for control character 0x7f */
1862 [ - + ]: 25216 : if (*c == 0x7f)
1863 : 0 : return -EINVAL;
1864 : :
1865 [ + + ]: 25216 : if (*c == '"') {
1866 [ + + ]: 2932 : if (!s) {
1867 : 4 : s = strdup("");
1868 [ - + ]: 4 : if (!s)
1869 : 0 : return -ENOMEM;
1870 : : } else
1871 : 2928 : s[n] = 0;
1872 : :
1873 : 2932 : *p = c + 1;
1874 : :
1875 : 2932 : *ret = TAKE_PTR(s);
1876 : 2932 : return JSON_TOKEN_STRING;
1877 : : }
1878 : :
1879 [ + + ]: 22284 : if (*c == '\\') {
1880 : 252 : char ch = 0;
1881 : 252 : c++;
1882 : :
1883 [ - + ]: 252 : if (*c == 0)
1884 : 0 : return -EINVAL;
1885 : :
1886 [ + + + + ]: 252 : if (IN_SET(*c, '"', '\\', '/'))
1887 : 72 : ch = *c;
1888 [ - + ]: 180 : else if (*c == 'b')
1889 : 0 : ch = '\b';
1890 [ - + ]: 180 : else if (*c == 'f')
1891 : 0 : ch = '\f';
1892 [ + + ]: 180 : else if (*c == 'n')
1893 : 4 : ch = '\n';
1894 [ - + ]: 176 : else if (*c == 'r')
1895 : 0 : ch = '\r';
1896 [ - + ]: 176 : else if (*c == 't')
1897 : 0 : ch = '\t';
1898 [ + - ]: 176 : else if (*c == 'u') {
1899 : : char16_t x;
1900 : : int r;
1901 : :
1902 : 176 : r = unhex_ucs2(c + 1, &x);
1903 [ + + ]: 176 : if (r < 0)
1904 : 12 : return r;
1905 : :
1906 : 172 : c += 5;
1907 : :
1908 [ - + ]: 172 : if (!GREEDY_REALLOC(s, allocated, n + 5))
1909 : 0 : return -ENOMEM;
1910 : :
1911 [ + + ]: 172 : if (!utf16_is_surrogate(x))
1912 : 4 : n += utf8_encode_unichar(s + n, (char32_t) x);
1913 [ + + ]: 168 : else if (utf16_is_trailing_surrogate(x))
1914 : 4 : return -EINVAL;
1915 : : else {
1916 : : char16_t y;
1917 : :
1918 [ + + - + ]: 164 : if (c[0] != '\\' || c[1] != 'u')
1919 : 4 : return -EINVAL;
1920 : :
1921 : 160 : r = unhex_ucs2(c + 2, &y);
1922 [ - + ]: 160 : if (r < 0)
1923 : 0 : return r;
1924 : :
1925 : 160 : c += 6;
1926 : :
1927 [ - + ]: 160 : if (!utf16_is_trailing_surrogate(y))
1928 : 0 : return -EINVAL;
1929 : :
1930 : 160 : n += utf8_encode_unichar(s + n, utf16_surrogate_pair_to_unichar(x, y));
1931 : : }
1932 : :
1933 : 164 : continue;
1934 : : } else
1935 : 0 : return -EINVAL;
1936 : :
1937 [ - + ]: 76 : if (!GREEDY_REALLOC(s, allocated, n + 2))
1938 : 0 : return -ENOMEM;
1939 : :
1940 : 76 : s[n++] = ch;
1941 : 76 : c ++;
1942 : 76 : continue;
1943 : : }
1944 : :
1945 : 22032 : len = utf8_encoded_valid_unichar(c, (size_t) -1);
1946 [ - + ]: 22032 : if (len < 0)
1947 : 0 : return len;
1948 : :
1949 [ - + ]: 22032 : if (!GREEDY_REALLOC(s, allocated, n + len + 1))
1950 : 0 : return -ENOMEM;
1951 : :
1952 : 22032 : memcpy(s + n, c, len);
1953 : 22032 : n += len;
1954 : 22032 : c += len;
1955 : : }
1956 : : }
1957 : :
1958 : 872 : static int json_parse_number(const char **p, JsonValue *ret) {
1959 : 872 : bool negative = false, exponent_negative = false, is_real = false;
1960 : 872 : long double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0;
1961 : 872 : intmax_t i = 0;
1962 : 872 : uintmax_t u = 0;
1963 : : const char *c;
1964 : :
1965 [ - + ]: 872 : assert(p);
1966 [ - + ]: 872 : assert(*p);
1967 [ - + ]: 872 : assert(ret);
1968 : :
1969 : 872 : c = *p;
1970 : :
1971 [ + + ]: 872 : if (*c == '-') {
1972 : 100 : negative = true;
1973 : 100 : c++;
1974 : : }
1975 : :
1976 [ + + ]: 872 : if (*c == '0')
1977 : 172 : c++;
1978 : : else {
1979 [ + - - + ]: 700 : if (!strchr("123456789", *c) || *c == 0)
1980 : 0 : return -EINVAL;
1981 : :
1982 : : do {
1983 [ + - ]: 1652 : if (!is_real) {
1984 [ + + ]: 1652 : if (negative) {
1985 : :
1986 [ - + ]: 192 : if (i < INTMAX_MIN / 10) /* overflow */
1987 : 0 : is_real = true;
1988 : : else {
1989 : 192 : intmax_t t = 10 * i;
1990 : :
1991 [ + + ]: 192 : if (t < INTMAX_MIN + (*c - '0')) /* overflow */
1992 : 4 : is_real = true;
1993 : : else
1994 : 188 : i = t - (*c - '0');
1995 : : }
1996 : : } else {
1997 [ - + ]: 1460 : if (u > UINTMAX_MAX / 10) /* overflow */
1998 : 0 : is_real = true;
1999 : : else {
2000 : 1460 : uintmax_t t = 10 * u;
2001 : :
2002 [ + + ]: 1460 : if (t > UINTMAX_MAX - (*c - '0')) /* overflow */
2003 : 4 : is_real = true;
2004 : : else
2005 : 1456 : u = t + (*c - '0');
2006 : : }
2007 : : }
2008 : : }
2009 : :
2010 : 1652 : x = 10.0 * x + (*c - '0');
2011 : :
2012 : 1652 : c++;
2013 [ + + + + ]: 1652 : } while (strchr("0123456789", *c) && *c != 0);
2014 : : }
2015 : :
2016 [ + + ]: 872 : if (*c == '.') {
2017 : 80 : is_real = true;
2018 : 80 : c++;
2019 : :
2020 [ + - - + ]: 80 : if (!strchr("0123456789", *c) || *c == 0)
2021 : 0 : return -EINVAL;
2022 : :
2023 : : do {
2024 : 308 : y = 10.0 * y + (*c - '0');
2025 : 308 : shift = 10.0 * shift;
2026 : 308 : c++;
2027 [ + + + + ]: 308 : } while (strchr("0123456789", *c) && *c != 0);
2028 : : }
2029 : :
2030 [ + + + + ]: 872 : if (IN_SET(*c, 'e', 'E')) {
2031 : 100 : is_real = true;
2032 : 100 : c++;
2033 : :
2034 [ + + ]: 100 : if (*c == '-') {
2035 : 28 : exponent_negative = true;
2036 : 28 : c++;
2037 [ + + ]: 72 : } else if (*c == '+')
2038 : 32 : c++;
2039 : :
2040 [ + - - + ]: 100 : if (!strchr("0123456789", *c) || *c == 0)
2041 : 0 : return -EINVAL;
2042 : :
2043 : : do {
2044 : 156 : exponent = 10.0 * exponent + (*c - '0');
2045 : 156 : c++;
2046 [ + + + + ]: 156 : } while (strchr("0123456789", *c) && *c != 0);
2047 : : }
2048 : :
2049 : 872 : *p = c;
2050 : :
2051 [ + + ]: 872 : if (is_real) {
2052 [ + + + + ]: 180 : ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10l((exponent_negative ? -1.0 : 1.0) * exponent);
2053 : 180 : return JSON_TOKEN_REAL;
2054 [ + + ]: 692 : } else if (negative) {
2055 : 32 : ret->integer = i;
2056 : 32 : return JSON_TOKEN_INTEGER;
2057 : : } else {
2058 : 660 : ret->unsig = u;
2059 : 660 : return JSON_TOKEN_UNSIGNED;
2060 : : }
2061 : : }
2062 : :
2063 : 11384 : int json_tokenize(
2064 : : const char **p,
2065 : : char **ret_string,
2066 : : JsonValue *ret_value,
2067 : : unsigned *ret_line, /* 'ret_line' returns the line at the beginning of this token */
2068 : : unsigned *ret_column,
2069 : : void **state,
2070 : : unsigned *line, /* 'line' is used as a line state, it always reflect the line we are at after the token was read */
2071 : : unsigned *column) {
2072 : :
2073 : : unsigned start_line, start_column;
2074 : : const char *start, *c;
2075 : : size_t n;
2076 : : int t, r;
2077 : :
2078 : : enum {
2079 : : STATE_NULL,
2080 : : STATE_VALUE,
2081 : : STATE_VALUE_POST,
2082 : : };
2083 : :
2084 [ - + ]: 11384 : assert(p);
2085 [ - + ]: 11384 : assert(*p);
2086 [ - + ]: 11384 : assert(ret_string);
2087 [ - + ]: 11384 : assert(ret_value);
2088 [ - + ]: 11384 : assert(ret_line);
2089 [ - + ]: 11384 : assert(ret_column);
2090 [ - + ]: 11384 : assert(line);
2091 [ - + ]: 11384 : assert(column);
2092 [ - + ]: 11384 : assert(state);
2093 : :
2094 : 11384 : t = PTR_TO_INT(*state);
2095 [ + + ]: 11384 : if (t == STATE_NULL) {
2096 : 748 : *line = 1;
2097 : 748 : *column = 1;
2098 : 748 : t = STATE_VALUE;
2099 : : }
2100 : :
2101 : : /* Skip over the whitespace */
2102 : 11384 : n = strspn(*p, WHITESPACE);
2103 : 11384 : inc_lines_columns(line, column, *p, n);
2104 : 11384 : c = *p + n;
2105 : :
2106 : : /* Remember where we started processing this token */
2107 : 11384 : start = c;
2108 : 11384 : start_line = *line;
2109 : 11384 : start_column = *column;
2110 : :
2111 [ + + ]: 11384 : if (*c == 0) {
2112 : 732 : *ret_string = NULL;
2113 : 732 : *ret_value = JSON_VALUE_NULL;
2114 : 732 : r = JSON_TOKEN_END;
2115 : 732 : goto finish;
2116 : : }
2117 : :
2118 [ + + - ]: 10652 : switch (t) {
2119 : :
2120 : 5708 : case STATE_VALUE:
2121 : :
2122 [ + + ]: 5708 : if (*c == '{') {
2123 : 1184 : c++;
2124 : 1184 : *state = INT_TO_PTR(STATE_VALUE);
2125 : 1184 : r = JSON_TOKEN_OBJECT_OPEN;
2126 : 1184 : goto null_return;
2127 : :
2128 [ + + ]: 4524 : } else if (*c == '}') {
2129 : 16 : c++;
2130 : 16 : *state = INT_TO_PTR(STATE_VALUE_POST);
2131 : 16 : r = JSON_TOKEN_OBJECT_CLOSE;
2132 : 16 : goto null_return;
2133 : :
2134 [ + + ]: 4508 : } else if (*c == '[') {
2135 : 84 : c++;
2136 : 84 : *state = INT_TO_PTR(STATE_VALUE);
2137 : 84 : r = JSON_TOKEN_ARRAY_OPEN;
2138 : 84 : goto null_return;
2139 : :
2140 [ + + ]: 4424 : } else if (*c == ']') {
2141 : 8 : c++;
2142 : 8 : *state = INT_TO_PTR(STATE_VALUE_POST);
2143 : 8 : r = JSON_TOKEN_ARRAY_CLOSE;
2144 : 8 : goto null_return;
2145 : :
2146 [ + + ]: 4416 : } else if (*c == '"') {
2147 : :
2148 : 2944 : r = json_parse_string(&c, ret_string);
2149 [ + + ]: 2944 : if (r < 0)
2150 : 12 : return r;
2151 : :
2152 : 2932 : *ret_value = JSON_VALUE_NULL;
2153 : 2932 : *state = INT_TO_PTR(STATE_VALUE_POST);
2154 : 2932 : goto finish;
2155 : :
2156 [ + + ]: 1472 : } else if (strchr("-0123456789", *c)) {
2157 : :
2158 : 872 : r = json_parse_number(&c, ret_value);
2159 [ - + ]: 872 : if (r < 0)
2160 : 0 : return r;
2161 : :
2162 : 872 : *ret_string = NULL;
2163 : 872 : *state = INT_TO_PTR(STATE_VALUE_POST);
2164 : 872 : goto finish;
2165 : :
2166 [ + + ]: 600 : } else if (startswith(c, "true")) {
2167 : 536 : *ret_string = NULL;
2168 : 536 : ret_value->boolean = true;
2169 : 536 : c += 4;
2170 : 536 : *state = INT_TO_PTR(STATE_VALUE_POST);
2171 : 536 : r = JSON_TOKEN_BOOLEAN;
2172 : 536 : goto finish;
2173 : :
2174 [ + + ]: 64 : } else if (startswith(c, "false")) {
2175 : 12 : *ret_string = NULL;
2176 : 12 : ret_value->boolean = false;
2177 : 12 : c += 5;
2178 : 12 : *state = INT_TO_PTR(STATE_VALUE_POST);
2179 : 12 : r = JSON_TOKEN_BOOLEAN;
2180 : 12 : goto finish;
2181 : :
2182 [ + + ]: 52 : } else if (startswith(c, "null")) {
2183 : 48 : *ret_string = NULL;
2184 : 48 : *ret_value = JSON_VALUE_NULL;
2185 : 48 : c += 4;
2186 : 48 : *state = INT_TO_PTR(STATE_VALUE_POST);
2187 : 48 : r = JSON_TOKEN_NULL;
2188 : 48 : goto finish;
2189 : :
2190 : : }
2191 : :
2192 : 4 : return -EINVAL;
2193 : :
2194 : 4944 : case STATE_VALUE_POST:
2195 : :
2196 [ + + ]: 4944 : if (*c == ':') {
2197 : 2284 : c++;
2198 : 2284 : *state = INT_TO_PTR(STATE_VALUE);
2199 : 2284 : r = JSON_TOKEN_COLON;
2200 : 2284 : goto null_return;
2201 : :
2202 [ + + ]: 2660 : } else if (*c == ',') {
2203 : 1416 : c++;
2204 : 1416 : *state = INT_TO_PTR(STATE_VALUE);
2205 : 1416 : r = JSON_TOKEN_COMMA;
2206 : 1416 : goto null_return;
2207 : :
2208 [ + + ]: 1244 : } else if (*c == '}') {
2209 : 1168 : c++;
2210 : 1168 : *state = INT_TO_PTR(STATE_VALUE_POST);
2211 : 1168 : r = JSON_TOKEN_OBJECT_CLOSE;
2212 : 1168 : goto null_return;
2213 : :
2214 [ + - ]: 76 : } else if (*c == ']') {
2215 : 76 : c++;
2216 : 76 : *state = INT_TO_PTR(STATE_VALUE_POST);
2217 : 76 : r = JSON_TOKEN_ARRAY_CLOSE;
2218 : 76 : goto null_return;
2219 : : }
2220 : :
2221 : 0 : return -EINVAL;
2222 : :
2223 : 0 : default:
2224 : 0 : assert_not_reached("Unexpected tokenizer state");
2225 : : }
2226 : :
2227 : 6236 : null_return:
2228 : 6236 : *ret_string = NULL;
2229 : 6236 : *ret_value = JSON_VALUE_NULL;
2230 : :
2231 : 11368 : finish:
2232 : 11368 : inc_lines_columns(line, column, start, c - start);
2233 : 11368 : *p = c;
2234 : :
2235 : 11368 : *ret_line = start_line;
2236 : 11368 : *ret_column = start_column;
2237 : :
2238 : 11368 : return r;
2239 : : }
2240 : :
2241 : : typedef enum JsonExpect {
2242 : : /* The following values are used by json_parse() */
2243 : : EXPECT_TOPLEVEL,
2244 : : EXPECT_END,
2245 : : EXPECT_OBJECT_FIRST_KEY,
2246 : : EXPECT_OBJECT_NEXT_KEY,
2247 : : EXPECT_OBJECT_COLON,
2248 : : EXPECT_OBJECT_VALUE,
2249 : : EXPECT_OBJECT_COMMA,
2250 : : EXPECT_ARRAY_FIRST_ELEMENT,
2251 : : EXPECT_ARRAY_NEXT_ELEMENT,
2252 : : EXPECT_ARRAY_COMMA,
2253 : :
2254 : : /* And these are used by json_build() */
2255 : : EXPECT_ARRAY_ELEMENT,
2256 : : EXPECT_OBJECT_KEY,
2257 : : } JsonExpect;
2258 : :
2259 : : typedef struct JsonStack {
2260 : : JsonExpect expect;
2261 : : JsonVariant **elements;
2262 : : size_t n_elements, n_elements_allocated;
2263 : : unsigned line_before;
2264 : : unsigned column_before;
2265 : : size_t n_suppress; /* When building: if > 0, suppress this many subsequent elements. If == (size_t) -1, suppress all subsequent elements */
2266 : : } JsonStack;
2267 : :
2268 : 7368 : static void json_stack_release(JsonStack *s) {
2269 [ - + ]: 7368 : assert(s);
2270 : :
2271 : 7368 : json_variant_unref_many(s->elements, s->n_elements);
2272 : 7368 : s->elements = mfree(s->elements);
2273 : 7368 : }
2274 : :
2275 : 608 : static int json_parse_internal(
2276 : : const char **input,
2277 : : JsonSource *source,
2278 : : JsonVariant **ret,
2279 : : unsigned *line,
2280 : : unsigned *column,
2281 : : bool continue_end) {
2282 : :
2283 : 608 : size_t n_stack = 1, n_stack_allocated = 0, i;
2284 : 608 : unsigned line_buffer = 0, column_buffer = 0;
2285 : 608 : void *tokenizer_state = NULL;
2286 : 608 : JsonStack *stack = NULL;
2287 : : const char *p;
2288 : : int r;
2289 : :
2290 [ - + - + ]: 608 : assert_return(input, -EINVAL);
2291 [ - + - + ]: 608 : assert_return(ret, -EINVAL);
2292 : :
2293 : 608 : p = *input;
2294 : :
2295 [ - + ]: 608 : if (!GREEDY_REALLOC(stack, n_stack_allocated, n_stack))
2296 : 0 : return -ENOMEM;
2297 : :
2298 : 608 : stack[0] = (JsonStack) {
2299 : : .expect = EXPECT_TOPLEVEL,
2300 : : };
2301 : :
2302 [ + - ]: 608 : if (!line)
2303 : 608 : line = &line_buffer;
2304 [ + - ]: 608 : if (!column)
2305 : 608 : column = &column_buffer;
2306 : :
2307 : 10432 : for (;;) {
2308 [ + + - ]: 11040 : _cleanup_(json_variant_unrefp) JsonVariant *add = NULL;
2309 [ + + - ]: 11040 : _cleanup_free_ char *string = NULL;
2310 : : unsigned line_token, column_token;
2311 : : JsonStack *current;
2312 : : JsonValue value;
2313 : : int token;
2314 : :
2315 [ - + ]: 11040 : assert(n_stack > 0);
2316 : 11040 : current = stack + n_stack - 1;
2317 : :
2318 [ - + # # ]: 11040 : if (continue_end && current->expect == EXPECT_END)
2319 : 0 : goto done;
2320 : :
2321 : 11040 : token = json_tokenize(&p, &string, &value, &line_token, &column_token, &tokenizer_state, line, column);
2322 [ - + ]: 11040 : if (token < 0) {
2323 : 0 : r = token;
2324 : 0 : goto finish;
2325 : : }
2326 : :
2327 [ + + + + : 11040 : switch (token) {
+ + + + +
+ + + +
- ]
2328 : :
2329 : 608 : case JSON_TOKEN_END:
2330 [ - + ]: 608 : if (current->expect != EXPECT_END) {
2331 : 0 : r = -EINVAL;
2332 : 0 : goto finish;
2333 : : }
2334 : :
2335 [ - + ]: 608 : assert(current->n_elements == 1);
2336 [ - + ]: 608 : assert(n_stack == 1);
2337 : 608 : goto done;
2338 : :
2339 : 2276 : case JSON_TOKEN_COLON:
2340 : :
2341 [ - + ]: 2276 : if (current->expect != EXPECT_OBJECT_COLON) {
2342 : 0 : r = -EINVAL;
2343 : 0 : goto finish;
2344 : : }
2345 : :
2346 : 2276 : current->expect = EXPECT_OBJECT_VALUE;
2347 : 2276 : break;
2348 : :
2349 : 1404 : case JSON_TOKEN_COMMA:
2350 : :
2351 [ + + ]: 1404 : if (current->expect == EXPECT_OBJECT_COMMA)
2352 : 1116 : current->expect = EXPECT_OBJECT_NEXT_KEY;
2353 [ + - ]: 288 : else if (current->expect == EXPECT_ARRAY_COMMA)
2354 : 288 : current->expect = EXPECT_ARRAY_NEXT_ELEMENT;
2355 : : else {
2356 : 0 : r = -EINVAL;
2357 : 0 : goto finish;
2358 : : }
2359 : :
2360 : 1404 : break;
2361 : :
2362 : 1168 : case JSON_TOKEN_OBJECT_OPEN:
2363 : :
2364 [ + - - + ]: 1168 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2365 : 0 : r = -EINVAL;
2366 : 0 : goto finish;
2367 : : }
2368 : :
2369 [ - + ]: 1168 : if (!GREEDY_REALLOC(stack, n_stack_allocated, n_stack+1)) {
2370 : 0 : r = -ENOMEM;
2371 : 0 : goto finish;
2372 : : }
2373 : 1168 : current = stack + n_stack - 1;
2374 : :
2375 : : /* Prepare the expect for when we return from the child */
2376 [ + + ]: 1168 : if (current->expect == EXPECT_TOPLEVEL)
2377 : 584 : current->expect = EXPECT_END;
2378 [ + + ]: 584 : else if (current->expect == EXPECT_OBJECT_VALUE)
2379 : 564 : current->expect = EXPECT_OBJECT_COMMA;
2380 : : else {
2381 [ + - - + ]: 20 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2382 : 20 : current->expect = EXPECT_ARRAY_COMMA;
2383 : : }
2384 : :
2385 : 1168 : stack[n_stack++] = (JsonStack) {
2386 : : .expect = EXPECT_OBJECT_FIRST_KEY,
2387 : : .line_before = line_token,
2388 : : .column_before = column_token,
2389 : : };
2390 : :
2391 : 1168 : current = stack + n_stack - 1;
2392 : 1168 : break;
2393 : :
2394 : 1168 : case JSON_TOKEN_OBJECT_CLOSE:
2395 [ + - - + ]: 1168 : if (!IN_SET(current->expect, EXPECT_OBJECT_FIRST_KEY, EXPECT_OBJECT_COMMA)) {
2396 : 0 : r = -EINVAL;
2397 : 0 : goto finish;
2398 : : }
2399 : :
2400 [ - + ]: 1168 : assert(n_stack > 1);
2401 : :
2402 : 1168 : r = json_variant_new_object(&add, current->elements, current->n_elements);
2403 [ - + ]: 1168 : if (r < 0)
2404 : 0 : goto finish;
2405 : :
2406 : 1168 : line_token = current->line_before;
2407 : 1168 : column_token = current->column_before;
2408 : :
2409 : 1168 : json_stack_release(current);
2410 : 1168 : n_stack--, current--;
2411 : :
2412 : 1168 : break;
2413 : :
2414 : 68 : case JSON_TOKEN_ARRAY_OPEN:
2415 [ + - - + ]: 68 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2416 : 0 : r = -EINVAL;
2417 : 0 : goto finish;
2418 : : }
2419 : :
2420 [ - + ]: 68 : if (!GREEDY_REALLOC(stack, n_stack_allocated, n_stack+1)) {
2421 : 0 : r = -ENOMEM;
2422 : 0 : goto finish;
2423 : : }
2424 : 68 : current = stack + n_stack - 1;
2425 : :
2426 : : /* Prepare the expect for when we return from the child */
2427 [ + + ]: 68 : if (current->expect == EXPECT_TOPLEVEL)
2428 : 16 : current->expect = EXPECT_END;
2429 [ + + ]: 52 : else if (current->expect == EXPECT_OBJECT_VALUE)
2430 : 44 : current->expect = EXPECT_OBJECT_COMMA;
2431 : : else {
2432 [ + - - + ]: 8 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2433 : 8 : current->expect = EXPECT_ARRAY_COMMA;
2434 : : }
2435 : :
2436 : 68 : stack[n_stack++] = (JsonStack) {
2437 : : .expect = EXPECT_ARRAY_FIRST_ELEMENT,
2438 : : .line_before = line_token,
2439 : : .column_before = column_token,
2440 : : };
2441 : :
2442 : 68 : break;
2443 : :
2444 : 68 : case JSON_TOKEN_ARRAY_CLOSE:
2445 [ + - - + ]: 68 : if (!IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_COMMA)) {
2446 : 0 : r = -EINVAL;
2447 : 0 : goto finish;
2448 : : }
2449 : :
2450 [ - + ]: 68 : assert(n_stack > 1);
2451 : :
2452 : 68 : r = json_variant_new_array(&add, current->elements, current->n_elements);
2453 [ - + ]: 68 : if (r < 0)
2454 : 0 : goto finish;
2455 : :
2456 : 68 : line_token = current->line_before;
2457 : 68 : column_token = current->column_before;
2458 : :
2459 : 68 : json_stack_release(current);
2460 : 68 : n_stack--, current--;
2461 : 68 : break;
2462 : :
2463 : 2896 : case JSON_TOKEN_STRING:
2464 [ + - - + ]: 2896 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_FIRST_KEY, EXPECT_OBJECT_NEXT_KEY, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2465 : 0 : r = -EINVAL;
2466 : 0 : goto finish;
2467 : : }
2468 : :
2469 : 2896 : r = json_variant_new_string(&add, string);
2470 [ - + ]: 2896 : if (r < 0)
2471 : 0 : goto finish;
2472 : :
2473 [ + + ]: 2896 : if (current->expect == EXPECT_TOPLEVEL)
2474 : 4 : current->expect = EXPECT_END;
2475 [ + + + + ]: 2892 : else if (IN_SET(current->expect, EXPECT_OBJECT_FIRST_KEY, EXPECT_OBJECT_NEXT_KEY))
2476 : 2276 : current->expect = EXPECT_OBJECT_COLON;
2477 [ + + ]: 616 : else if (current->expect == EXPECT_OBJECT_VALUE)
2478 : 568 : current->expect = EXPECT_OBJECT_COMMA;
2479 : : else {
2480 [ + - - + ]: 48 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2481 : 48 : current->expect = EXPECT_ARRAY_COMMA;
2482 : : }
2483 : :
2484 : 2896 : break;
2485 : :
2486 : 156 : case JSON_TOKEN_REAL:
2487 [ + - - + ]: 156 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2488 : 0 : r = -EINVAL;
2489 : 0 : goto finish;
2490 : : }
2491 : :
2492 : 156 : r = json_variant_new_real(&add, value.real);
2493 [ - + ]: 156 : if (r < 0)
2494 : 0 : goto finish;
2495 : :
2496 [ + + ]: 156 : if (current->expect == EXPECT_TOPLEVEL)
2497 : 4 : current->expect = EXPECT_END;
2498 [ + + ]: 152 : else if (current->expect == EXPECT_OBJECT_VALUE)
2499 : 16 : current->expect = EXPECT_OBJECT_COMMA;
2500 : : else {
2501 [ + - - + ]: 136 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2502 : 136 : current->expect = EXPECT_ARRAY_COMMA;
2503 : : }
2504 : :
2505 : 156 : break;
2506 : :
2507 : 12 : case JSON_TOKEN_INTEGER:
2508 [ + - - + ]: 12 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2509 : 0 : r = -EINVAL;
2510 : 0 : goto finish;
2511 : : }
2512 : :
2513 : 12 : r = json_variant_new_integer(&add, value.integer);
2514 [ - + ]: 12 : if (r < 0)
2515 : 0 : goto finish;
2516 : :
2517 [ - + ]: 12 : if (current->expect == EXPECT_TOPLEVEL)
2518 : 0 : current->expect = EXPECT_END;
2519 [ - + ]: 12 : else if (current->expect == EXPECT_OBJECT_VALUE)
2520 : 0 : current->expect = EXPECT_OBJECT_COMMA;
2521 : : else {
2522 [ + - - + ]: 12 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2523 : 12 : current->expect = EXPECT_ARRAY_COMMA;
2524 : : }
2525 : :
2526 : 12 : break;
2527 : :
2528 : 640 : case JSON_TOKEN_UNSIGNED:
2529 [ + - - + ]: 640 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2530 : 0 : r = -EINVAL;
2531 : 0 : goto finish;
2532 : : }
2533 : :
2534 : 640 : r = json_variant_new_unsigned(&add, value.unsig);
2535 [ - + ]: 640 : if (r < 0)
2536 : 0 : goto finish;
2537 : :
2538 [ - + ]: 640 : if (current->expect == EXPECT_TOPLEVEL)
2539 : 0 : current->expect = EXPECT_END;
2540 [ + + ]: 640 : else if (current->expect == EXPECT_OBJECT_VALUE)
2541 : 544 : current->expect = EXPECT_OBJECT_COMMA;
2542 : : else {
2543 [ + - - + ]: 96 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2544 : 96 : current->expect = EXPECT_ARRAY_COMMA;
2545 : : }
2546 : :
2547 : 640 : break;
2548 : :
2549 : 532 : case JSON_TOKEN_BOOLEAN:
2550 [ + - - + ]: 532 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2551 : 0 : r = -EINVAL;
2552 : 0 : goto finish;
2553 : : }
2554 : :
2555 : 532 : r = json_variant_new_boolean(&add, value.boolean);
2556 [ - + ]: 532 : if (r < 0)
2557 : 0 : goto finish;
2558 : :
2559 [ - + ]: 532 : if (current->expect == EXPECT_TOPLEVEL)
2560 : 0 : current->expect = EXPECT_END;
2561 [ + + ]: 532 : else if (current->expect == EXPECT_OBJECT_VALUE)
2562 : 524 : current->expect = EXPECT_OBJECT_COMMA;
2563 : : else {
2564 [ + - - + ]: 8 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2565 : 8 : current->expect = EXPECT_ARRAY_COMMA;
2566 : : }
2567 : :
2568 : 532 : break;
2569 : :
2570 : 44 : case JSON_TOKEN_NULL:
2571 [ + - - + ]: 44 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
2572 : 0 : r = -EINVAL;
2573 : 0 : goto finish;
2574 : : }
2575 : :
2576 : 44 : r = json_variant_new_null(&add);
2577 [ - + ]: 44 : if (r < 0)
2578 : 0 : goto finish;
2579 : :
2580 [ - + ]: 44 : if (current->expect == EXPECT_TOPLEVEL)
2581 : 0 : current->expect = EXPECT_END;
2582 [ + + ]: 44 : else if (current->expect == EXPECT_OBJECT_VALUE)
2583 : 16 : current->expect = EXPECT_OBJECT_COMMA;
2584 : : else {
2585 [ + - - + ]: 28 : assert(IN_SET(current->expect, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT));
2586 : 28 : current->expect = EXPECT_ARRAY_COMMA;
2587 : : }
2588 : :
2589 : 44 : break;
2590 : :
2591 : 0 : default:
2592 : 0 : assert_not_reached("Unexpected token");
2593 : : }
2594 : :
2595 [ + + ]: 10432 : if (add) {
2596 : 5516 : (void) json_variant_set_source(&add, source, line_token, column_token);
2597 : :
2598 [ - + ]: 5516 : if (!GREEDY_REALLOC(current->elements, current->n_elements_allocated, current->n_elements + 1)) {
2599 : 0 : r = -ENOMEM;
2600 : 0 : goto finish;
2601 : : }
2602 : :
2603 : 5516 : current->elements[current->n_elements++] = TAKE_PTR(add);
2604 : : }
2605 : : }
2606 : :
2607 : 608 : done:
2608 [ - + ]: 608 : assert(n_stack == 1);
2609 [ - + ]: 608 : assert(stack[0].n_elements == 1);
2610 : :
2611 : 608 : *ret = json_variant_ref(stack[0].elements[0]);
2612 : 608 : *input = p;
2613 : 608 : r = 0;
2614 : :
2615 : 608 : finish:
2616 [ + + ]: 1216 : for (i = 0; i < n_stack; i++)
2617 : 608 : json_stack_release(stack + i);
2618 : :
2619 : 608 : free(stack);
2620 : :
2621 : 608 : return r;
2622 : : }
2623 : :
2624 : 604 : int json_parse(const char *input, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
2625 : 604 : return json_parse_internal(&input, NULL, ret, ret_line, ret_column, false);
2626 : : }
2627 : :
2628 : 0 : int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
2629 : 0 : return json_parse_internal(p, NULL, ret, ret_line, ret_column, true);
2630 : : }
2631 : :
2632 : 4 : int json_parse_file(FILE *f, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
2633 : 4 : _cleanup_(json_source_unrefp) JsonSource *source = NULL;
2634 : 4 : _cleanup_free_ char *text = NULL;
2635 : : const char *p;
2636 : : int r;
2637 : :
2638 [ + - ]: 4 : if (f)
2639 : 4 : r = read_full_stream(f, &text, NULL);
2640 [ # # ]: 0 : else if (path)
2641 : 0 : r = read_full_file(path, &text, NULL);
2642 : : else
2643 : 0 : return -EINVAL;
2644 [ - + ]: 4 : if (r < 0)
2645 : 0 : return r;
2646 : :
2647 [ + - ]: 4 : if (path) {
2648 : 4 : source = json_source_new(path);
2649 [ - + ]: 4 : if (!source)
2650 : 0 : return -ENOMEM;
2651 : : }
2652 : :
2653 : 4 : p = text;
2654 : 4 : return json_parse_internal(&p, source, ret, ret_line, ret_column, false);
2655 : : }
2656 : :
2657 : 2764 : int json_buildv(JsonVariant **ret, va_list ap) {
2658 : 2764 : JsonStack *stack = NULL;
2659 : 2764 : size_t n_stack = 1, n_stack_allocated = 0, i;
2660 : : int r;
2661 : :
2662 [ - + - + ]: 2764 : assert_return(ret, -EINVAL);
2663 : :
2664 [ - + ]: 2764 : if (!GREEDY_REALLOC(stack, n_stack_allocated, n_stack))
2665 : 0 : return -ENOMEM;
2666 : :
2667 : 2764 : stack[0] = (JsonStack) {
2668 : : .expect = EXPECT_TOPLEVEL,
2669 : : };
2670 : :
2671 : 16560 : for (;;) {
2672 [ + + - ]: 19324 : _cleanup_(json_variant_unrefp) JsonVariant *add = NULL;
2673 : 19324 : size_t n_subtract = 0; /* how much to subtract from current->n_suppress, i.e. how many elements would
2674 : : * have been added to the current variant */
2675 : : JsonStack *current;
2676 : : int command;
2677 : :
2678 [ - + ]: 19324 : assert(n_stack > 0);
2679 : 19324 : current = stack + n_stack - 1;
2680 : :
2681 [ + + ]: 19324 : if (current->expect == EXPECT_END)
2682 : 2764 : goto done;
2683 : :
2684 : 16560 : command = va_arg(ap, int);
2685 : :
2686 [ + + - + : 16560 : switch (command) {
+ + + + +
+ + + + +
+ - ]
2687 : :
2688 : 1416 : case _JSON_BUILD_STRING: {
2689 : : const char *p;
2690 : :
2691 [ + - - + ]: 1416 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2692 : 0 : r = -EINVAL;
2693 : 0 : goto finish;
2694 : : }
2695 : :
2696 : 1416 : p = va_arg(ap, const char *);
2697 : :
2698 [ + + ]: 1416 : if (current->n_suppress == 0) {
2699 : 1400 : r = json_variant_new_string(&add, p);
2700 [ - + ]: 1400 : if (r < 0)
2701 : 0 : goto finish;
2702 : : }
2703 : :
2704 : 1416 : n_subtract = 1;
2705 : :
2706 [ + + ]: 1416 : if (current->expect == EXPECT_TOPLEVEL)
2707 : 8 : current->expect = EXPECT_END;
2708 [ + + ]: 1408 : else if (current->expect == EXPECT_OBJECT_VALUE)
2709 : 1392 : current->expect = EXPECT_OBJECT_KEY;
2710 : : else
2711 [ - + ]: 16 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2712 : :
2713 : 1416 : break;
2714 : : }
2715 : :
2716 : 1372 : case _JSON_BUILD_INTEGER: {
2717 : : intmax_t j;
2718 : :
2719 [ + - - + ]: 1372 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2720 : 0 : r = -EINVAL;
2721 : 0 : goto finish;
2722 : : }
2723 : :
2724 : 1372 : j = va_arg(ap, intmax_t);
2725 : :
2726 [ + - ]: 1372 : if (current->n_suppress == 0) {
2727 : 1372 : r = json_variant_new_integer(&add, j);
2728 [ - + ]: 1372 : if (r < 0)
2729 : 0 : goto finish;
2730 : : }
2731 : :
2732 : 1372 : n_subtract = 1;
2733 : :
2734 [ - + ]: 1372 : if (current->expect == EXPECT_TOPLEVEL)
2735 : 0 : current->expect = EXPECT_END;
2736 [ + + ]: 1372 : else if (current->expect == EXPECT_OBJECT_VALUE)
2737 : 1368 : current->expect = EXPECT_OBJECT_KEY;
2738 : : else
2739 [ - + ]: 4 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2740 : :
2741 : 1372 : break;
2742 : : }
2743 : :
2744 : 0 : case _JSON_BUILD_UNSIGNED: {
2745 : : uintmax_t j;
2746 : :
2747 [ # # # # ]: 0 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2748 : 0 : r = -EINVAL;
2749 : 0 : goto finish;
2750 : : }
2751 : :
2752 : 0 : j = va_arg(ap, uintmax_t);
2753 : :
2754 [ # # ]: 0 : if (current->n_suppress == 0) {
2755 : 0 : r = json_variant_new_unsigned(&add, j);
2756 [ # # ]: 0 : if (r < 0)
2757 : 0 : goto finish;
2758 : : }
2759 : :
2760 : 0 : n_subtract = 1;
2761 : :
2762 [ # # ]: 0 : if (current->expect == EXPECT_TOPLEVEL)
2763 : 0 : current->expect = EXPECT_END;
2764 [ # # ]: 0 : else if (current->expect == EXPECT_OBJECT_VALUE)
2765 : 0 : current->expect = EXPECT_OBJECT_KEY;
2766 : : else
2767 [ # # ]: 0 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2768 : :
2769 : 0 : break;
2770 : : }
2771 : :
2772 : 20 : case _JSON_BUILD_REAL: {
2773 : : long double d;
2774 : :
2775 [ + - - + ]: 20 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2776 : 0 : r = -EINVAL;
2777 : 0 : goto finish;
2778 : : }
2779 : :
2780 : 20 : d = va_arg(ap, long double);
2781 : :
2782 [ + - ]: 20 : if (current->n_suppress == 0) {
2783 : 20 : r = json_variant_new_real(&add, d);
2784 [ - + ]: 20 : if (r < 0)
2785 : 0 : goto finish;
2786 : : }
2787 : :
2788 : 20 : n_subtract = 1;
2789 : :
2790 [ + + ]: 20 : if (current->expect == EXPECT_TOPLEVEL)
2791 : 4 : current->expect = EXPECT_END;
2792 [ + - ]: 16 : else if (current->expect == EXPECT_OBJECT_VALUE)
2793 : 16 : current->expect = EXPECT_OBJECT_KEY;
2794 : : else
2795 [ # # ]: 0 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2796 : :
2797 : 20 : break;
2798 : : }
2799 : :
2800 : 1340 : case _JSON_BUILD_BOOLEAN: {
2801 : : bool b;
2802 : :
2803 [ + - - + ]: 1340 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2804 : 0 : r = -EINVAL;
2805 : 0 : goto finish;
2806 : : }
2807 : :
2808 : 1340 : b = va_arg(ap, int);
2809 : :
2810 [ + - ]: 1340 : if (current->n_suppress == 0) {
2811 : 1340 : r = json_variant_new_boolean(&add, b);
2812 [ - + ]: 1340 : if (r < 0)
2813 : 0 : goto finish;
2814 : : }
2815 : :
2816 : 1340 : n_subtract = 1;
2817 : :
2818 [ - + ]: 1340 : if (current->expect == EXPECT_TOPLEVEL)
2819 : 0 : current->expect = EXPECT_END;
2820 [ + - ]: 1340 : else if (current->expect == EXPECT_OBJECT_VALUE)
2821 : 1340 : current->expect = EXPECT_OBJECT_KEY;
2822 : : else
2823 [ # # ]: 0 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2824 : :
2825 : 1340 : break;
2826 : : }
2827 : :
2828 : 8 : case _JSON_BUILD_NULL:
2829 : :
2830 [ + - - + ]: 8 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2831 : 0 : r = -EINVAL;
2832 : 0 : goto finish;
2833 : : }
2834 : :
2835 [ + - ]: 8 : if (current->n_suppress == 0) {
2836 : 8 : r = json_variant_new_null(&add);
2837 [ - + ]: 8 : if (r < 0)
2838 : 0 : goto finish;
2839 : : }
2840 : :
2841 : 8 : n_subtract = 1;
2842 : :
2843 [ - + ]: 8 : if (current->expect == EXPECT_TOPLEVEL)
2844 : 0 : current->expect = EXPECT_END;
2845 [ + + ]: 8 : else if (current->expect == EXPECT_OBJECT_VALUE)
2846 : 4 : current->expect = EXPECT_OBJECT_KEY;
2847 : : else
2848 [ - + ]: 4 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2849 : :
2850 : 8 : break;
2851 : :
2852 : 1380 : case _JSON_BUILD_VARIANT:
2853 : :
2854 [ + - - + ]: 1380 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2855 : 0 : r = -EINVAL;
2856 : 0 : goto finish;
2857 : : }
2858 : :
2859 : : /* Note that we don't care for current->n_suppress here, after all the variant is already
2860 : : * allocated anyway... */
2861 : 1380 : add = va_arg(ap, JsonVariant*);
2862 [ + + ]: 1380 : if (!add)
2863 : 4 : add = JSON_VARIANT_MAGIC_NULL;
2864 : : else
2865 : 1376 : json_variant_ref(add);
2866 : :
2867 : 1380 : n_subtract = 1;
2868 : :
2869 [ + + ]: 1380 : if (current->expect == EXPECT_TOPLEVEL)
2870 : 4 : current->expect = EXPECT_END;
2871 [ + + ]: 1376 : else if (current->expect == EXPECT_OBJECT_VALUE)
2872 : 1364 : current->expect = EXPECT_OBJECT_KEY;
2873 : : else
2874 [ - + ]: 12 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2875 : :
2876 : 1380 : break;
2877 : :
2878 : 8 : case _JSON_BUILD_LITERAL: {
2879 : : const char *l;
2880 : :
2881 [ + - - + ]: 8 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2882 : 0 : r = -EINVAL;
2883 : 0 : goto finish;
2884 : : }
2885 : :
2886 : 8 : l = va_arg(ap, const char *);
2887 : :
2888 [ + + ]: 8 : if (l) {
2889 : : /* Note that we don't care for current->n_suppress here, we should generate parsing
2890 : : * errors even in suppressed object properties */
2891 : :
2892 : 4 : r = json_parse(l, &add, NULL, NULL);
2893 [ - + ]: 4 : if (r < 0)
2894 : 0 : goto finish;
2895 : : } else
2896 : 4 : add = JSON_VARIANT_MAGIC_NULL;
2897 : :
2898 : 8 : n_subtract = 1;
2899 : :
2900 [ + + ]: 8 : if (current->expect == EXPECT_TOPLEVEL)
2901 : 4 : current->expect = EXPECT_END;
2902 [ - + ]: 4 : else if (current->expect == EXPECT_OBJECT_VALUE)
2903 : 0 : current->expect = EXPECT_OBJECT_KEY;
2904 : : else
2905 [ - + ]: 4 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2906 : :
2907 : 8 : break;
2908 : : }
2909 : :
2910 : 12 : case _JSON_BUILD_ARRAY_BEGIN:
2911 : :
2912 [ + - - + ]: 12 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2913 : 0 : r = -EINVAL;
2914 : 0 : goto finish;
2915 : : }
2916 : :
2917 [ - + ]: 12 : if (!GREEDY_REALLOC(stack, n_stack_allocated, n_stack+1)) {
2918 : 0 : r = -ENOMEM;
2919 : 0 : goto finish;
2920 : : }
2921 : 12 : current = stack + n_stack - 1;
2922 : :
2923 [ + + ]: 12 : if (current->expect == EXPECT_TOPLEVEL)
2924 : 4 : current->expect = EXPECT_END;
2925 [ + + ]: 8 : else if (current->expect == EXPECT_OBJECT_VALUE)
2926 : 4 : current->expect = EXPECT_OBJECT_KEY;
2927 : : else
2928 [ - + ]: 4 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2929 : :
2930 : 24 : stack[n_stack++] = (JsonStack) {
2931 : : .expect = EXPECT_ARRAY_ELEMENT,
2932 [ + + ]: 12 : .n_suppress = current->n_suppress != 0 ? (size_t) -1 : 0, /* if we shall suppress the
2933 : : * new array, then we should
2934 : : * also suppress all array
2935 : : * members */
2936 : : };
2937 : :
2938 : 12 : break;
2939 : :
2940 : 12 : case _JSON_BUILD_ARRAY_END:
2941 [ - + ]: 12 : if (current->expect != EXPECT_ARRAY_ELEMENT) {
2942 : 0 : r = -EINVAL;
2943 : 0 : goto finish;
2944 : : }
2945 : :
2946 [ - + ]: 12 : assert(n_stack > 1);
2947 : :
2948 [ + + ]: 12 : if (current->n_suppress == 0) {
2949 : 8 : r = json_variant_new_array(&add, current->elements, current->n_elements);
2950 [ - + ]: 8 : if (r < 0)
2951 : 0 : goto finish;
2952 : : }
2953 : :
2954 : 12 : n_subtract = 1;
2955 : :
2956 : 12 : json_stack_release(current);
2957 : 12 : n_stack--, current--;
2958 : :
2959 : 12 : break;
2960 : :
2961 : 4 : case _JSON_BUILD_STRV: {
2962 : : char **l;
2963 : :
2964 [ + - - + ]: 4 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2965 : 0 : r = -EINVAL;
2966 : 0 : goto finish;
2967 : : }
2968 : :
2969 : 4 : l = va_arg(ap, char **);
2970 : :
2971 [ + - ]: 4 : if (current->n_suppress == 0) {
2972 : 4 : r = json_variant_new_array_strv(&add, l);
2973 [ - + ]: 4 : if (r < 0)
2974 : 0 : goto finish;
2975 : : }
2976 : :
2977 : 4 : n_subtract = 1;
2978 : :
2979 [ - + ]: 4 : if (current->expect == EXPECT_TOPLEVEL)
2980 : 0 : current->expect = EXPECT_END;
2981 [ - + ]: 4 : else if (current->expect == EXPECT_OBJECT_VALUE)
2982 : 0 : current->expect = EXPECT_OBJECT_KEY;
2983 : : else
2984 [ - + ]: 4 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
2985 : :
2986 : 4 : break;
2987 : : }
2988 : :
2989 : 2748 : case _JSON_BUILD_OBJECT_BEGIN:
2990 : :
2991 [ + - - + ]: 2748 : if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
2992 : 0 : r = -EINVAL;
2993 : 0 : goto finish;
2994 : : }
2995 : :
2996 [ - + ]: 2748 : if (!GREEDY_REALLOC(stack, n_stack_allocated, n_stack+1)) {
2997 : 0 : r = -ENOMEM;
2998 : 0 : goto finish;
2999 : : }
3000 : 2748 : current = stack + n_stack - 1;
3001 : :
3002 [ + + ]: 2748 : if (current->expect == EXPECT_TOPLEVEL)
3003 : 2740 : current->expect = EXPECT_END;
3004 [ + + ]: 8 : else if (current->expect == EXPECT_OBJECT_VALUE)
3005 : 4 : current->expect = EXPECT_OBJECT_KEY;
3006 : : else
3007 [ - + ]: 4 : assert(current->expect == EXPECT_ARRAY_ELEMENT);
3008 : :
3009 : 5496 : stack[n_stack++] = (JsonStack) {
3010 : : .expect = EXPECT_OBJECT_KEY,
3011 [ - + ]: 2748 : .n_suppress = current->n_suppress != 0 ? (size_t) -1 : 0, /* if we shall suppress the
3012 : : * new object, then we should
3013 : : * also suppress all object
3014 : : * members */
3015 : : };
3016 : :
3017 : 2748 : break;
3018 : :
3019 : 2748 : case _JSON_BUILD_OBJECT_END:
3020 : :
3021 [ - + ]: 2748 : if (current->expect != EXPECT_OBJECT_KEY) {
3022 : 0 : r = -EINVAL;
3023 : 0 : goto finish;
3024 : : }
3025 : :
3026 [ - + ]: 2748 : assert(n_stack > 1);
3027 : :
3028 [ + - ]: 2748 : if (current->n_suppress == 0) {
3029 : 2748 : r = json_variant_new_object(&add, current->elements, current->n_elements);
3030 [ - + ]: 2748 : if (r < 0)
3031 : 0 : goto finish;
3032 : : }
3033 : :
3034 : 2748 : n_subtract = 1;
3035 : :
3036 : 2748 : json_stack_release(current);
3037 : 2748 : n_stack--, current--;
3038 : :
3039 : 2748 : break;
3040 : :
3041 : 5480 : case _JSON_BUILD_PAIR: {
3042 : : const char *n;
3043 : :
3044 [ - + ]: 5480 : if (current->expect != EXPECT_OBJECT_KEY) {
3045 : 0 : r = -EINVAL;
3046 : 0 : goto finish;
3047 : : }
3048 : :
3049 : 5480 : n = va_arg(ap, const char *);
3050 : :
3051 [ + - ]: 5480 : if (current->n_suppress == 0) {
3052 : 5480 : r = json_variant_new_string(&add, n);
3053 [ - + ]: 5480 : if (r < 0)
3054 : 0 : goto finish;
3055 : : }
3056 : :
3057 : 5480 : n_subtract = 1;
3058 : :
3059 : 5480 : current->expect = EXPECT_OBJECT_VALUE;
3060 : 5480 : break;
3061 : : }
3062 : :
3063 : 12 : case _JSON_BUILD_PAIR_CONDITION: {
3064 : : const char *n;
3065 : : bool b;
3066 : :
3067 [ - + ]: 12 : if (current->expect != EXPECT_OBJECT_KEY) {
3068 : 0 : r = -EINVAL;
3069 : 0 : goto finish;
3070 : : }
3071 : :
3072 : 12 : b = va_arg(ap, int);
3073 : 12 : n = va_arg(ap, const char *);
3074 : :
3075 [ + + + - ]: 12 : if (b && current->n_suppress == 0) {
3076 : 4 : r = json_variant_new_string(&add, n);
3077 [ - + ]: 4 : if (r < 0)
3078 : 0 : goto finish;
3079 : : }
3080 : :
3081 : 12 : n_subtract = 1; /* we generated one item */
3082 : :
3083 [ + + + - ]: 12 : if (!b && current->n_suppress != (size_t) -1)
3084 : 8 : current->n_suppress += 2; /* Suppress this one and the next item */
3085 : :
3086 : 12 : current->expect = EXPECT_OBJECT_VALUE;
3087 : 12 : break;
3088 : : }}
3089 : :
3090 : : /* If a variant was generated, add it to our current variant, but only if we are not supposed to suppress additions */
3091 [ + + + - ]: 16560 : if (add && current->n_suppress == 0) {
3092 [ - + ]: 13772 : if (!GREEDY_REALLOC(current->elements, current->n_elements_allocated, current->n_elements + 1)) {
3093 : 0 : r = -ENOMEM;
3094 : 0 : goto finish;
3095 : : }
3096 : :
3097 : 13772 : current->elements[current->n_elements++] = TAKE_PTR(add);
3098 : : }
3099 : :
3100 : : /* If we are supposed to suppress items, let's subtract how many items where generated from that
3101 : : * counter. Except if the counter is (size_t) -1, i.e. we shall suppress an infinite number of elements
3102 : : * on this stack level */
3103 [ + + ]: 16560 : if (current->n_suppress != (size_t) -1) {
3104 [ + + ]: 16548 : if (current->n_suppress <= n_subtract) /* Saturated */
3105 : 16536 : current->n_suppress = 0;
3106 : : else
3107 : 12 : current->n_suppress -= n_subtract;
3108 : : }
3109 : : }
3110 : :
3111 : 2764 : done:
3112 [ - + ]: 2764 : assert(n_stack == 1);
3113 [ - + ]: 2764 : assert(stack[0].n_elements == 1);
3114 : :
3115 : 2764 : *ret = json_variant_ref(stack[0].elements[0]);
3116 : 2764 : r = 0;
3117 : :
3118 : 2764 : finish:
3119 [ + + ]: 5528 : for (i = 0; i < n_stack; i++)
3120 : 2764 : json_stack_release(stack + i);
3121 : :
3122 : 2764 : free(stack);
3123 : :
3124 : 2764 : return r;
3125 : : }
3126 : :
3127 : 1420 : int json_build(JsonVariant **ret, ...) {
3128 : : va_list ap;
3129 : : int r;
3130 : :
3131 : 1420 : va_start(ap, ret);
3132 : 1420 : r = json_buildv(ret, ap);
3133 : 1420 : va_end(ap);
3134 : :
3135 : 1420 : return r;
3136 : : }
3137 : :
3138 : 0 : int json_log_internal(
3139 : : JsonVariant *variant,
3140 : : int level,
3141 : : int error,
3142 : : const char *file,
3143 : : int line,
3144 : : const char *func,
3145 : : const char *format, ...) {
3146 : :
3147 : 0 : PROTECT_ERRNO;
3148 : :
3149 : : unsigned source_line, source_column;
3150 : : char buffer[LINE_MAX];
3151 : : const char *source;
3152 : : va_list ap;
3153 : : int r;
3154 : :
3155 : 0 : errno = ERRNO_VALUE(error);
3156 : :
3157 : 0 : va_start(ap, format);
3158 : 0 : (void) vsnprintf(buffer, sizeof buffer, format, ap);
3159 : 0 : va_end(ap);
3160 : :
3161 [ # # ]: 0 : if (variant) {
3162 : 0 : r = json_variant_get_source(variant, &source, &source_line, &source_column);
3163 [ # # ]: 0 : if (r < 0)
3164 : 0 : return r;
3165 : : } else {
3166 : 0 : source = NULL;
3167 : 0 : source_line = 0;
3168 : 0 : source_column = 0;
3169 : : }
3170 : :
3171 [ # # # # : 0 : if (source && source_line > 0 && source_column > 0)
# # ]
3172 : 0 : return log_struct_internal(
3173 : : LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
3174 : : error,
3175 : : file, line, func,
3176 : : "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
3177 : : "CONFIG_FILE=%s", source,
3178 : : "CONFIG_LINE=%u", source_line,
3179 : : "CONFIG_COLUMN=%u", source_column,
3180 : : LOG_MESSAGE("%s:%u:%u: %s", source, source_line, source_column, buffer),
3181 : : NULL);
3182 : : else
3183 : 0 : return log_struct_internal(
3184 : : LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
3185 : : error,
3186 : : file, line, func,
3187 : : "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
3188 : : LOG_MESSAGE("%s", buffer),
3189 : : NULL);
3190 : : }
3191 : :
3192 : 0 : int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata) {
3193 : : const JsonDispatch *p;
3194 : : size_t i, n, m;
3195 : 0 : int r, done = 0;
3196 : : bool *found;
3197 : :
3198 [ # # ]: 0 : if (!json_variant_is_object(v)) {
3199 [ # # ]: 0 : json_log(v, flags, 0, "JSON variant is not an object.");
3200 : :
3201 [ # # ]: 0 : if (flags & JSON_PERMISSIVE)
3202 : 0 : return 0;
3203 : :
3204 : 0 : return -EINVAL;
3205 : : }
3206 : :
3207 [ # # ]: 0 : for (p = table, m = 0; p->name; p++)
3208 : 0 : m++;
3209 : :
3210 [ # # # # : 0 : found = newa0(bool, m);
# # ]
3211 : :
3212 : 0 : n = json_variant_elements(v);
3213 [ # # ]: 0 : for (i = 0; i < n; i += 2) {
3214 : : JsonVariant *key, *value;
3215 : :
3216 [ # # ]: 0 : assert_se(key = json_variant_by_index(v, i));
3217 [ # # ]: 0 : assert_se(value = json_variant_by_index(v, i+1));
3218 : :
3219 [ # # ]: 0 : for (p = table; p->name; p++)
3220 [ # # # # ]: 0 : if (p->name == (const char*) -1 ||
3221 : 0 : streq_ptr(json_variant_string(key), p->name))
3222 : : break;
3223 : :
3224 [ # # ]: 0 : if (p->name) { /* Found a matching entry! :-) */
3225 : : JsonDispatchFlags merged_flags;
3226 : :
3227 : 0 : merged_flags = flags | p->flags;
3228 : :
3229 [ # # ]: 0 : if (p->type != _JSON_VARIANT_TYPE_INVALID &&
3230 [ # # ]: 0 : !json_variant_has_type(value, p->type)) {
3231 : :
3232 [ # # ]: 0 : json_log(value, merged_flags, 0,
3233 : : "Object field '%s' has wrong type %s, expected %s.", json_variant_string(key),
3234 : : json_variant_type_to_string(json_variant_type(value)), json_variant_type_to_string(p->type));
3235 : :
3236 [ # # ]: 0 : if (merged_flags & JSON_PERMISSIVE)
3237 : 0 : continue;
3238 : :
3239 : 0 : return -EINVAL;
3240 : : }
3241 : :
3242 [ # # ]: 0 : if (found[p-table]) {
3243 [ # # ]: 0 : json_log(value, merged_flags, 0, "Duplicate object field '%s'.", json_variant_string(key));
3244 : :
3245 [ # # ]: 0 : if (merged_flags & JSON_PERMISSIVE)
3246 : 0 : continue;
3247 : :
3248 : 0 : return -ENOTUNIQ;
3249 : : }
3250 : :
3251 : 0 : found[p-table] = true;
3252 : :
3253 [ # # ]: 0 : if (p->callback) {
3254 : 0 : r = p->callback(json_variant_string(key), value, merged_flags, (uint8_t*) userdata + p->offset);
3255 [ # # ]: 0 : if (r < 0) {
3256 [ # # ]: 0 : if (merged_flags & JSON_PERMISSIVE)
3257 : 0 : continue;
3258 : :
3259 : 0 : return r;
3260 : : }
3261 : : }
3262 : :
3263 : 0 : done ++;
3264 : :
3265 : : } else { /* Didn't find a matching entry! :-( */
3266 : :
3267 [ # # ]: 0 : if (bad) {
3268 : 0 : r = bad(json_variant_string(key), value, flags, userdata);
3269 [ # # ]: 0 : if (r < 0) {
3270 [ # # ]: 0 : if (flags & JSON_PERMISSIVE)
3271 : 0 : continue;
3272 : :
3273 : 0 : return r;
3274 : : } else
3275 : 0 : done ++;
3276 : :
3277 : : } else {
3278 [ # # ]: 0 : json_log(value, flags, 0, "Unexpected object field '%s'.", json_variant_string(key));
3279 : :
3280 [ # # ]: 0 : if (flags & JSON_PERMISSIVE)
3281 : 0 : continue;
3282 : :
3283 : 0 : return -EADDRNOTAVAIL;
3284 : : }
3285 : : }
3286 : : }
3287 : :
3288 [ # # ]: 0 : for (p = table; p->name; p++) {
3289 : 0 : JsonDispatchFlags merged_flags = p->flags | flags;
3290 : :
3291 [ # # # # ]: 0 : if ((merged_flags & JSON_MANDATORY) && !found[p-table]) {
3292 [ # # ]: 0 : json_log(v, merged_flags, 0, "Missing object field '%s'.", p->name);
3293 : :
3294 [ # # ]: 0 : if ((merged_flags & JSON_PERMISSIVE))
3295 : 0 : continue;
3296 : :
3297 : 0 : return -ENXIO;
3298 : : }
3299 : : }
3300 : :
3301 : 0 : return done;
3302 : : }
3303 : :
3304 : 0 : int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3305 : 0 : bool *b = userdata;
3306 : :
3307 [ # # ]: 0 : assert(variant);
3308 [ # # ]: 0 : assert(b);
3309 : :
3310 [ # # ]: 0 : if (!json_variant_is_boolean(variant))
3311 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
3312 : :
3313 : 0 : *b = json_variant_boolean(variant);
3314 : 0 : return 0;
3315 : : }
3316 : :
3317 : 0 : int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3318 : 0 : int *b = userdata;
3319 : :
3320 [ # # ]: 0 : assert(variant);
3321 [ # # ]: 0 : assert(b);
3322 : :
3323 [ # # ]: 0 : if (!json_variant_is_boolean(variant))
3324 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
3325 : :
3326 : 0 : *b = json_variant_boolean(variant);
3327 : 0 : return 0;
3328 : : }
3329 : :
3330 : 0 : int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3331 : 0 : intmax_t *i = userdata;
3332 : :
3333 [ # # ]: 0 : assert(variant);
3334 [ # # ]: 0 : assert(i);
3335 : :
3336 [ # # ]: 0 : if (!json_variant_is_integer(variant))
3337 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
3338 : :
3339 : 0 : *i = json_variant_integer(variant);
3340 : 0 : return 0;
3341 : : }
3342 : :
3343 : 0 : int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3344 : 0 : uintmax_t *u = userdata;
3345 : :
3346 [ # # ]: 0 : assert(variant);
3347 [ # # ]: 0 : assert(u);
3348 : :
3349 [ # # ]: 0 : if (!json_variant_is_unsigned(variant))
3350 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an unsigned integer.", strna(name));
3351 : :
3352 : 0 : *u = json_variant_unsigned(variant);
3353 : 0 : return 0;
3354 : : }
3355 : :
3356 : 0 : int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3357 : 0 : uint32_t *u = userdata;
3358 : :
3359 [ # # ]: 0 : assert(variant);
3360 [ # # ]: 0 : assert(u);
3361 : :
3362 [ # # ]: 0 : if (!json_variant_is_unsigned(variant))
3363 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an unsigned integer.", strna(name));
3364 : :
3365 [ # # ]: 0 : if (json_variant_unsigned(variant) > UINT32_MAX)
3366 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds.", strna(name));
3367 : :
3368 : 0 : *u = (uint32_t) json_variant_unsigned(variant);
3369 : 0 : return 0;
3370 : : }
3371 : :
3372 : 0 : int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3373 : 0 : int32_t *i = userdata;
3374 : :
3375 [ # # ]: 0 : assert(variant);
3376 [ # # ]: 0 : assert(i);
3377 : :
3378 [ # # ]: 0 : if (!json_variant_is_integer(variant))
3379 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
3380 : :
3381 [ # # # # ]: 0 : if (json_variant_integer(variant) < INT32_MIN || json_variant_integer(variant) > INT32_MAX)
3382 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds.", strna(name));
3383 : :
3384 : 0 : *i = (int32_t) json_variant_integer(variant);
3385 : 0 : return 0;
3386 : : }
3387 : :
3388 : 0 : int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3389 : 0 : char **s = userdata;
3390 : : int r;
3391 : :
3392 [ # # ]: 0 : assert(variant);
3393 [ # # ]: 0 : assert(s);
3394 : :
3395 [ # # ]: 0 : if (json_variant_is_null(variant)) {
3396 : 0 : *s = mfree(*s);
3397 : 0 : return 0;
3398 : : }
3399 : :
3400 [ # # ]: 0 : if (!json_variant_is_string(variant))
3401 [ # # ]: 0 : return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
3402 : :
3403 : 0 : r = free_and_strdup(s, json_variant_string(variant));
3404 [ # # ]: 0 : if (r < 0)
3405 [ # # ]: 0 : return json_log(variant, flags, r, "Failed to allocate string: %m");
3406 : :
3407 : 0 : return 0;
3408 : : }
3409 : :
3410 : 0 : int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3411 : 0 : _cleanup_strv_free_ char **l = NULL;
3412 : 0 : char ***s = userdata;
3413 : : JsonVariant *e;
3414 : : int r;
3415 : :
3416 [ # # ]: 0 : assert(variant);
3417 [ # # ]: 0 : assert(s);
3418 : :
3419 [ # # ]: 0 : if (json_variant_is_null(variant)) {
3420 : 0 : *s = strv_free(*s);
3421 : 0 : return 0;
3422 : : }
3423 : :
3424 [ # # ]: 0 : if (!json_variant_is_array(variant))
3425 [ # # ]: 0 : return json_log(variant, SYNTHETIC_ERRNO(EINVAL), flags, "JSON field '%s' is not an array.", strna(name));
3426 : :
3427 [ # # # # : 0 : JSON_VARIANT_ARRAY_FOREACH(e, variant) {
# # ]
3428 [ # # ]: 0 : if (!json_variant_is_string(e))
3429 [ # # ]: 0 : return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
3430 : :
3431 : 0 : r = strv_extend(&l, json_variant_string(e));
3432 [ # # ]: 0 : if (r < 0)
3433 [ # # ]: 0 : return json_log(e, flags, r, "Failed to append array element: %m");
3434 : : }
3435 : :
3436 : 0 : strv_free_and_replace(*s, l);
3437 : 0 : return 0;
3438 : : }
3439 : :
3440 : 0 : int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
3441 : 0 : JsonVariant **p = userdata;
3442 : :
3443 [ # # ]: 0 : assert(variant);
3444 [ # # ]: 0 : assert(p);
3445 : :
3446 : 0 : json_variant_unref(*p);
3447 : 0 : *p = json_variant_ref(variant);
3448 : :
3449 : 0 : return 0;
3450 : : }
3451 : :
3452 : : static const char* const json_variant_type_table[_JSON_VARIANT_TYPE_MAX] = {
3453 : : [JSON_VARIANT_STRING] = "string",
3454 : : [JSON_VARIANT_INTEGER] = "integer",
3455 : : [JSON_VARIANT_UNSIGNED] = "unsigned",
3456 : : [JSON_VARIANT_REAL] = "real",
3457 : : [JSON_VARIANT_NUMBER] = "number",
3458 : : [JSON_VARIANT_BOOLEAN] = "boolean",
3459 : : [JSON_VARIANT_ARRAY] = "array",
3460 : : [JSON_VARIANT_OBJECT] = "object",
3461 : : [JSON_VARIANT_NULL] = "null",
3462 : : };
3463 : :
3464 [ # # # # ]: 0 : DEFINE_STRING_TABLE_LOOKUP(json_variant_type, JsonVariantType);
|