1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2016 Arun Raghavan <mail@arunraghavan.net>
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <math.h>
25
26 #include <pulse/xmalloc.h>
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/hashmap.h>
29 #include <pulsecore/json.h>
30 #include <pulsecore/strbuf.h>
31
32 #define MAX_NESTING_DEPTH 20 /* Arbitrary number to make sure we don't have a stack overflow */
33
34 struct pa_json_object {
35 pa_json_type type;
36
37 union {
38 int64_t int_value;
39 double double_value;
40 bool bool_value;
41 char *string_value;
42 pa_hashmap *object_values; /* name -> object */
43 pa_idxset *array_values; /* objects */
44 };
45 };
46
47 /* JSON encoder context type */
48 typedef enum pa_json_context_type {
49 /* Top-level context of empty encoder. JSON element can be added. */
50 PA_JSON_CONTEXT_EMPTY = 0,
51 /* Top-level context of encoder with an element. JSON element cannot be added. */
52 PA_JSON_CONTEXT_TOP = 1,
53 /* JSON array context. JSON elements can be added. */
54 PA_JSON_CONTEXT_ARRAY = 2,
55 /* JSON object context. JSON object members can be added. */
56 PA_JSON_CONTEXT_OBJECT = 3,
57 } pa_json_context_type_t;
58
59 typedef struct encoder_context {
60 pa_json_context_type_t type;
61 int counter;
62 struct encoder_context *next;
63 } encoder_context;
64
65 /* JSON encoder structure, a wrapper for pa_strbuf and encoder context */
66 struct pa_json_encoder {
67 pa_strbuf *buffer;
68 encoder_context *context;
69 };
70
71 static const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth);
72
json_object_new(void)73 static pa_json_object* json_object_new(void) {
74 pa_json_object *obj;
75
76 obj = pa_xnew0(pa_json_object, 1);
77
78 return obj;
79 }
80
is_whitespace(char c)81 static bool is_whitespace(char c) {
82 return c == '\t' || c == '\n' || c == '\r' || c == ' ';
83 }
84
is_digit(char c)85 static bool is_digit(char c) {
86 return c >= '0' && c <= '9';
87 }
88
is_end(const char c,const char * end)89 static bool is_end(const char c, const char *end) {
90 if (!end)
91 return c == '\0';
92 else {
93 while (*end) {
94 if (c == *end)
95 return true;
96 end++;
97 }
98 }
99
100 return false;
101 }
102
consume_string(const char * str,const char * expect)103 static const char* consume_string(const char *str, const char *expect) {
104 while (*expect) {
105 if (*str != *expect)
106 return NULL;
107
108 str++;
109 expect++;
110 }
111
112 return str;
113 }
114
parse_null(const char * str,pa_json_object * obj)115 static const char* parse_null(const char *str, pa_json_object *obj) {
116 str = consume_string(str, "null");
117
118 if (str)
119 obj->type = PA_JSON_TYPE_NULL;
120
121 return str;
122 }
123
parse_boolean(const char * str,pa_json_object * obj)124 static const char* parse_boolean(const char *str, pa_json_object *obj) {
125 const char *tmp;
126
127 tmp = consume_string(str, "true");
128
129 if (tmp) {
130 obj->type = PA_JSON_TYPE_BOOL;
131 obj->bool_value = true;
132 } else {
133 tmp = consume_string(str, "false");
134
135 if (str) {
136 obj->type = PA_JSON_TYPE_BOOL;
137 obj->bool_value = false;
138 }
139 }
140
141 return tmp;
142 }
143
parse_string(const char * str,pa_json_object * obj)144 static const char* parse_string(const char *str, pa_json_object *obj) {
145 pa_strbuf *buf = pa_strbuf_new();
146
147 str++; /* Consume leading '"' */
148
149 while (*str && *str != '"') {
150 if (*str != '\\') {
151 /* We only accept ASCII printable characters. */
152 if (*str < 0x20 || *str > 0x7E) {
153 pa_log("Invalid non-ASCII character: 0x%x", (unsigned int) *str);
154 goto error;
155 }
156
157 /* Normal character, juts consume */
158 pa_strbuf_putc(buf, *str);
159 } else {
160 /* Need to unescape */
161 str++;
162
163 switch (*str) {
164 case '"':
165 case '\\':
166 case '/':
167 pa_strbuf_putc(buf, *str);
168 break;
169
170 case 'b':
171 pa_strbuf_putc(buf, '\b' /* backspace */);
172 break;
173
174 case 'f':
175 pa_strbuf_putc(buf, '\f' /* form feed */);
176 break;
177
178 case 'n':
179 pa_strbuf_putc(buf, '\n' /* new line */);
180 break;
181
182 case 'r':
183 pa_strbuf_putc(buf, '\r' /* carriage return */);
184 break;
185
186 case 't':
187 pa_strbuf_putc(buf, '\t' /* horizontal tab */);
188 break;
189
190 case 'u':
191 pa_log("Unicode code points are currently unsupported");
192 goto error;
193
194 default:
195 pa_log("Unexpected escape value: %c", *str);
196 goto error;
197 }
198 }
199
200 str++;
201 }
202
203 if (*str != '"') {
204 pa_log("Failed to parse remainder of string: %s", str);
205 goto error;
206 }
207
208 str++;
209
210 obj->type = PA_JSON_TYPE_STRING;
211 obj->string_value = pa_strbuf_to_string_free(buf);
212
213 return str;
214
215 error:
216 pa_strbuf_free(buf);
217 return NULL;
218 }
219
parse_number(const char * str,pa_json_object * obj)220 static const char* parse_number(const char *str, pa_json_object *obj) {
221 bool has_fraction = false, has_exponent = false, valid = false;
222 char *candidate = NULL;
223 const char *s = str;
224
225 if (*s == '-')
226 s++;
227
228 if (*s == '0') {
229 valid = true;
230 s++;
231 goto fraction;
232 }
233
234 while (is_digit(*s)) {
235 valid = true;
236 s++;
237 }
238
239 fraction:
240
241 if (!valid) {
242 pa_log("Missing digits while parsing number");
243 goto error;
244 }
245
246 if (*s == '.') {
247 has_fraction = true;
248 s++;
249 valid = false;
250
251 while (is_digit(*s)) {
252 valid = true;
253 s++;
254 }
255
256 if (!valid) {
257 pa_log("No digit after '.' while parsing fraction");
258 goto error;
259 }
260 }
261
262 if (*s == 'e' || *s == 'E') {
263 has_exponent = true;
264 s++;
265 valid = false;
266
267 if (*s == '-' || *s == '+')
268 s++;
269
270 while (is_digit(*s)) {
271 valid = true;
272 s++;
273 }
274
275 if (!valid) {
276 pa_log("No digit in exponent while parsing fraction");
277 goto error;
278 }
279 }
280
281 /* Number format looks good, now try to extract the value.
282 * Here 's' points just after the string which will be consumed. */
283
284 candidate = pa_xstrndup(str, s - str);
285
286 if (has_fraction || has_exponent) {
287 if (pa_atod(candidate, &obj->double_value) < 0) {
288 pa_log("Cannot convert string '%s' to double value", str);
289 goto error;
290 }
291 obj->type = PA_JSON_TYPE_DOUBLE;
292 } else {
293 if (pa_atoi64(candidate, &obj->int_value) < 0) {
294 pa_log("Cannot convert string '%s' to int64_t value", str);
295 goto error;
296 }
297 obj->type = PA_JSON_TYPE_INT;
298 }
299
300 pa_xfree(candidate);
301
302 return s;
303
304 error:
305 pa_xfree(candidate);
306 return NULL;
307 }
308
parse_object(const char * str,pa_json_object * obj,unsigned int depth)309 static const char *parse_object(const char *str, pa_json_object *obj, unsigned int depth) {
310 pa_json_object *name = NULL, *value = NULL;
311
312 obj->object_values = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
313 pa_xfree, (pa_free_cb_t) pa_json_object_free);
314
315 while (*str != '}') {
316 str++; /* Consume leading '{' or ',' */
317
318 str = parse_value(str, ":", &name, depth + 1);
319 if (!str || pa_json_object_get_type(name) != PA_JSON_TYPE_STRING) {
320 pa_log("Could not parse key for object");
321 goto error;
322 }
323
324 /* Consume the ':' */
325 str++;
326
327 str = parse_value(str, ",}", &value, depth + 1);
328 if (!str) {
329 pa_log("Could not parse value for object");
330 goto error;
331 }
332
333 pa_hashmap_put(obj->object_values, pa_xstrdup(pa_json_object_get_string(name)), value);
334 pa_json_object_free(name);
335
336 name = NULL;
337 value = NULL;
338 }
339
340 /* Drop trailing '}' */
341 str++;
342
343 /* We now know the value was correctly parsed */
344 obj->type = PA_JSON_TYPE_OBJECT;
345
346 return str;
347
348 error:
349 pa_hashmap_free(obj->object_values);
350 obj->object_values = NULL;
351
352 if (name)
353 pa_json_object_free(name);
354 if (value)
355 pa_json_object_free(value);
356
357 return NULL;
358 }
359
parse_array(const char * str,pa_json_object * obj,unsigned int depth)360 static const char *parse_array(const char *str, pa_json_object *obj, unsigned int depth) {
361 pa_json_object *value;
362
363 obj->array_values = pa_idxset_new(NULL, NULL);
364
365 while (*str != ']') {
366 str++; /* Consume leading '[' or ',' */
367
368 /* Need to chew up whitespaces as a special case to deal with the
369 * possibility of an empty array */
370 while (is_whitespace(*str))
371 str++;
372
373 if (*str == ']')
374 break;
375
376 str = parse_value(str, ",]", &value, depth + 1);
377 if (!str) {
378 pa_log("Could not parse value for array");
379 goto error;
380 }
381
382 pa_idxset_put(obj->array_values, value, NULL);
383 }
384
385 /* Drop trailing ']' */
386 str++;
387
388 /* We now know the value was correctly parsed */
389 obj->type = PA_JSON_TYPE_ARRAY;
390
391 return str;
392
393 error:
394 pa_idxset_free(obj->array_values, (pa_free_cb_t) pa_json_object_free);
395 obj->array_values = NULL;
396 return NULL;
397 }
398
399 typedef enum {
400 JSON_PARSER_STATE_INIT,
401 JSON_PARSER_STATE_FINISH,
402 } json_parser_state;
403
parse_value(const char * str,const char * end,pa_json_object ** obj,unsigned int depth)404 static const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth) {
405 json_parser_state state = JSON_PARSER_STATE_INIT;
406 pa_json_object *o;
407
408 pa_assert(str != NULL);
409
410 o = json_object_new();
411
412 if (depth > MAX_NESTING_DEPTH) {
413 pa_log("Exceeded maximum permitted nesting depth of objects (%u)", MAX_NESTING_DEPTH);
414 goto error;
415 }
416
417 while (!is_end(*str, end)) {
418 switch (state) {
419 case JSON_PARSER_STATE_INIT:
420 if (is_whitespace(*str)) {
421 str++;
422 } else if (*str == 'n') {
423 str = parse_null(str, o);
424 state = JSON_PARSER_STATE_FINISH;
425 } else if (*str == 't' || *str == 'f') {
426 str = parse_boolean(str, o);
427 state = JSON_PARSER_STATE_FINISH;
428 } else if (*str == '"') {
429 str = parse_string(str, o);
430 state = JSON_PARSER_STATE_FINISH;
431 } else if (is_digit(*str) || *str == '-') {
432 str = parse_number(str, o);
433 state = JSON_PARSER_STATE_FINISH;
434 } else if (*str == '{') {
435 str = parse_object(str, o, depth);
436 state = JSON_PARSER_STATE_FINISH;
437 } else if (*str == '[') {
438 str = parse_array(str, o, depth);
439 state = JSON_PARSER_STATE_FINISH;
440 } else {
441 pa_log("Invalid JSON string: %s", str);
442 goto error;
443 }
444
445 if (!str)
446 goto error;
447
448 break;
449
450 case JSON_PARSER_STATE_FINISH:
451 /* Consume trailing whitespaces */
452 if (is_whitespace(*str)) {
453 str++;
454 } else {
455 goto error;
456 }
457 }
458 }
459
460 if (pa_json_object_get_type(o) == PA_JSON_TYPE_INIT) {
461 /* We didn't actually get any data */
462 pa_log("No data while parsing json string: '%s' till '%s'", str, pa_strnull(end));
463 goto error;
464 }
465
466 *obj = o;
467
468 return str;
469
470 error:
471 pa_json_object_free(o);
472 return NULL;
473 }
474
475
pa_json_parse(const char * str)476 pa_json_object* pa_json_parse(const char *str) {
477 pa_json_object *obj;
478
479 str = parse_value(str, NULL, &obj, 0);
480
481 if (!str) {
482 pa_log("JSON parsing failed");
483 return NULL;
484 }
485
486 if (*str != '\0') {
487 pa_log("Unable to parse complete JSON string, remainder is: %s", str);
488 pa_json_object_free(obj);
489 return NULL;
490 }
491
492 return obj;
493 }
494
pa_json_object_get_type(const pa_json_object * obj)495 pa_json_type pa_json_object_get_type(const pa_json_object *obj) {
496 return obj->type;
497 }
498
pa_json_object_free(pa_json_object * obj)499 void pa_json_object_free(pa_json_object *obj) {
500
501 switch (pa_json_object_get_type(obj)) {
502 case PA_JSON_TYPE_INIT:
503 case PA_JSON_TYPE_INT:
504 case PA_JSON_TYPE_DOUBLE:
505 case PA_JSON_TYPE_BOOL:
506 case PA_JSON_TYPE_NULL:
507 break;
508
509 case PA_JSON_TYPE_STRING:
510 pa_xfree(obj->string_value);
511 break;
512
513 case PA_JSON_TYPE_OBJECT:
514 pa_hashmap_free(obj->object_values);
515 break;
516
517 case PA_JSON_TYPE_ARRAY:
518 pa_idxset_free(obj->array_values, (pa_free_cb_t) pa_json_object_free);
519 break;
520
521 default:
522 pa_assert_not_reached();
523 }
524
525 pa_xfree(obj);
526 }
527
pa_json_object_get_int(const pa_json_object * o)528 int64_t pa_json_object_get_int(const pa_json_object *o) {
529 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_INT);
530 return o->int_value;
531 }
532
pa_json_object_get_double(const pa_json_object * o)533 double pa_json_object_get_double(const pa_json_object *o) {
534 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_DOUBLE);
535 return o->double_value;
536 }
537
pa_json_object_get_bool(const pa_json_object * o)538 bool pa_json_object_get_bool(const pa_json_object *o) {
539 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_BOOL);
540 return o->bool_value;
541 }
542
pa_json_object_get_string(const pa_json_object * o)543 const char* pa_json_object_get_string(const pa_json_object *o) {
544 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_STRING);
545 return o->string_value;
546 }
547
pa_json_object_get_object_member(const pa_json_object * o,const char * name)548 const pa_json_object* pa_json_object_get_object_member(const pa_json_object *o, const char *name) {
549 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_OBJECT);
550 return pa_hashmap_get(o->object_values, name);
551 }
552
pa_json_object_get_object_member_hashmap(const pa_json_object * o)553 const pa_hashmap *pa_json_object_get_object_member_hashmap(const pa_json_object *o) {
554 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_OBJECT);
555 return o->object_values;
556 }
557
pa_json_object_get_array_length(const pa_json_object * o)558 int pa_json_object_get_array_length(const pa_json_object *o) {
559 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_ARRAY);
560 return pa_idxset_size(o->array_values);
561 }
562
pa_json_object_get_array_member(const pa_json_object * o,int index)563 const pa_json_object* pa_json_object_get_array_member(const pa_json_object *o, int index) {
564 pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_ARRAY);
565 return pa_idxset_get_by_index(o->array_values, index);
566 }
567
pa_json_object_equal(const pa_json_object * o1,const pa_json_object * o2)568 bool pa_json_object_equal(const pa_json_object *o1, const pa_json_object *o2) {
569 int i;
570
571 if (pa_json_object_get_type(o1) != pa_json_object_get_type(o2))
572 return false;
573
574 switch (pa_json_object_get_type(o1)) {
575 case PA_JSON_TYPE_NULL:
576 return true;
577
578 case PA_JSON_TYPE_BOOL:
579 return o1->bool_value == o2->bool_value;
580
581 case PA_JSON_TYPE_INT:
582 return o1->int_value == o2->int_value;
583
584 case PA_JSON_TYPE_DOUBLE:
585 return PA_DOUBLE_IS_EQUAL(o1->double_value, o2->double_value);
586
587 case PA_JSON_TYPE_STRING:
588 return pa_streq(o1->string_value, o2->string_value);
589
590 case PA_JSON_TYPE_ARRAY:
591 if (pa_json_object_get_array_length(o1) != pa_json_object_get_array_length(o2))
592 return false;
593
594 for (i = 0; i < pa_json_object_get_array_length(o1); i++) {
595 if (!pa_json_object_equal(pa_json_object_get_array_member(o1, i),
596 pa_json_object_get_array_member(o2, i)))
597 return false;
598 }
599
600 return true;
601
602 case PA_JSON_TYPE_OBJECT: {
603 void *state;
604 const char *key;
605 const pa_json_object *v1, *v2;
606
607 if (pa_hashmap_size(o1->object_values) != pa_hashmap_size(o2->object_values))
608 return false;
609
610 PA_HASHMAP_FOREACH_KV(key, v1, o1->object_values, state) {
611 v2 = pa_json_object_get_object_member(o2, key);
612 if (!v2 || !pa_json_object_equal(v1, v2))
613 return false;
614 }
615
616 return true;
617 }
618
619 default:
620 pa_assert_not_reached();
621 }
622 }
623
624 /* Write functions. The functions are wrapper functions around pa_strbuf,
625 * so that the client does not need to use pa_strbuf directly. */
626
json_encoder_context_push(pa_json_encoder * encoder,pa_json_context_type_t type)627 static void json_encoder_context_push(pa_json_encoder *encoder, pa_json_context_type_t type) {
628 pa_assert(encoder);
629
630 encoder_context *head = pa_xnew0(encoder_context, 1);
631 head->type = type;
632 head->next = encoder->context;
633 encoder->context = head;
634 }
635
636 /* Returns type of context popped off encoder context stack. */
json_encoder_context_pop(pa_json_encoder * encoder)637 static pa_json_context_type_t json_encoder_context_pop(pa_json_encoder *encoder) {
638 encoder_context *head;
639 pa_json_context_type_t type;
640
641 pa_assert(encoder);
642 pa_assert(encoder->context);
643
644 type = encoder->context->type;
645
646 head = encoder->context->next;
647 pa_xfree(encoder->context);
648 encoder->context = head;
649
650 return type;
651 }
652
pa_json_encoder_is_empty(pa_json_encoder * encoder)653 bool pa_json_encoder_is_empty(pa_json_encoder *encoder) {
654 pa_json_context_type_t type;
655
656 pa_assert(encoder);
657 pa_assert(encoder->context);
658
659 type = encoder->context->type;
660 return type == PA_JSON_CONTEXT_EMPTY;
661 }
662
pa_json_encoder_new(void)663 pa_json_encoder *pa_json_encoder_new(void) {
664 pa_json_encoder *encoder;
665
666 encoder = pa_xnew(pa_json_encoder, 1);
667 encoder->buffer = pa_strbuf_new();
668
669 encoder->context = NULL;
670 json_encoder_context_push(encoder, PA_JSON_CONTEXT_EMPTY);
671
672 return encoder;
673 }
674
pa_json_encoder_free(pa_json_encoder * encoder)675 void pa_json_encoder_free(pa_json_encoder *encoder) {
676 pa_json_context_type_t type;
677 pa_assert(encoder);
678
679 /* should have exactly one encoder context left at this point */
680 pa_assert(encoder->context);
681 type = json_encoder_context_pop(encoder);
682 pa_assert(encoder->context == NULL);
683
684 pa_assert(type == PA_JSON_CONTEXT_TOP || type == PA_JSON_CONTEXT_EMPTY);
685 if (type == PA_JSON_CONTEXT_EMPTY)
686 pa_log_warn("JSON encoder is empty.");
687
688 if (encoder->buffer)
689 pa_strbuf_free(encoder->buffer);
690
691 pa_xfree(encoder);
692 }
693
pa_json_encoder_to_string_free(pa_json_encoder * encoder)694 char *pa_json_encoder_to_string_free(pa_json_encoder *encoder) {
695 char *result;
696
697 pa_assert(encoder);
698
699 result = pa_strbuf_to_string_free(encoder->buffer);
700
701 encoder->buffer = NULL;
702 pa_json_encoder_free(encoder);
703
704 return result;
705 }
706
json_encoder_insert_delimiter(pa_json_encoder * encoder)707 static void json_encoder_insert_delimiter(pa_json_encoder *encoder) {
708 pa_assert(encoder);
709
710 if (encoder->context->counter++)
711 pa_strbuf_putc(encoder->buffer, ',');
712 }
713
714 /* Escapes p to create valid JSON string.
715 * The caller has to free the returned string. */
pa_json_escape(const char * p)716 static char *pa_json_escape(const char *p) {
717 const char *s;
718 char *out_string, *output;
719 int char_count = strlen(p);
720
721 /* Maximum number of characters in output string
722 * including trailing 0. */
723 char_count = 2 * char_count + 1;
724
725 /* allocate output string */
726 out_string = pa_xmalloc(char_count);
727 output = out_string;
728
729 /* write output string */
730 for (s = p; *s; ++s) {
731 switch (*s) {
732 case '"':
733 *output++ = '\\';
734 *output++ = '"';
735 break;
736 case '\\':
737 *output++ = '\\';
738 *output++ = '\\';
739 break;
740 case '\b':
741 *output++ = '\\';
742 *output++ = 'b';
743 break;
744
745 case '\f':
746 *output++ = '\\';
747 *output++ = 'f';
748 break;
749
750 case '\n':
751 *output++ = '\\';
752 *output++ = 'n';
753 break;
754
755 case '\r':
756 *output++ = '\\';
757 *output++ = 'r';
758 break;
759
760 case '\t':
761 *output++ = '\\';
762 *output++ = 't';
763 break;
764 default:
765 if (*s < 0x20 || *s > 0x7E) {
766 pa_log("Invalid non-ASCII character: 0x%x", (unsigned int) *s);
767 pa_xfree(out_string);
768 return NULL;
769 }
770 *output++ = *s;
771 break;
772 }
773 }
774
775 *output = 0;
776
777 return out_string;
778 }
779
json_write_string_escaped(pa_json_encoder * encoder,const char * value)780 static void json_write_string_escaped(pa_json_encoder *encoder, const char *value) {
781 char *escaped_value;
782
783 pa_assert(encoder);
784
785 escaped_value = pa_json_escape(value);
786 pa_strbuf_printf(encoder->buffer, "\"%s\"", escaped_value);
787 pa_xfree(escaped_value);
788 }
789
790 /* Writes an opening curly brace */
pa_json_encoder_begin_element_object(pa_json_encoder * encoder)791 void pa_json_encoder_begin_element_object(pa_json_encoder *encoder) {
792 pa_assert(encoder);
793 pa_assert(encoder->context->type != PA_JSON_CONTEXT_TOP);
794
795 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
796 encoder->context->type = PA_JSON_CONTEXT_TOP;
797
798 json_encoder_insert_delimiter(encoder);
799 pa_strbuf_putc(encoder->buffer, '{');
800
801 json_encoder_context_push(encoder, PA_JSON_CONTEXT_OBJECT);
802 }
803
804 /* Writes an opening curly brace */
pa_json_encoder_begin_member_object(pa_json_encoder * encoder,const char * name)805 void pa_json_encoder_begin_member_object(pa_json_encoder *encoder, const char *name) {
806 pa_assert(encoder);
807 pa_assert(encoder->context);
808 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
809 pa_assert(name && name[0]);
810
811 json_encoder_insert_delimiter(encoder);
812
813 json_write_string_escaped(encoder, name);
814 pa_strbuf_putc(encoder->buffer, ':');
815
816 pa_strbuf_putc(encoder->buffer, '{');
817
818 json_encoder_context_push(encoder, PA_JSON_CONTEXT_OBJECT);
819 }
820
821 /* Writes a closing curly brace */
pa_json_encoder_end_object(pa_json_encoder * encoder)822 void pa_json_encoder_end_object(pa_json_encoder *encoder) {
823 pa_json_context_type_t type;
824 pa_assert(encoder);
825
826 type = json_encoder_context_pop(encoder);
827 pa_assert(type == PA_JSON_CONTEXT_OBJECT);
828
829 pa_strbuf_putc(encoder->buffer, '}');
830 }
831
832 /* Writes an opening bracket */
pa_json_encoder_begin_element_array(pa_json_encoder * encoder)833 void pa_json_encoder_begin_element_array(pa_json_encoder *encoder) {
834 pa_assert(encoder);
835 pa_assert(encoder->context);
836 pa_assert(encoder->context->type != PA_JSON_CONTEXT_TOP);
837
838 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
839 encoder->context->type = PA_JSON_CONTEXT_TOP;
840
841 json_encoder_insert_delimiter(encoder);
842 pa_strbuf_putc(encoder->buffer, '[');
843
844 json_encoder_context_push(encoder, PA_JSON_CONTEXT_ARRAY);
845 }
846
847 /* Writes member name and an opening bracket */
pa_json_encoder_begin_member_array(pa_json_encoder * encoder,const char * name)848 void pa_json_encoder_begin_member_array(pa_json_encoder *encoder, const char *name) {
849 pa_assert(encoder);
850 pa_assert(encoder->context);
851 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
852 pa_assert(name && name[0]);
853
854 json_encoder_insert_delimiter(encoder);
855
856 json_write_string_escaped(encoder, name);
857 pa_strbuf_putc(encoder->buffer, ':');
858
859 pa_strbuf_putc(encoder->buffer, '[');
860
861 json_encoder_context_push(encoder, PA_JSON_CONTEXT_ARRAY);
862 }
863
864 /* Writes a closing bracket */
pa_json_encoder_end_array(pa_json_encoder * encoder)865 void pa_json_encoder_end_array(pa_json_encoder *encoder) {
866 pa_json_context_type_t type;
867 pa_assert(encoder);
868
869 type = json_encoder_context_pop(encoder);
870 pa_assert(type == PA_JSON_CONTEXT_ARRAY);
871
872 pa_strbuf_putc(encoder->buffer, ']');
873 }
874
pa_json_encoder_add_element_string(pa_json_encoder * encoder,const char * value)875 void pa_json_encoder_add_element_string(pa_json_encoder *encoder, const char *value) {
876 pa_assert(encoder);
877 pa_assert(encoder->context);
878 pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY);
879
880 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
881 encoder->context->type = PA_JSON_CONTEXT_TOP;
882
883 json_encoder_insert_delimiter(encoder);
884
885 json_write_string_escaped(encoder, value);
886 }
887
pa_json_encoder_add_member_string(pa_json_encoder * encoder,const char * name,const char * value)888 void pa_json_encoder_add_member_string(pa_json_encoder *encoder, const char *name, const char *value) {
889 pa_assert(encoder);
890 pa_assert(encoder->context);
891 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
892 pa_assert(name && name[0]);
893
894 json_encoder_insert_delimiter(encoder);
895
896 json_write_string_escaped(encoder, name);
897
898 pa_strbuf_putc(encoder->buffer, ':');
899
900 /* Null value is written as empty element */
901 if (!value)
902 value = "";
903
904 json_write_string_escaped(encoder, value);
905 }
906
json_write_null(pa_json_encoder * encoder)907 static void json_write_null(pa_json_encoder *encoder) {
908 pa_assert(encoder);
909
910 pa_strbuf_puts(encoder->buffer, "null");
911 }
912
pa_json_encoder_add_element_null(pa_json_encoder * encoder)913 void pa_json_encoder_add_element_null(pa_json_encoder *encoder) {
914 pa_assert(encoder);
915 pa_assert(encoder->context);
916 pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY);
917
918 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
919 encoder->context->type = PA_JSON_CONTEXT_TOP;
920
921 json_encoder_insert_delimiter(encoder);
922
923 json_write_null(encoder);
924 }
925
pa_json_encoder_add_member_null(pa_json_encoder * encoder,const char * name)926 void pa_json_encoder_add_member_null(pa_json_encoder *encoder, const char *name) {
927 pa_assert(encoder);
928 pa_assert(encoder->context);
929 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
930 pa_assert(name && name[0]);
931
932 json_encoder_insert_delimiter(encoder);
933
934 json_write_string_escaped(encoder, name);
935 pa_strbuf_putc(encoder->buffer, ':');
936
937 json_write_null(encoder);
938 }
939
json_write_bool(pa_json_encoder * encoder,bool value)940 static void json_write_bool(pa_json_encoder *encoder, bool value) {
941 pa_assert(encoder);
942
943 pa_strbuf_puts(encoder->buffer, value ? "true" : "false");
944 }
945
pa_json_encoder_add_element_bool(pa_json_encoder * encoder,bool value)946 void pa_json_encoder_add_element_bool(pa_json_encoder *encoder, bool value) {
947 pa_assert(encoder);
948 pa_assert(encoder->context);
949 pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY);
950
951 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
952 encoder->context->type = PA_JSON_CONTEXT_TOP;
953
954 json_encoder_insert_delimiter(encoder);
955
956 json_write_bool(encoder, value);
957 }
958
pa_json_encoder_add_member_bool(pa_json_encoder * encoder,const char * name,bool value)959 void pa_json_encoder_add_member_bool(pa_json_encoder *encoder, const char *name, bool value) {
960 pa_assert(encoder);
961 pa_assert(encoder->context);
962 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
963 pa_assert(name && name[0]);
964
965 json_encoder_insert_delimiter(encoder);
966
967 json_write_string_escaped(encoder, name);
968
969 pa_strbuf_putc(encoder->buffer, ':');
970
971 json_write_bool(encoder, value);
972 }
973
json_write_int(pa_json_encoder * encoder,int64_t value)974 static void json_write_int(pa_json_encoder *encoder, int64_t value) {
975 pa_assert(encoder);
976
977 pa_strbuf_printf(encoder->buffer, "%"PRId64, value);
978 }
979
pa_json_encoder_add_element_int(pa_json_encoder * encoder,int64_t value)980 void pa_json_encoder_add_element_int(pa_json_encoder *encoder, int64_t value) {
981 pa_assert(encoder);
982 pa_assert(encoder->context);
983 pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY);
984
985 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
986 encoder->context->type = PA_JSON_CONTEXT_TOP;
987
988 json_encoder_insert_delimiter(encoder);
989
990 json_write_int(encoder, value);
991 }
992
pa_json_encoder_add_member_int(pa_json_encoder * encoder,const char * name,int64_t value)993 void pa_json_encoder_add_member_int(pa_json_encoder *encoder, const char *name, int64_t value) {
994 pa_assert(encoder);
995 pa_assert(encoder->context);
996 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
997 pa_assert(name && name[0]);
998
999 json_encoder_insert_delimiter(encoder);
1000
1001 json_write_string_escaped(encoder, name);
1002
1003 pa_strbuf_putc(encoder->buffer, ':');
1004
1005 json_write_int(encoder, value);
1006 }
1007
json_write_double(pa_json_encoder * encoder,double value,int precision)1008 static void json_write_double(pa_json_encoder *encoder, double value, int precision) {
1009 pa_assert(encoder);
1010 pa_strbuf_printf(encoder->buffer, "%.*f", precision, value);
1011 }
1012
pa_json_encoder_add_element_double(pa_json_encoder * encoder,double value,int precision)1013 void pa_json_encoder_add_element_double(pa_json_encoder *encoder, double value, int precision) {
1014 pa_assert(encoder);
1015 pa_assert(encoder->context);
1016 pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY);
1017
1018 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
1019 encoder->context->type = PA_JSON_CONTEXT_TOP;
1020
1021 json_encoder_insert_delimiter(encoder);
1022
1023 json_write_double(encoder, value, precision);
1024 }
1025
pa_json_encoder_add_member_double(pa_json_encoder * encoder,const char * name,double value,int precision)1026 void pa_json_encoder_add_member_double(pa_json_encoder *encoder, const char *name, double value, int precision) {
1027 pa_assert(encoder);
1028 pa_assert(encoder->context);
1029 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
1030 pa_assert(name && name[0]);
1031
1032 json_encoder_insert_delimiter(encoder);
1033
1034 json_write_string_escaped(encoder, name);
1035
1036 pa_strbuf_putc(encoder->buffer, ':');
1037
1038 json_write_double(encoder, value, precision);
1039 }
1040
json_write_raw(pa_json_encoder * encoder,const char * raw_string)1041 static void json_write_raw(pa_json_encoder *encoder, const char *raw_string) {
1042 pa_assert(encoder);
1043 pa_strbuf_puts(encoder->buffer, raw_string);
1044 }
1045
pa_json_encoder_add_element_raw_json(pa_json_encoder * encoder,const char * raw_json_string)1046 void pa_json_encoder_add_element_raw_json(pa_json_encoder *encoder, const char *raw_json_string) {
1047 pa_assert(encoder);
1048 pa_assert(encoder->context);
1049 pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY);
1050
1051 if (encoder->context->type == PA_JSON_CONTEXT_EMPTY)
1052 encoder->context->type = PA_JSON_CONTEXT_TOP;
1053
1054 json_encoder_insert_delimiter(encoder);
1055
1056 json_write_raw(encoder, raw_json_string);
1057 }
1058
pa_json_encoder_add_member_raw_json(pa_json_encoder * encoder,const char * name,const char * raw_json_string)1059 void pa_json_encoder_add_member_raw_json(pa_json_encoder *encoder, const char *name, const char *raw_json_string) {
1060 pa_assert(encoder);
1061 pa_assert(encoder->context);
1062 pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT);
1063 pa_assert(name && name[0]);
1064
1065 json_encoder_insert_delimiter(encoder);
1066
1067 json_write_string_escaped(encoder, name);
1068
1069 pa_strbuf_putc(encoder->buffer, ':');
1070
1071 json_write_raw(encoder, raw_json_string);
1072 }
1073