• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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