153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2016 Arun Raghavan <mail@arunraghavan.net> 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <math.h> 2553a5a1b3Sopenharmony_ci 2653a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 2753a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 2853a5a1b3Sopenharmony_ci#include <pulsecore/hashmap.h> 2953a5a1b3Sopenharmony_ci#include <pulsecore/json.h> 3053a5a1b3Sopenharmony_ci#include <pulsecore/strbuf.h> 3153a5a1b3Sopenharmony_ci 3253a5a1b3Sopenharmony_ci#define MAX_NESTING_DEPTH 20 /* Arbitrary number to make sure we don't have a stack overflow */ 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_cistruct pa_json_object { 3553a5a1b3Sopenharmony_ci pa_json_type type; 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_ci union { 3853a5a1b3Sopenharmony_ci int64_t int_value; 3953a5a1b3Sopenharmony_ci double double_value; 4053a5a1b3Sopenharmony_ci bool bool_value; 4153a5a1b3Sopenharmony_ci char *string_value; 4253a5a1b3Sopenharmony_ci pa_hashmap *object_values; /* name -> object */ 4353a5a1b3Sopenharmony_ci pa_idxset *array_values; /* objects */ 4453a5a1b3Sopenharmony_ci }; 4553a5a1b3Sopenharmony_ci}; 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_ci/* JSON encoder context type */ 4853a5a1b3Sopenharmony_citypedef enum pa_json_context_type { 4953a5a1b3Sopenharmony_ci /* Top-level context of empty encoder. JSON element can be added. */ 5053a5a1b3Sopenharmony_ci PA_JSON_CONTEXT_EMPTY = 0, 5153a5a1b3Sopenharmony_ci /* Top-level context of encoder with an element. JSON element cannot be added. */ 5253a5a1b3Sopenharmony_ci PA_JSON_CONTEXT_TOP = 1, 5353a5a1b3Sopenharmony_ci /* JSON array context. JSON elements can be added. */ 5453a5a1b3Sopenharmony_ci PA_JSON_CONTEXT_ARRAY = 2, 5553a5a1b3Sopenharmony_ci /* JSON object context. JSON object members can be added. */ 5653a5a1b3Sopenharmony_ci PA_JSON_CONTEXT_OBJECT = 3, 5753a5a1b3Sopenharmony_ci} pa_json_context_type_t; 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_citypedef struct encoder_context { 6053a5a1b3Sopenharmony_ci pa_json_context_type_t type; 6153a5a1b3Sopenharmony_ci int counter; 6253a5a1b3Sopenharmony_ci struct encoder_context *next; 6353a5a1b3Sopenharmony_ci} encoder_context; 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_ci/* JSON encoder structure, a wrapper for pa_strbuf and encoder context */ 6653a5a1b3Sopenharmony_cistruct pa_json_encoder { 6753a5a1b3Sopenharmony_ci pa_strbuf *buffer; 6853a5a1b3Sopenharmony_ci encoder_context *context; 6953a5a1b3Sopenharmony_ci}; 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_cistatic const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth); 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_cistatic pa_json_object* json_object_new(void) { 7453a5a1b3Sopenharmony_ci pa_json_object *obj; 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci obj = pa_xnew0(pa_json_object, 1); 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci return obj; 7953a5a1b3Sopenharmony_ci} 8053a5a1b3Sopenharmony_ci 8153a5a1b3Sopenharmony_cistatic bool is_whitespace(char c) { 8253a5a1b3Sopenharmony_ci return c == '\t' || c == '\n' || c == '\r' || c == ' '; 8353a5a1b3Sopenharmony_ci} 8453a5a1b3Sopenharmony_ci 8553a5a1b3Sopenharmony_cistatic bool is_digit(char c) { 8653a5a1b3Sopenharmony_ci return c >= '0' && c <= '9'; 8753a5a1b3Sopenharmony_ci} 8853a5a1b3Sopenharmony_ci 8953a5a1b3Sopenharmony_cistatic bool is_end(const char c, const char *end) { 9053a5a1b3Sopenharmony_ci if (!end) 9153a5a1b3Sopenharmony_ci return c == '\0'; 9253a5a1b3Sopenharmony_ci else { 9353a5a1b3Sopenharmony_ci while (*end) { 9453a5a1b3Sopenharmony_ci if (c == *end) 9553a5a1b3Sopenharmony_ci return true; 9653a5a1b3Sopenharmony_ci end++; 9753a5a1b3Sopenharmony_ci } 9853a5a1b3Sopenharmony_ci } 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci return false; 10153a5a1b3Sopenharmony_ci} 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_cistatic const char* consume_string(const char *str, const char *expect) { 10453a5a1b3Sopenharmony_ci while (*expect) { 10553a5a1b3Sopenharmony_ci if (*str != *expect) 10653a5a1b3Sopenharmony_ci return NULL; 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci str++; 10953a5a1b3Sopenharmony_ci expect++; 11053a5a1b3Sopenharmony_ci } 11153a5a1b3Sopenharmony_ci 11253a5a1b3Sopenharmony_ci return str; 11353a5a1b3Sopenharmony_ci} 11453a5a1b3Sopenharmony_ci 11553a5a1b3Sopenharmony_cistatic const char* parse_null(const char *str, pa_json_object *obj) { 11653a5a1b3Sopenharmony_ci str = consume_string(str, "null"); 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_ci if (str) 11953a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_NULL; 12053a5a1b3Sopenharmony_ci 12153a5a1b3Sopenharmony_ci return str; 12253a5a1b3Sopenharmony_ci} 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_cistatic const char* parse_boolean(const char *str, pa_json_object *obj) { 12553a5a1b3Sopenharmony_ci const char *tmp; 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_ci tmp = consume_string(str, "true"); 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci if (tmp) { 13053a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_BOOL; 13153a5a1b3Sopenharmony_ci obj->bool_value = true; 13253a5a1b3Sopenharmony_ci } else { 13353a5a1b3Sopenharmony_ci tmp = consume_string(str, "false"); 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_ci if (str) { 13653a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_BOOL; 13753a5a1b3Sopenharmony_ci obj->bool_value = false; 13853a5a1b3Sopenharmony_ci } 13953a5a1b3Sopenharmony_ci } 14053a5a1b3Sopenharmony_ci 14153a5a1b3Sopenharmony_ci return tmp; 14253a5a1b3Sopenharmony_ci} 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_cistatic const char* parse_string(const char *str, pa_json_object *obj) { 14553a5a1b3Sopenharmony_ci pa_strbuf *buf = pa_strbuf_new(); 14653a5a1b3Sopenharmony_ci 14753a5a1b3Sopenharmony_ci str++; /* Consume leading '"' */ 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci while (*str && *str != '"') { 15053a5a1b3Sopenharmony_ci if (*str != '\\') { 15153a5a1b3Sopenharmony_ci /* We only accept ASCII printable characters. */ 15253a5a1b3Sopenharmony_ci if (*str < 0x20 || *str > 0x7E) { 15353a5a1b3Sopenharmony_ci pa_log("Invalid non-ASCII character: 0x%x", (unsigned int) *str); 15453a5a1b3Sopenharmony_ci goto error; 15553a5a1b3Sopenharmony_ci } 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_ci /* Normal character, juts consume */ 15853a5a1b3Sopenharmony_ci pa_strbuf_putc(buf, *str); 15953a5a1b3Sopenharmony_ci } else { 16053a5a1b3Sopenharmony_ci /* Need to unescape */ 16153a5a1b3Sopenharmony_ci str++; 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci switch (*str) { 16453a5a1b3Sopenharmony_ci case '"': 16553a5a1b3Sopenharmony_ci case '\\': 16653a5a1b3Sopenharmony_ci case '/': 16753a5a1b3Sopenharmony_ci pa_strbuf_putc(buf, *str); 16853a5a1b3Sopenharmony_ci break; 16953a5a1b3Sopenharmony_ci 17053a5a1b3Sopenharmony_ci case 'b': 17153a5a1b3Sopenharmony_ci pa_strbuf_putc(buf, '\b' /* backspace */); 17253a5a1b3Sopenharmony_ci break; 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci case 'f': 17553a5a1b3Sopenharmony_ci pa_strbuf_putc(buf, '\f' /* form feed */); 17653a5a1b3Sopenharmony_ci break; 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_ci case 'n': 17953a5a1b3Sopenharmony_ci pa_strbuf_putc(buf, '\n' /* new line */); 18053a5a1b3Sopenharmony_ci break; 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci case 'r': 18353a5a1b3Sopenharmony_ci pa_strbuf_putc(buf, '\r' /* carriage return */); 18453a5a1b3Sopenharmony_ci break; 18553a5a1b3Sopenharmony_ci 18653a5a1b3Sopenharmony_ci case 't': 18753a5a1b3Sopenharmony_ci pa_strbuf_putc(buf, '\t' /* horizontal tab */); 18853a5a1b3Sopenharmony_ci break; 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_ci case 'u': 19153a5a1b3Sopenharmony_ci pa_log("Unicode code points are currently unsupported"); 19253a5a1b3Sopenharmony_ci goto error; 19353a5a1b3Sopenharmony_ci 19453a5a1b3Sopenharmony_ci default: 19553a5a1b3Sopenharmony_ci pa_log("Unexpected escape value: %c", *str); 19653a5a1b3Sopenharmony_ci goto error; 19753a5a1b3Sopenharmony_ci } 19853a5a1b3Sopenharmony_ci } 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci str++; 20153a5a1b3Sopenharmony_ci } 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci if (*str != '"') { 20453a5a1b3Sopenharmony_ci pa_log("Failed to parse remainder of string: %s", str); 20553a5a1b3Sopenharmony_ci goto error; 20653a5a1b3Sopenharmony_ci } 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci str++; 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_STRING; 21153a5a1b3Sopenharmony_ci obj->string_value = pa_strbuf_to_string_free(buf); 21253a5a1b3Sopenharmony_ci 21353a5a1b3Sopenharmony_ci return str; 21453a5a1b3Sopenharmony_ci 21553a5a1b3Sopenharmony_cierror: 21653a5a1b3Sopenharmony_ci pa_strbuf_free(buf); 21753a5a1b3Sopenharmony_ci return NULL; 21853a5a1b3Sopenharmony_ci} 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_cistatic const char* parse_number(const char *str, pa_json_object *obj) { 22153a5a1b3Sopenharmony_ci bool has_fraction = false, has_exponent = false, valid = false; 22253a5a1b3Sopenharmony_ci char *candidate = NULL; 22353a5a1b3Sopenharmony_ci const char *s = str; 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci if (*s == '-') 22653a5a1b3Sopenharmony_ci s++; 22753a5a1b3Sopenharmony_ci 22853a5a1b3Sopenharmony_ci if (*s == '0') { 22953a5a1b3Sopenharmony_ci valid = true; 23053a5a1b3Sopenharmony_ci s++; 23153a5a1b3Sopenharmony_ci goto fraction; 23253a5a1b3Sopenharmony_ci } 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci while (is_digit(*s)) { 23553a5a1b3Sopenharmony_ci valid = true; 23653a5a1b3Sopenharmony_ci s++; 23753a5a1b3Sopenharmony_ci } 23853a5a1b3Sopenharmony_ci 23953a5a1b3Sopenharmony_cifraction: 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci if (!valid) { 24253a5a1b3Sopenharmony_ci pa_log("Missing digits while parsing number"); 24353a5a1b3Sopenharmony_ci goto error; 24453a5a1b3Sopenharmony_ci } 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ci if (*s == '.') { 24753a5a1b3Sopenharmony_ci has_fraction = true; 24853a5a1b3Sopenharmony_ci s++; 24953a5a1b3Sopenharmony_ci valid = false; 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci while (is_digit(*s)) { 25253a5a1b3Sopenharmony_ci valid = true; 25353a5a1b3Sopenharmony_ci s++; 25453a5a1b3Sopenharmony_ci } 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci if (!valid) { 25753a5a1b3Sopenharmony_ci pa_log("No digit after '.' while parsing fraction"); 25853a5a1b3Sopenharmony_ci goto error; 25953a5a1b3Sopenharmony_ci } 26053a5a1b3Sopenharmony_ci } 26153a5a1b3Sopenharmony_ci 26253a5a1b3Sopenharmony_ci if (*s == 'e' || *s == 'E') { 26353a5a1b3Sopenharmony_ci has_exponent = true; 26453a5a1b3Sopenharmony_ci s++; 26553a5a1b3Sopenharmony_ci valid = false; 26653a5a1b3Sopenharmony_ci 26753a5a1b3Sopenharmony_ci if (*s == '-' || *s == '+') 26853a5a1b3Sopenharmony_ci s++; 26953a5a1b3Sopenharmony_ci 27053a5a1b3Sopenharmony_ci while (is_digit(*s)) { 27153a5a1b3Sopenharmony_ci valid = true; 27253a5a1b3Sopenharmony_ci s++; 27353a5a1b3Sopenharmony_ci } 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci if (!valid) { 27653a5a1b3Sopenharmony_ci pa_log("No digit in exponent while parsing fraction"); 27753a5a1b3Sopenharmony_ci goto error; 27853a5a1b3Sopenharmony_ci } 27953a5a1b3Sopenharmony_ci } 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci /* Number format looks good, now try to extract the value. 28253a5a1b3Sopenharmony_ci * Here 's' points just after the string which will be consumed. */ 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci candidate = pa_xstrndup(str, s - str); 28553a5a1b3Sopenharmony_ci 28653a5a1b3Sopenharmony_ci if (has_fraction || has_exponent) { 28753a5a1b3Sopenharmony_ci if (pa_atod(candidate, &obj->double_value) < 0) { 28853a5a1b3Sopenharmony_ci pa_log("Cannot convert string '%s' to double value", str); 28953a5a1b3Sopenharmony_ci goto error; 29053a5a1b3Sopenharmony_ci } 29153a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_DOUBLE; 29253a5a1b3Sopenharmony_ci } else { 29353a5a1b3Sopenharmony_ci if (pa_atoi64(candidate, &obj->int_value) < 0) { 29453a5a1b3Sopenharmony_ci pa_log("Cannot convert string '%s' to int64_t value", str); 29553a5a1b3Sopenharmony_ci goto error; 29653a5a1b3Sopenharmony_ci } 29753a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_INT; 29853a5a1b3Sopenharmony_ci } 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_ci pa_xfree(candidate); 30153a5a1b3Sopenharmony_ci 30253a5a1b3Sopenharmony_ci return s; 30353a5a1b3Sopenharmony_ci 30453a5a1b3Sopenharmony_cierror: 30553a5a1b3Sopenharmony_ci pa_xfree(candidate); 30653a5a1b3Sopenharmony_ci return NULL; 30753a5a1b3Sopenharmony_ci} 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_cistatic const char *parse_object(const char *str, pa_json_object *obj, unsigned int depth) { 31053a5a1b3Sopenharmony_ci pa_json_object *name = NULL, *value = NULL; 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_ci obj->object_values = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, 31353a5a1b3Sopenharmony_ci pa_xfree, (pa_free_cb_t) pa_json_object_free); 31453a5a1b3Sopenharmony_ci 31553a5a1b3Sopenharmony_ci while (*str != '}') { 31653a5a1b3Sopenharmony_ci str++; /* Consume leading '{' or ',' */ 31753a5a1b3Sopenharmony_ci 31853a5a1b3Sopenharmony_ci str = parse_value(str, ":", &name, depth + 1); 31953a5a1b3Sopenharmony_ci if (!str || pa_json_object_get_type(name) != PA_JSON_TYPE_STRING) { 32053a5a1b3Sopenharmony_ci pa_log("Could not parse key for object"); 32153a5a1b3Sopenharmony_ci goto error; 32253a5a1b3Sopenharmony_ci } 32353a5a1b3Sopenharmony_ci 32453a5a1b3Sopenharmony_ci /* Consume the ':' */ 32553a5a1b3Sopenharmony_ci str++; 32653a5a1b3Sopenharmony_ci 32753a5a1b3Sopenharmony_ci str = parse_value(str, ",}", &value, depth + 1); 32853a5a1b3Sopenharmony_ci if (!str) { 32953a5a1b3Sopenharmony_ci pa_log("Could not parse value for object"); 33053a5a1b3Sopenharmony_ci goto error; 33153a5a1b3Sopenharmony_ci } 33253a5a1b3Sopenharmony_ci 33353a5a1b3Sopenharmony_ci pa_hashmap_put(obj->object_values, pa_xstrdup(pa_json_object_get_string(name)), value); 33453a5a1b3Sopenharmony_ci pa_json_object_free(name); 33553a5a1b3Sopenharmony_ci 33653a5a1b3Sopenharmony_ci name = NULL; 33753a5a1b3Sopenharmony_ci value = NULL; 33853a5a1b3Sopenharmony_ci } 33953a5a1b3Sopenharmony_ci 34053a5a1b3Sopenharmony_ci /* Drop trailing '}' */ 34153a5a1b3Sopenharmony_ci str++; 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci /* We now know the value was correctly parsed */ 34453a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_OBJECT; 34553a5a1b3Sopenharmony_ci 34653a5a1b3Sopenharmony_ci return str; 34753a5a1b3Sopenharmony_ci 34853a5a1b3Sopenharmony_cierror: 34953a5a1b3Sopenharmony_ci pa_hashmap_free(obj->object_values); 35053a5a1b3Sopenharmony_ci obj->object_values = NULL; 35153a5a1b3Sopenharmony_ci 35253a5a1b3Sopenharmony_ci if (name) 35353a5a1b3Sopenharmony_ci pa_json_object_free(name); 35453a5a1b3Sopenharmony_ci if (value) 35553a5a1b3Sopenharmony_ci pa_json_object_free(value); 35653a5a1b3Sopenharmony_ci 35753a5a1b3Sopenharmony_ci return NULL; 35853a5a1b3Sopenharmony_ci} 35953a5a1b3Sopenharmony_ci 36053a5a1b3Sopenharmony_cistatic const char *parse_array(const char *str, pa_json_object *obj, unsigned int depth) { 36153a5a1b3Sopenharmony_ci pa_json_object *value; 36253a5a1b3Sopenharmony_ci 36353a5a1b3Sopenharmony_ci obj->array_values = pa_idxset_new(NULL, NULL); 36453a5a1b3Sopenharmony_ci 36553a5a1b3Sopenharmony_ci while (*str != ']') { 36653a5a1b3Sopenharmony_ci str++; /* Consume leading '[' or ',' */ 36753a5a1b3Sopenharmony_ci 36853a5a1b3Sopenharmony_ci /* Need to chew up whitespaces as a special case to deal with the 36953a5a1b3Sopenharmony_ci * possibility of an empty array */ 37053a5a1b3Sopenharmony_ci while (is_whitespace(*str)) 37153a5a1b3Sopenharmony_ci str++; 37253a5a1b3Sopenharmony_ci 37353a5a1b3Sopenharmony_ci if (*str == ']') 37453a5a1b3Sopenharmony_ci break; 37553a5a1b3Sopenharmony_ci 37653a5a1b3Sopenharmony_ci str = parse_value(str, ",]", &value, depth + 1); 37753a5a1b3Sopenharmony_ci if (!str) { 37853a5a1b3Sopenharmony_ci pa_log("Could not parse value for array"); 37953a5a1b3Sopenharmony_ci goto error; 38053a5a1b3Sopenharmony_ci } 38153a5a1b3Sopenharmony_ci 38253a5a1b3Sopenharmony_ci pa_idxset_put(obj->array_values, value, NULL); 38353a5a1b3Sopenharmony_ci } 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci /* Drop trailing ']' */ 38653a5a1b3Sopenharmony_ci str++; 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_ci /* We now know the value was correctly parsed */ 38953a5a1b3Sopenharmony_ci obj->type = PA_JSON_TYPE_ARRAY; 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci return str; 39253a5a1b3Sopenharmony_ci 39353a5a1b3Sopenharmony_cierror: 39453a5a1b3Sopenharmony_ci pa_idxset_free(obj->array_values, (pa_free_cb_t) pa_json_object_free); 39553a5a1b3Sopenharmony_ci obj->array_values = NULL; 39653a5a1b3Sopenharmony_ci return NULL; 39753a5a1b3Sopenharmony_ci} 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_citypedef enum { 40053a5a1b3Sopenharmony_ci JSON_PARSER_STATE_INIT, 40153a5a1b3Sopenharmony_ci JSON_PARSER_STATE_FINISH, 40253a5a1b3Sopenharmony_ci} json_parser_state; 40353a5a1b3Sopenharmony_ci 40453a5a1b3Sopenharmony_cistatic const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth) { 40553a5a1b3Sopenharmony_ci json_parser_state state = JSON_PARSER_STATE_INIT; 40653a5a1b3Sopenharmony_ci pa_json_object *o; 40753a5a1b3Sopenharmony_ci 40853a5a1b3Sopenharmony_ci pa_assert(str != NULL); 40953a5a1b3Sopenharmony_ci 41053a5a1b3Sopenharmony_ci o = json_object_new(); 41153a5a1b3Sopenharmony_ci 41253a5a1b3Sopenharmony_ci if (depth > MAX_NESTING_DEPTH) { 41353a5a1b3Sopenharmony_ci pa_log("Exceeded maximum permitted nesting depth of objects (%u)", MAX_NESTING_DEPTH); 41453a5a1b3Sopenharmony_ci goto error; 41553a5a1b3Sopenharmony_ci } 41653a5a1b3Sopenharmony_ci 41753a5a1b3Sopenharmony_ci while (!is_end(*str, end)) { 41853a5a1b3Sopenharmony_ci switch (state) { 41953a5a1b3Sopenharmony_ci case JSON_PARSER_STATE_INIT: 42053a5a1b3Sopenharmony_ci if (is_whitespace(*str)) { 42153a5a1b3Sopenharmony_ci str++; 42253a5a1b3Sopenharmony_ci } else if (*str == 'n') { 42353a5a1b3Sopenharmony_ci str = parse_null(str, o); 42453a5a1b3Sopenharmony_ci state = JSON_PARSER_STATE_FINISH; 42553a5a1b3Sopenharmony_ci } else if (*str == 't' || *str == 'f') { 42653a5a1b3Sopenharmony_ci str = parse_boolean(str, o); 42753a5a1b3Sopenharmony_ci state = JSON_PARSER_STATE_FINISH; 42853a5a1b3Sopenharmony_ci } else if (*str == '"') { 42953a5a1b3Sopenharmony_ci str = parse_string(str, o); 43053a5a1b3Sopenharmony_ci state = JSON_PARSER_STATE_FINISH; 43153a5a1b3Sopenharmony_ci } else if (is_digit(*str) || *str == '-') { 43253a5a1b3Sopenharmony_ci str = parse_number(str, o); 43353a5a1b3Sopenharmony_ci state = JSON_PARSER_STATE_FINISH; 43453a5a1b3Sopenharmony_ci } else if (*str == '{') { 43553a5a1b3Sopenharmony_ci str = parse_object(str, o, depth); 43653a5a1b3Sopenharmony_ci state = JSON_PARSER_STATE_FINISH; 43753a5a1b3Sopenharmony_ci } else if (*str == '[') { 43853a5a1b3Sopenharmony_ci str = parse_array(str, o, depth); 43953a5a1b3Sopenharmony_ci state = JSON_PARSER_STATE_FINISH; 44053a5a1b3Sopenharmony_ci } else { 44153a5a1b3Sopenharmony_ci pa_log("Invalid JSON string: %s", str); 44253a5a1b3Sopenharmony_ci goto error; 44353a5a1b3Sopenharmony_ci } 44453a5a1b3Sopenharmony_ci 44553a5a1b3Sopenharmony_ci if (!str) 44653a5a1b3Sopenharmony_ci goto error; 44753a5a1b3Sopenharmony_ci 44853a5a1b3Sopenharmony_ci break; 44953a5a1b3Sopenharmony_ci 45053a5a1b3Sopenharmony_ci case JSON_PARSER_STATE_FINISH: 45153a5a1b3Sopenharmony_ci /* Consume trailing whitespaces */ 45253a5a1b3Sopenharmony_ci if (is_whitespace(*str)) { 45353a5a1b3Sopenharmony_ci str++; 45453a5a1b3Sopenharmony_ci } else { 45553a5a1b3Sopenharmony_ci goto error; 45653a5a1b3Sopenharmony_ci } 45753a5a1b3Sopenharmony_ci } 45853a5a1b3Sopenharmony_ci } 45953a5a1b3Sopenharmony_ci 46053a5a1b3Sopenharmony_ci if (pa_json_object_get_type(o) == PA_JSON_TYPE_INIT) { 46153a5a1b3Sopenharmony_ci /* We didn't actually get any data */ 46253a5a1b3Sopenharmony_ci pa_log("No data while parsing json string: '%s' till '%s'", str, pa_strnull(end)); 46353a5a1b3Sopenharmony_ci goto error; 46453a5a1b3Sopenharmony_ci } 46553a5a1b3Sopenharmony_ci 46653a5a1b3Sopenharmony_ci *obj = o; 46753a5a1b3Sopenharmony_ci 46853a5a1b3Sopenharmony_ci return str; 46953a5a1b3Sopenharmony_ci 47053a5a1b3Sopenharmony_cierror: 47153a5a1b3Sopenharmony_ci pa_json_object_free(o); 47253a5a1b3Sopenharmony_ci return NULL; 47353a5a1b3Sopenharmony_ci} 47453a5a1b3Sopenharmony_ci 47553a5a1b3Sopenharmony_ci 47653a5a1b3Sopenharmony_cipa_json_object* pa_json_parse(const char *str) { 47753a5a1b3Sopenharmony_ci pa_json_object *obj; 47853a5a1b3Sopenharmony_ci 47953a5a1b3Sopenharmony_ci str = parse_value(str, NULL, &obj, 0); 48053a5a1b3Sopenharmony_ci 48153a5a1b3Sopenharmony_ci if (!str) { 48253a5a1b3Sopenharmony_ci pa_log("JSON parsing failed"); 48353a5a1b3Sopenharmony_ci return NULL; 48453a5a1b3Sopenharmony_ci } 48553a5a1b3Sopenharmony_ci 48653a5a1b3Sopenharmony_ci if (*str != '\0') { 48753a5a1b3Sopenharmony_ci pa_log("Unable to parse complete JSON string, remainder is: %s", str); 48853a5a1b3Sopenharmony_ci pa_json_object_free(obj); 48953a5a1b3Sopenharmony_ci return NULL; 49053a5a1b3Sopenharmony_ci } 49153a5a1b3Sopenharmony_ci 49253a5a1b3Sopenharmony_ci return obj; 49353a5a1b3Sopenharmony_ci} 49453a5a1b3Sopenharmony_ci 49553a5a1b3Sopenharmony_cipa_json_type pa_json_object_get_type(const pa_json_object *obj) { 49653a5a1b3Sopenharmony_ci return obj->type; 49753a5a1b3Sopenharmony_ci} 49853a5a1b3Sopenharmony_ci 49953a5a1b3Sopenharmony_civoid pa_json_object_free(pa_json_object *obj) { 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci switch (pa_json_object_get_type(obj)) { 50253a5a1b3Sopenharmony_ci case PA_JSON_TYPE_INIT: 50353a5a1b3Sopenharmony_ci case PA_JSON_TYPE_INT: 50453a5a1b3Sopenharmony_ci case PA_JSON_TYPE_DOUBLE: 50553a5a1b3Sopenharmony_ci case PA_JSON_TYPE_BOOL: 50653a5a1b3Sopenharmony_ci case PA_JSON_TYPE_NULL: 50753a5a1b3Sopenharmony_ci break; 50853a5a1b3Sopenharmony_ci 50953a5a1b3Sopenharmony_ci case PA_JSON_TYPE_STRING: 51053a5a1b3Sopenharmony_ci pa_xfree(obj->string_value); 51153a5a1b3Sopenharmony_ci break; 51253a5a1b3Sopenharmony_ci 51353a5a1b3Sopenharmony_ci case PA_JSON_TYPE_OBJECT: 51453a5a1b3Sopenharmony_ci pa_hashmap_free(obj->object_values); 51553a5a1b3Sopenharmony_ci break; 51653a5a1b3Sopenharmony_ci 51753a5a1b3Sopenharmony_ci case PA_JSON_TYPE_ARRAY: 51853a5a1b3Sopenharmony_ci pa_idxset_free(obj->array_values, (pa_free_cb_t) pa_json_object_free); 51953a5a1b3Sopenharmony_ci break; 52053a5a1b3Sopenharmony_ci 52153a5a1b3Sopenharmony_ci default: 52253a5a1b3Sopenharmony_ci pa_assert_not_reached(); 52353a5a1b3Sopenharmony_ci } 52453a5a1b3Sopenharmony_ci 52553a5a1b3Sopenharmony_ci pa_xfree(obj); 52653a5a1b3Sopenharmony_ci} 52753a5a1b3Sopenharmony_ci 52853a5a1b3Sopenharmony_ciint64_t pa_json_object_get_int(const pa_json_object *o) { 52953a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_INT); 53053a5a1b3Sopenharmony_ci return o->int_value; 53153a5a1b3Sopenharmony_ci} 53253a5a1b3Sopenharmony_ci 53353a5a1b3Sopenharmony_cidouble pa_json_object_get_double(const pa_json_object *o) { 53453a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_DOUBLE); 53553a5a1b3Sopenharmony_ci return o->double_value; 53653a5a1b3Sopenharmony_ci} 53753a5a1b3Sopenharmony_ci 53853a5a1b3Sopenharmony_cibool pa_json_object_get_bool(const pa_json_object *o) { 53953a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_BOOL); 54053a5a1b3Sopenharmony_ci return o->bool_value; 54153a5a1b3Sopenharmony_ci} 54253a5a1b3Sopenharmony_ci 54353a5a1b3Sopenharmony_ciconst char* pa_json_object_get_string(const pa_json_object *o) { 54453a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_STRING); 54553a5a1b3Sopenharmony_ci return o->string_value; 54653a5a1b3Sopenharmony_ci} 54753a5a1b3Sopenharmony_ci 54853a5a1b3Sopenharmony_ciconst pa_json_object* pa_json_object_get_object_member(const pa_json_object *o, const char *name) { 54953a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_OBJECT); 55053a5a1b3Sopenharmony_ci return pa_hashmap_get(o->object_values, name); 55153a5a1b3Sopenharmony_ci} 55253a5a1b3Sopenharmony_ci 55353a5a1b3Sopenharmony_ciconst pa_hashmap *pa_json_object_get_object_member_hashmap(const pa_json_object *o) { 55453a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_OBJECT); 55553a5a1b3Sopenharmony_ci return o->object_values; 55653a5a1b3Sopenharmony_ci} 55753a5a1b3Sopenharmony_ci 55853a5a1b3Sopenharmony_ciint pa_json_object_get_array_length(const pa_json_object *o) { 55953a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_ARRAY); 56053a5a1b3Sopenharmony_ci return pa_idxset_size(o->array_values); 56153a5a1b3Sopenharmony_ci} 56253a5a1b3Sopenharmony_ci 56353a5a1b3Sopenharmony_ciconst pa_json_object* pa_json_object_get_array_member(const pa_json_object *o, int index) { 56453a5a1b3Sopenharmony_ci pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_ARRAY); 56553a5a1b3Sopenharmony_ci return pa_idxset_get_by_index(o->array_values, index); 56653a5a1b3Sopenharmony_ci} 56753a5a1b3Sopenharmony_ci 56853a5a1b3Sopenharmony_cibool pa_json_object_equal(const pa_json_object *o1, const pa_json_object *o2) { 56953a5a1b3Sopenharmony_ci int i; 57053a5a1b3Sopenharmony_ci 57153a5a1b3Sopenharmony_ci if (pa_json_object_get_type(o1) != pa_json_object_get_type(o2)) 57253a5a1b3Sopenharmony_ci return false; 57353a5a1b3Sopenharmony_ci 57453a5a1b3Sopenharmony_ci switch (pa_json_object_get_type(o1)) { 57553a5a1b3Sopenharmony_ci case PA_JSON_TYPE_NULL: 57653a5a1b3Sopenharmony_ci return true; 57753a5a1b3Sopenharmony_ci 57853a5a1b3Sopenharmony_ci case PA_JSON_TYPE_BOOL: 57953a5a1b3Sopenharmony_ci return o1->bool_value == o2->bool_value; 58053a5a1b3Sopenharmony_ci 58153a5a1b3Sopenharmony_ci case PA_JSON_TYPE_INT: 58253a5a1b3Sopenharmony_ci return o1->int_value == o2->int_value; 58353a5a1b3Sopenharmony_ci 58453a5a1b3Sopenharmony_ci case PA_JSON_TYPE_DOUBLE: 58553a5a1b3Sopenharmony_ci return PA_DOUBLE_IS_EQUAL(o1->double_value, o2->double_value); 58653a5a1b3Sopenharmony_ci 58753a5a1b3Sopenharmony_ci case PA_JSON_TYPE_STRING: 58853a5a1b3Sopenharmony_ci return pa_streq(o1->string_value, o2->string_value); 58953a5a1b3Sopenharmony_ci 59053a5a1b3Sopenharmony_ci case PA_JSON_TYPE_ARRAY: 59153a5a1b3Sopenharmony_ci if (pa_json_object_get_array_length(o1) != pa_json_object_get_array_length(o2)) 59253a5a1b3Sopenharmony_ci return false; 59353a5a1b3Sopenharmony_ci 59453a5a1b3Sopenharmony_ci for (i = 0; i < pa_json_object_get_array_length(o1); i++) { 59553a5a1b3Sopenharmony_ci if (!pa_json_object_equal(pa_json_object_get_array_member(o1, i), 59653a5a1b3Sopenharmony_ci pa_json_object_get_array_member(o2, i))) 59753a5a1b3Sopenharmony_ci return false; 59853a5a1b3Sopenharmony_ci } 59953a5a1b3Sopenharmony_ci 60053a5a1b3Sopenharmony_ci return true; 60153a5a1b3Sopenharmony_ci 60253a5a1b3Sopenharmony_ci case PA_JSON_TYPE_OBJECT: { 60353a5a1b3Sopenharmony_ci void *state; 60453a5a1b3Sopenharmony_ci const char *key; 60553a5a1b3Sopenharmony_ci const pa_json_object *v1, *v2; 60653a5a1b3Sopenharmony_ci 60753a5a1b3Sopenharmony_ci if (pa_hashmap_size(o1->object_values) != pa_hashmap_size(o2->object_values)) 60853a5a1b3Sopenharmony_ci return false; 60953a5a1b3Sopenharmony_ci 61053a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH_KV(key, v1, o1->object_values, state) { 61153a5a1b3Sopenharmony_ci v2 = pa_json_object_get_object_member(o2, key); 61253a5a1b3Sopenharmony_ci if (!v2 || !pa_json_object_equal(v1, v2)) 61353a5a1b3Sopenharmony_ci return false; 61453a5a1b3Sopenharmony_ci } 61553a5a1b3Sopenharmony_ci 61653a5a1b3Sopenharmony_ci return true; 61753a5a1b3Sopenharmony_ci } 61853a5a1b3Sopenharmony_ci 61953a5a1b3Sopenharmony_ci default: 62053a5a1b3Sopenharmony_ci pa_assert_not_reached(); 62153a5a1b3Sopenharmony_ci } 62253a5a1b3Sopenharmony_ci} 62353a5a1b3Sopenharmony_ci 62453a5a1b3Sopenharmony_ci/* Write functions. The functions are wrapper functions around pa_strbuf, 62553a5a1b3Sopenharmony_ci * so that the client does not need to use pa_strbuf directly. */ 62653a5a1b3Sopenharmony_ci 62753a5a1b3Sopenharmony_cistatic void json_encoder_context_push(pa_json_encoder *encoder, pa_json_context_type_t type) { 62853a5a1b3Sopenharmony_ci pa_assert(encoder); 62953a5a1b3Sopenharmony_ci 63053a5a1b3Sopenharmony_ci encoder_context *head = pa_xnew0(encoder_context, 1); 63153a5a1b3Sopenharmony_ci head->type = type; 63253a5a1b3Sopenharmony_ci head->next = encoder->context; 63353a5a1b3Sopenharmony_ci encoder->context = head; 63453a5a1b3Sopenharmony_ci} 63553a5a1b3Sopenharmony_ci 63653a5a1b3Sopenharmony_ci/* Returns type of context popped off encoder context stack. */ 63753a5a1b3Sopenharmony_cistatic pa_json_context_type_t json_encoder_context_pop(pa_json_encoder *encoder) { 63853a5a1b3Sopenharmony_ci encoder_context *head; 63953a5a1b3Sopenharmony_ci pa_json_context_type_t type; 64053a5a1b3Sopenharmony_ci 64153a5a1b3Sopenharmony_ci pa_assert(encoder); 64253a5a1b3Sopenharmony_ci pa_assert(encoder->context); 64353a5a1b3Sopenharmony_ci 64453a5a1b3Sopenharmony_ci type = encoder->context->type; 64553a5a1b3Sopenharmony_ci 64653a5a1b3Sopenharmony_ci head = encoder->context->next; 64753a5a1b3Sopenharmony_ci pa_xfree(encoder->context); 64853a5a1b3Sopenharmony_ci encoder->context = head; 64953a5a1b3Sopenharmony_ci 65053a5a1b3Sopenharmony_ci return type; 65153a5a1b3Sopenharmony_ci} 65253a5a1b3Sopenharmony_ci 65353a5a1b3Sopenharmony_cibool pa_json_encoder_is_empty(pa_json_encoder *encoder) { 65453a5a1b3Sopenharmony_ci pa_json_context_type_t type; 65553a5a1b3Sopenharmony_ci 65653a5a1b3Sopenharmony_ci pa_assert(encoder); 65753a5a1b3Sopenharmony_ci pa_assert(encoder->context); 65853a5a1b3Sopenharmony_ci 65953a5a1b3Sopenharmony_ci type = encoder->context->type; 66053a5a1b3Sopenharmony_ci return type == PA_JSON_CONTEXT_EMPTY; 66153a5a1b3Sopenharmony_ci} 66253a5a1b3Sopenharmony_ci 66353a5a1b3Sopenharmony_cipa_json_encoder *pa_json_encoder_new(void) { 66453a5a1b3Sopenharmony_ci pa_json_encoder *encoder; 66553a5a1b3Sopenharmony_ci 66653a5a1b3Sopenharmony_ci encoder = pa_xnew(pa_json_encoder, 1); 66753a5a1b3Sopenharmony_ci encoder->buffer = pa_strbuf_new(); 66853a5a1b3Sopenharmony_ci 66953a5a1b3Sopenharmony_ci encoder->context = NULL; 67053a5a1b3Sopenharmony_ci json_encoder_context_push(encoder, PA_JSON_CONTEXT_EMPTY); 67153a5a1b3Sopenharmony_ci 67253a5a1b3Sopenharmony_ci return encoder; 67353a5a1b3Sopenharmony_ci} 67453a5a1b3Sopenharmony_ci 67553a5a1b3Sopenharmony_civoid pa_json_encoder_free(pa_json_encoder *encoder) { 67653a5a1b3Sopenharmony_ci pa_json_context_type_t type; 67753a5a1b3Sopenharmony_ci pa_assert(encoder); 67853a5a1b3Sopenharmony_ci 67953a5a1b3Sopenharmony_ci /* should have exactly one encoder context left at this point */ 68053a5a1b3Sopenharmony_ci pa_assert(encoder->context); 68153a5a1b3Sopenharmony_ci type = json_encoder_context_pop(encoder); 68253a5a1b3Sopenharmony_ci pa_assert(encoder->context == NULL); 68353a5a1b3Sopenharmony_ci 68453a5a1b3Sopenharmony_ci pa_assert(type == PA_JSON_CONTEXT_TOP || type == PA_JSON_CONTEXT_EMPTY); 68553a5a1b3Sopenharmony_ci if (type == PA_JSON_CONTEXT_EMPTY) 68653a5a1b3Sopenharmony_ci pa_log_warn("JSON encoder is empty."); 68753a5a1b3Sopenharmony_ci 68853a5a1b3Sopenharmony_ci if (encoder->buffer) 68953a5a1b3Sopenharmony_ci pa_strbuf_free(encoder->buffer); 69053a5a1b3Sopenharmony_ci 69153a5a1b3Sopenharmony_ci pa_xfree(encoder); 69253a5a1b3Sopenharmony_ci} 69353a5a1b3Sopenharmony_ci 69453a5a1b3Sopenharmony_cichar *pa_json_encoder_to_string_free(pa_json_encoder *encoder) { 69553a5a1b3Sopenharmony_ci char *result; 69653a5a1b3Sopenharmony_ci 69753a5a1b3Sopenharmony_ci pa_assert(encoder); 69853a5a1b3Sopenharmony_ci 69953a5a1b3Sopenharmony_ci result = pa_strbuf_to_string_free(encoder->buffer); 70053a5a1b3Sopenharmony_ci 70153a5a1b3Sopenharmony_ci encoder->buffer = NULL; 70253a5a1b3Sopenharmony_ci pa_json_encoder_free(encoder); 70353a5a1b3Sopenharmony_ci 70453a5a1b3Sopenharmony_ci return result; 70553a5a1b3Sopenharmony_ci} 70653a5a1b3Sopenharmony_ci 70753a5a1b3Sopenharmony_cistatic void json_encoder_insert_delimiter(pa_json_encoder *encoder) { 70853a5a1b3Sopenharmony_ci pa_assert(encoder); 70953a5a1b3Sopenharmony_ci 71053a5a1b3Sopenharmony_ci if (encoder->context->counter++) 71153a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ','); 71253a5a1b3Sopenharmony_ci} 71353a5a1b3Sopenharmony_ci 71453a5a1b3Sopenharmony_ci/* Escapes p to create valid JSON string. 71553a5a1b3Sopenharmony_ci * The caller has to free the returned string. */ 71653a5a1b3Sopenharmony_cistatic char *pa_json_escape(const char *p) { 71753a5a1b3Sopenharmony_ci const char *s; 71853a5a1b3Sopenharmony_ci char *out_string, *output; 71953a5a1b3Sopenharmony_ci int char_count = strlen(p); 72053a5a1b3Sopenharmony_ci 72153a5a1b3Sopenharmony_ci /* Maximum number of characters in output string 72253a5a1b3Sopenharmony_ci * including trailing 0. */ 72353a5a1b3Sopenharmony_ci char_count = 2 * char_count + 1; 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_ci /* allocate output string */ 72653a5a1b3Sopenharmony_ci out_string = pa_xmalloc(char_count); 72753a5a1b3Sopenharmony_ci output = out_string; 72853a5a1b3Sopenharmony_ci 72953a5a1b3Sopenharmony_ci /* write output string */ 73053a5a1b3Sopenharmony_ci for (s = p; *s; ++s) { 73153a5a1b3Sopenharmony_ci switch (*s) { 73253a5a1b3Sopenharmony_ci case '"': 73353a5a1b3Sopenharmony_ci *output++ = '\\'; 73453a5a1b3Sopenharmony_ci *output++ = '"'; 73553a5a1b3Sopenharmony_ci break; 73653a5a1b3Sopenharmony_ci case '\\': 73753a5a1b3Sopenharmony_ci *output++ = '\\'; 73853a5a1b3Sopenharmony_ci *output++ = '\\'; 73953a5a1b3Sopenharmony_ci break; 74053a5a1b3Sopenharmony_ci case '\b': 74153a5a1b3Sopenharmony_ci *output++ = '\\'; 74253a5a1b3Sopenharmony_ci *output++ = 'b'; 74353a5a1b3Sopenharmony_ci break; 74453a5a1b3Sopenharmony_ci 74553a5a1b3Sopenharmony_ci case '\f': 74653a5a1b3Sopenharmony_ci *output++ = '\\'; 74753a5a1b3Sopenharmony_ci *output++ = 'f'; 74853a5a1b3Sopenharmony_ci break; 74953a5a1b3Sopenharmony_ci 75053a5a1b3Sopenharmony_ci case '\n': 75153a5a1b3Sopenharmony_ci *output++ = '\\'; 75253a5a1b3Sopenharmony_ci *output++ = 'n'; 75353a5a1b3Sopenharmony_ci break; 75453a5a1b3Sopenharmony_ci 75553a5a1b3Sopenharmony_ci case '\r': 75653a5a1b3Sopenharmony_ci *output++ = '\\'; 75753a5a1b3Sopenharmony_ci *output++ = 'r'; 75853a5a1b3Sopenharmony_ci break; 75953a5a1b3Sopenharmony_ci 76053a5a1b3Sopenharmony_ci case '\t': 76153a5a1b3Sopenharmony_ci *output++ = '\\'; 76253a5a1b3Sopenharmony_ci *output++ = 't'; 76353a5a1b3Sopenharmony_ci break; 76453a5a1b3Sopenharmony_ci default: 76553a5a1b3Sopenharmony_ci if (*s < 0x20 || *s > 0x7E) { 76653a5a1b3Sopenharmony_ci pa_log("Invalid non-ASCII character: 0x%x", (unsigned int) *s); 76753a5a1b3Sopenharmony_ci pa_xfree(out_string); 76853a5a1b3Sopenharmony_ci return NULL; 76953a5a1b3Sopenharmony_ci } 77053a5a1b3Sopenharmony_ci *output++ = *s; 77153a5a1b3Sopenharmony_ci break; 77253a5a1b3Sopenharmony_ci } 77353a5a1b3Sopenharmony_ci } 77453a5a1b3Sopenharmony_ci 77553a5a1b3Sopenharmony_ci *output = 0; 77653a5a1b3Sopenharmony_ci 77753a5a1b3Sopenharmony_ci return out_string; 77853a5a1b3Sopenharmony_ci} 77953a5a1b3Sopenharmony_ci 78053a5a1b3Sopenharmony_cistatic void json_write_string_escaped(pa_json_encoder *encoder, const char *value) { 78153a5a1b3Sopenharmony_ci char *escaped_value; 78253a5a1b3Sopenharmony_ci 78353a5a1b3Sopenharmony_ci pa_assert(encoder); 78453a5a1b3Sopenharmony_ci 78553a5a1b3Sopenharmony_ci escaped_value = pa_json_escape(value); 78653a5a1b3Sopenharmony_ci pa_strbuf_printf(encoder->buffer, "\"%s\"", escaped_value); 78753a5a1b3Sopenharmony_ci pa_xfree(escaped_value); 78853a5a1b3Sopenharmony_ci} 78953a5a1b3Sopenharmony_ci 79053a5a1b3Sopenharmony_ci/* Writes an opening curly brace */ 79153a5a1b3Sopenharmony_civoid pa_json_encoder_begin_element_object(pa_json_encoder *encoder) { 79253a5a1b3Sopenharmony_ci pa_assert(encoder); 79353a5a1b3Sopenharmony_ci pa_assert(encoder->context->type != PA_JSON_CONTEXT_TOP); 79453a5a1b3Sopenharmony_ci 79553a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 79653a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 79753a5a1b3Sopenharmony_ci 79853a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 79953a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, '{'); 80053a5a1b3Sopenharmony_ci 80153a5a1b3Sopenharmony_ci json_encoder_context_push(encoder, PA_JSON_CONTEXT_OBJECT); 80253a5a1b3Sopenharmony_ci} 80353a5a1b3Sopenharmony_ci 80453a5a1b3Sopenharmony_ci/* Writes an opening curly brace */ 80553a5a1b3Sopenharmony_civoid pa_json_encoder_begin_member_object(pa_json_encoder *encoder, const char *name) { 80653a5a1b3Sopenharmony_ci pa_assert(encoder); 80753a5a1b3Sopenharmony_ci pa_assert(encoder->context); 80853a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 80953a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 81053a5a1b3Sopenharmony_ci 81153a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 81253a5a1b3Sopenharmony_ci 81353a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 81453a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 81553a5a1b3Sopenharmony_ci 81653a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, '{'); 81753a5a1b3Sopenharmony_ci 81853a5a1b3Sopenharmony_ci json_encoder_context_push(encoder, PA_JSON_CONTEXT_OBJECT); 81953a5a1b3Sopenharmony_ci} 82053a5a1b3Sopenharmony_ci 82153a5a1b3Sopenharmony_ci/* Writes a closing curly brace */ 82253a5a1b3Sopenharmony_civoid pa_json_encoder_end_object(pa_json_encoder *encoder) { 82353a5a1b3Sopenharmony_ci pa_json_context_type_t type; 82453a5a1b3Sopenharmony_ci pa_assert(encoder); 82553a5a1b3Sopenharmony_ci 82653a5a1b3Sopenharmony_ci type = json_encoder_context_pop(encoder); 82753a5a1b3Sopenharmony_ci pa_assert(type == PA_JSON_CONTEXT_OBJECT); 82853a5a1b3Sopenharmony_ci 82953a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, '}'); 83053a5a1b3Sopenharmony_ci} 83153a5a1b3Sopenharmony_ci 83253a5a1b3Sopenharmony_ci/* Writes an opening bracket */ 83353a5a1b3Sopenharmony_civoid pa_json_encoder_begin_element_array(pa_json_encoder *encoder) { 83453a5a1b3Sopenharmony_ci pa_assert(encoder); 83553a5a1b3Sopenharmony_ci pa_assert(encoder->context); 83653a5a1b3Sopenharmony_ci pa_assert(encoder->context->type != PA_JSON_CONTEXT_TOP); 83753a5a1b3Sopenharmony_ci 83853a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 83953a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 84053a5a1b3Sopenharmony_ci 84153a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 84253a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, '['); 84353a5a1b3Sopenharmony_ci 84453a5a1b3Sopenharmony_ci json_encoder_context_push(encoder, PA_JSON_CONTEXT_ARRAY); 84553a5a1b3Sopenharmony_ci} 84653a5a1b3Sopenharmony_ci 84753a5a1b3Sopenharmony_ci/* Writes member name and an opening bracket */ 84853a5a1b3Sopenharmony_civoid pa_json_encoder_begin_member_array(pa_json_encoder *encoder, const char *name) { 84953a5a1b3Sopenharmony_ci pa_assert(encoder); 85053a5a1b3Sopenharmony_ci pa_assert(encoder->context); 85153a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 85253a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 85353a5a1b3Sopenharmony_ci 85453a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 85553a5a1b3Sopenharmony_ci 85653a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 85753a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 85853a5a1b3Sopenharmony_ci 85953a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, '['); 86053a5a1b3Sopenharmony_ci 86153a5a1b3Sopenharmony_ci json_encoder_context_push(encoder, PA_JSON_CONTEXT_ARRAY); 86253a5a1b3Sopenharmony_ci} 86353a5a1b3Sopenharmony_ci 86453a5a1b3Sopenharmony_ci/* Writes a closing bracket */ 86553a5a1b3Sopenharmony_civoid pa_json_encoder_end_array(pa_json_encoder *encoder) { 86653a5a1b3Sopenharmony_ci pa_json_context_type_t type; 86753a5a1b3Sopenharmony_ci pa_assert(encoder); 86853a5a1b3Sopenharmony_ci 86953a5a1b3Sopenharmony_ci type = json_encoder_context_pop(encoder); 87053a5a1b3Sopenharmony_ci pa_assert(type == PA_JSON_CONTEXT_ARRAY); 87153a5a1b3Sopenharmony_ci 87253a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ']'); 87353a5a1b3Sopenharmony_ci} 87453a5a1b3Sopenharmony_ci 87553a5a1b3Sopenharmony_civoid pa_json_encoder_add_element_string(pa_json_encoder *encoder, const char *value) { 87653a5a1b3Sopenharmony_ci pa_assert(encoder); 87753a5a1b3Sopenharmony_ci pa_assert(encoder->context); 87853a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY); 87953a5a1b3Sopenharmony_ci 88053a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 88153a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 88253a5a1b3Sopenharmony_ci 88353a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 88453a5a1b3Sopenharmony_ci 88553a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, value); 88653a5a1b3Sopenharmony_ci} 88753a5a1b3Sopenharmony_ci 88853a5a1b3Sopenharmony_civoid pa_json_encoder_add_member_string(pa_json_encoder *encoder, const char *name, const char *value) { 88953a5a1b3Sopenharmony_ci pa_assert(encoder); 89053a5a1b3Sopenharmony_ci pa_assert(encoder->context); 89153a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 89253a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 89353a5a1b3Sopenharmony_ci 89453a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 89553a5a1b3Sopenharmony_ci 89653a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 89753a5a1b3Sopenharmony_ci 89853a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 89953a5a1b3Sopenharmony_ci 90053a5a1b3Sopenharmony_ci /* Null value is written as empty element */ 90153a5a1b3Sopenharmony_ci if (!value) 90253a5a1b3Sopenharmony_ci value = ""; 90353a5a1b3Sopenharmony_ci 90453a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, value); 90553a5a1b3Sopenharmony_ci} 90653a5a1b3Sopenharmony_ci 90753a5a1b3Sopenharmony_cistatic void json_write_null(pa_json_encoder *encoder) { 90853a5a1b3Sopenharmony_ci pa_assert(encoder); 90953a5a1b3Sopenharmony_ci 91053a5a1b3Sopenharmony_ci pa_strbuf_puts(encoder->buffer, "null"); 91153a5a1b3Sopenharmony_ci} 91253a5a1b3Sopenharmony_ci 91353a5a1b3Sopenharmony_civoid pa_json_encoder_add_element_null(pa_json_encoder *encoder) { 91453a5a1b3Sopenharmony_ci pa_assert(encoder); 91553a5a1b3Sopenharmony_ci pa_assert(encoder->context); 91653a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY); 91753a5a1b3Sopenharmony_ci 91853a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 91953a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 92053a5a1b3Sopenharmony_ci 92153a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 92253a5a1b3Sopenharmony_ci 92353a5a1b3Sopenharmony_ci json_write_null(encoder); 92453a5a1b3Sopenharmony_ci} 92553a5a1b3Sopenharmony_ci 92653a5a1b3Sopenharmony_civoid pa_json_encoder_add_member_null(pa_json_encoder *encoder, const char *name) { 92753a5a1b3Sopenharmony_ci pa_assert(encoder); 92853a5a1b3Sopenharmony_ci pa_assert(encoder->context); 92953a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 93053a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 93153a5a1b3Sopenharmony_ci 93253a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 93353a5a1b3Sopenharmony_ci 93453a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 93553a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 93653a5a1b3Sopenharmony_ci 93753a5a1b3Sopenharmony_ci json_write_null(encoder); 93853a5a1b3Sopenharmony_ci} 93953a5a1b3Sopenharmony_ci 94053a5a1b3Sopenharmony_cistatic void json_write_bool(pa_json_encoder *encoder, bool value) { 94153a5a1b3Sopenharmony_ci pa_assert(encoder); 94253a5a1b3Sopenharmony_ci 94353a5a1b3Sopenharmony_ci pa_strbuf_puts(encoder->buffer, value ? "true" : "false"); 94453a5a1b3Sopenharmony_ci} 94553a5a1b3Sopenharmony_ci 94653a5a1b3Sopenharmony_civoid pa_json_encoder_add_element_bool(pa_json_encoder *encoder, bool value) { 94753a5a1b3Sopenharmony_ci pa_assert(encoder); 94853a5a1b3Sopenharmony_ci pa_assert(encoder->context); 94953a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY); 95053a5a1b3Sopenharmony_ci 95153a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 95253a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 95353a5a1b3Sopenharmony_ci 95453a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 95553a5a1b3Sopenharmony_ci 95653a5a1b3Sopenharmony_ci json_write_bool(encoder, value); 95753a5a1b3Sopenharmony_ci} 95853a5a1b3Sopenharmony_ci 95953a5a1b3Sopenharmony_civoid pa_json_encoder_add_member_bool(pa_json_encoder *encoder, const char *name, bool value) { 96053a5a1b3Sopenharmony_ci pa_assert(encoder); 96153a5a1b3Sopenharmony_ci pa_assert(encoder->context); 96253a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 96353a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 96453a5a1b3Sopenharmony_ci 96553a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 96653a5a1b3Sopenharmony_ci 96753a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 96853a5a1b3Sopenharmony_ci 96953a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 97053a5a1b3Sopenharmony_ci 97153a5a1b3Sopenharmony_ci json_write_bool(encoder, value); 97253a5a1b3Sopenharmony_ci} 97353a5a1b3Sopenharmony_ci 97453a5a1b3Sopenharmony_cistatic void json_write_int(pa_json_encoder *encoder, int64_t value) { 97553a5a1b3Sopenharmony_ci pa_assert(encoder); 97653a5a1b3Sopenharmony_ci 97753a5a1b3Sopenharmony_ci pa_strbuf_printf(encoder->buffer, "%"PRId64, value); 97853a5a1b3Sopenharmony_ci} 97953a5a1b3Sopenharmony_ci 98053a5a1b3Sopenharmony_civoid pa_json_encoder_add_element_int(pa_json_encoder *encoder, int64_t value) { 98153a5a1b3Sopenharmony_ci pa_assert(encoder); 98253a5a1b3Sopenharmony_ci pa_assert(encoder->context); 98353a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY); 98453a5a1b3Sopenharmony_ci 98553a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 98653a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 98753a5a1b3Sopenharmony_ci 98853a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 98953a5a1b3Sopenharmony_ci 99053a5a1b3Sopenharmony_ci json_write_int(encoder, value); 99153a5a1b3Sopenharmony_ci} 99253a5a1b3Sopenharmony_ci 99353a5a1b3Sopenharmony_civoid pa_json_encoder_add_member_int(pa_json_encoder *encoder, const char *name, int64_t value) { 99453a5a1b3Sopenharmony_ci pa_assert(encoder); 99553a5a1b3Sopenharmony_ci pa_assert(encoder->context); 99653a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 99753a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 99853a5a1b3Sopenharmony_ci 99953a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 100053a5a1b3Sopenharmony_ci 100153a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 100253a5a1b3Sopenharmony_ci 100353a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 100453a5a1b3Sopenharmony_ci 100553a5a1b3Sopenharmony_ci json_write_int(encoder, value); 100653a5a1b3Sopenharmony_ci} 100753a5a1b3Sopenharmony_ci 100853a5a1b3Sopenharmony_cistatic void json_write_double(pa_json_encoder *encoder, double value, int precision) { 100953a5a1b3Sopenharmony_ci pa_assert(encoder); 101053a5a1b3Sopenharmony_ci pa_strbuf_printf(encoder->buffer, "%.*f", precision, value); 101153a5a1b3Sopenharmony_ci} 101253a5a1b3Sopenharmony_ci 101353a5a1b3Sopenharmony_civoid pa_json_encoder_add_element_double(pa_json_encoder *encoder, double value, int precision) { 101453a5a1b3Sopenharmony_ci pa_assert(encoder); 101553a5a1b3Sopenharmony_ci pa_assert(encoder->context); 101653a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY); 101753a5a1b3Sopenharmony_ci 101853a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 101953a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 102053a5a1b3Sopenharmony_ci 102153a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 102253a5a1b3Sopenharmony_ci 102353a5a1b3Sopenharmony_ci json_write_double(encoder, value, precision); 102453a5a1b3Sopenharmony_ci} 102553a5a1b3Sopenharmony_ci 102653a5a1b3Sopenharmony_civoid pa_json_encoder_add_member_double(pa_json_encoder *encoder, const char *name, double value, int precision) { 102753a5a1b3Sopenharmony_ci pa_assert(encoder); 102853a5a1b3Sopenharmony_ci pa_assert(encoder->context); 102953a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 103053a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 103153a5a1b3Sopenharmony_ci 103253a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 103353a5a1b3Sopenharmony_ci 103453a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 103553a5a1b3Sopenharmony_ci 103653a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 103753a5a1b3Sopenharmony_ci 103853a5a1b3Sopenharmony_ci json_write_double(encoder, value, precision); 103953a5a1b3Sopenharmony_ci} 104053a5a1b3Sopenharmony_ci 104153a5a1b3Sopenharmony_cistatic void json_write_raw(pa_json_encoder *encoder, const char *raw_string) { 104253a5a1b3Sopenharmony_ci pa_assert(encoder); 104353a5a1b3Sopenharmony_ci pa_strbuf_puts(encoder->buffer, raw_string); 104453a5a1b3Sopenharmony_ci} 104553a5a1b3Sopenharmony_ci 104653a5a1b3Sopenharmony_civoid pa_json_encoder_add_element_raw_json(pa_json_encoder *encoder, const char *raw_json_string) { 104753a5a1b3Sopenharmony_ci pa_assert(encoder); 104853a5a1b3Sopenharmony_ci pa_assert(encoder->context); 104953a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_EMPTY || encoder->context->type == PA_JSON_CONTEXT_ARRAY); 105053a5a1b3Sopenharmony_ci 105153a5a1b3Sopenharmony_ci if (encoder->context->type == PA_JSON_CONTEXT_EMPTY) 105253a5a1b3Sopenharmony_ci encoder->context->type = PA_JSON_CONTEXT_TOP; 105353a5a1b3Sopenharmony_ci 105453a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 105553a5a1b3Sopenharmony_ci 105653a5a1b3Sopenharmony_ci json_write_raw(encoder, raw_json_string); 105753a5a1b3Sopenharmony_ci} 105853a5a1b3Sopenharmony_ci 105953a5a1b3Sopenharmony_civoid pa_json_encoder_add_member_raw_json(pa_json_encoder *encoder, const char *name, const char *raw_json_string) { 106053a5a1b3Sopenharmony_ci pa_assert(encoder); 106153a5a1b3Sopenharmony_ci pa_assert(encoder->context); 106253a5a1b3Sopenharmony_ci pa_assert(encoder->context->type == PA_JSON_CONTEXT_OBJECT); 106353a5a1b3Sopenharmony_ci pa_assert(name && name[0]); 106453a5a1b3Sopenharmony_ci 106553a5a1b3Sopenharmony_ci json_encoder_insert_delimiter(encoder); 106653a5a1b3Sopenharmony_ci 106753a5a1b3Sopenharmony_ci json_write_string_escaped(encoder, name); 106853a5a1b3Sopenharmony_ci 106953a5a1b3Sopenharmony_ci pa_strbuf_putc(encoder->buffer, ':'); 107053a5a1b3Sopenharmony_ci 107153a5a1b3Sopenharmony_ci json_write_raw(encoder, raw_json_string); 107253a5a1b3Sopenharmony_ci} 1073