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 34struct 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 */ 48typedef 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 59typedef 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 */ 66struct pa_json_encoder { 67 pa_strbuf *buffer; 68 encoder_context *context; 69}; 70 71static const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth); 72 73static 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 81static bool is_whitespace(char c) { 82 return c == '\t' || c == '\n' || c == '\r' || c == ' '; 83} 84 85static bool is_digit(char c) { 86 return c >= '0' && c <= '9'; 87} 88 89static 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 103static 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 115static 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 124static 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 144static 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 215error: 216 pa_strbuf_free(buf); 217 return NULL; 218} 219 220static 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 239fraction: 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 304error: 305 pa_xfree(candidate); 306 return NULL; 307} 308 309static 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 348error: 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 360static 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 393error: 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 399typedef enum { 400 JSON_PARSER_STATE_INIT, 401 JSON_PARSER_STATE_FINISH, 402} json_parser_state; 403 404static 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 470error: 471 pa_json_object_free(o); 472 return NULL; 473} 474 475 476pa_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 495pa_json_type pa_json_object_get_type(const pa_json_object *obj) { 496 return obj->type; 497} 498 499void 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 528int64_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 533double 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 538bool 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 543const 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 548const 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 553const 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 558int 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 563const 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 568bool 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 627static 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. */ 637static 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 653bool 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 663pa_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 675void 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 694char *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 707static 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. */ 716static 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 780static 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 */ 791void 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 */ 805void 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 */ 822void 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 */ 833void 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 */ 848void 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 */ 865void 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 875void 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 888void 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 907static void json_write_null(pa_json_encoder *encoder) { 908 pa_assert(encoder); 909 910 pa_strbuf_puts(encoder->buffer, "null"); 911} 912 913void 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 926void 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 940static 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 946void 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 959void 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 974static 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 980void 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 993void 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 1008static 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 1013void 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 1026void 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 1041static 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 1046void 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 1059void 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