UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /** 29 * @file json.h 30 * @brief Interface for parsing data from JSON files. 31 * @author Mike Becker 32 * @author Olaf Wintermann 33 * @copyright 2-Clause BSD License 34 */ 35 36 #ifndef UCX_JSON_H 37 #define UCX_JSON_H 38 39 #include "common.h" 40 #include "allocator.h" 41 #include "string.h" 42 #include "buffer.h" 43 #include "array_list.h" 44 45 #include <string.h> 46 47 #ifdef __cplusplus 48 extern "C" { 49 #endif 50 51 52 /** 53 * The type of the parsed token. 54 */ 55 enum cx_json_token_type { 56 /** 57 * No complete token parsed, yet. 58 */ 59 CX_JSON_NO_TOKEN, 60 /** 61 * The presumed token contains syntactical errors. 62 */ 63 CX_JSON_TOKEN_ERROR, 64 /** 65 * A "begin of array" '[' token. 66 */ 67 CX_JSON_TOKEN_BEGIN_ARRAY, 68 /** 69 * A "begin of object" '{' token. 70 */ 71 CX_JSON_TOKEN_BEGIN_OBJECT, 72 /** 73 * An "end of array" ']' token. 74 */ 75 CX_JSON_TOKEN_END_ARRAY, 76 /** 77 * An "end of object" '}' token. 78 */ 79 CX_JSON_TOKEN_END_OBJECT, 80 /** 81 * A colon ':' token separating names and values. 82 */ 83 CX_JSON_TOKEN_NAME_SEPARATOR, 84 /** 85 * A comma ',' token separating object entries or array elements. 86 */ 87 CX_JSON_TOKEN_VALUE_SEPARATOR, 88 /** 89 * A string token. 90 */ 91 CX_JSON_TOKEN_STRING, 92 /** 93 * A number token that can be represented as integer. 94 */ 95 CX_JSON_TOKEN_INTEGER, 96 /** 97 * A number token that cannot be represented as integer. 98 */ 99 CX_JSON_TOKEN_NUMBER, 100 /** 101 * A literal token. 102 */ 103 CX_JSON_TOKEN_LITERAL, 104 /** 105 * A white-space token. 106 */ 107 CX_JSON_TOKEN_SPACE 108 }; 109 110 /** 111 * The type of some JSON value. 112 */ 113 enum cx_json_value_type { 114 /** 115 * Reserved. 116 */ 117 CX_JSON_NOTHING, // this allows us to always return non-NULL values 118 /** 119 * A JSON object. 120 */ 121 CX_JSON_OBJECT, 122 /** 123 * A JSON array. 124 */ 125 CX_JSON_ARRAY, 126 /** 127 * A string. 128 */ 129 CX_JSON_STRING, 130 /** 131 * A number that contains an integer. 132 */ 133 CX_JSON_INTEGER, 134 /** 135 * A number, not necessarily an integer. 136 */ 137 CX_JSON_NUMBER, 138 /** 139 * A literal (true, false, null). 140 */ 141 CX_JSON_LITERAL 142 }; 143 144 /** 145 * JSON literal types. 146 */ 147 enum cx_json_literal { 148 /** 149 * The @c null literal. 150 */ 151 CX_JSON_NULL, 152 /** 153 * The @c true literal. 154 */ 155 CX_JSON_TRUE, 156 /** 157 * The @c false literal. 158 */ 159 CX_JSON_FALSE 160 }; 161 162 /** 163 * Type alias for the token type enum. 164 */ 165 typedef enum cx_json_token_type CxJsonTokenType; 166 /** 167 * Type alias for the value type enum. 168 */ 169 typedef enum cx_json_value_type CxJsonValueType; 170 171 /** 172 * Type alias for the JSON parser interface. 173 */ 174 typedef struct cx_json_s CxJson; 175 176 /** 177 * Type alias for the token struct. 178 */ 179 typedef struct cx_json_token_s CxJsonToken; 180 181 /** 182 * Type alias for the JSON value struct. 183 */ 184 typedef struct cx_json_value_s CxJsonValue; 185 186 /** 187 * Type alias for the JSON array struct. 188 */ 189 typedef struct cx_json_array_s CxJsonArray; 190 /** 191 * Type alias for the JSON object struct. 192 */ 193 typedef struct cx_json_object_s CxJsonObject; 194 /** 195 * Type alias for a JSON string. 196 */ 197 typedef struct cx_mutstr_s CxJsonString; 198 /** 199 * Type alias for a number that can be represented as 64-bit signed integer. 200 */ 201 typedef int64_t CxJsonInteger; 202 /** 203 * Type alias for number that is not an integer. 204 */ 205 typedef double CxJsonNumber; 206 /** 207 * Type alias for a JSON literal. 208 */ 209 typedef enum cx_json_literal CxJsonLiteral; 210 211 /** 212 * Type alias for a key/value pair in a JSON object. 213 */ 214 typedef struct cx_json_obj_value_s CxJsonObjValue; 215 216 /** 217 * JSON array structure. 218 */ 219 struct cx_json_array_s { 220 /** 221 * The array data. 222 */ 223 CX_ARRAY_DECLARE(CxJsonValue*, array); 224 }; 225 226 /** 227 * JSON object structure. 228 */ 229 struct cx_json_object_s { 230 /** 231 * The key/value entries. 232 */ 233 CX_ARRAY_DECLARE(CxJsonObjValue, values); 234 /** 235 * The original indices to reconstruct the order in which the members were added. 236 */ 237 size_t *indices; 238 }; 239 240 /** 241 * Structure for a key/value entry in a JSON object. 242 */ 243 struct cx_json_obj_value_s { 244 /** 245 * The key (or name in JSON terminology) of the value. 246 */ 247 cxmutstr name; 248 /** 249 * The value. 250 */ 251 CxJsonValue *value; 252 }; 253 254 /** 255 * Structure for a JSON value. 256 */ 257 struct cx_json_value_s { 258 /** 259 * The allocator with which the value was allocated. 260 * 261 * Required for recursively deallocating memory of objects and arrays. 262 */ 263 const CxAllocator *allocator; 264 /** 265 * The type of this value. 266 * 267 * Specifies how the @c value union shall be resolved. 268 */ 269 CxJsonValueType type; 270 /** 271 * The value data. 272 */ 273 union { 274 /** 275 * The array data if type is #CX_JSON_ARRAY. 276 */ 277 CxJsonArray array; 278 /** 279 * The object data if type is #CX_JSON_OBJECT. 280 */ 281 CxJsonObject object; 282 /** 283 * The string data if type is #CX_JSON_STRING. 284 */ 285 CxJsonString string; 286 /** 287 * The integer if type is #CX_JSON_INTEGER. 288 */ 289 CxJsonInteger integer; 290 /** 291 * The number if type is #CX_JSON_NUMBER. 292 */ 293 CxJsonNumber number; 294 /** 295 * The literal type if type is #CX_JSON_LITERAL. 296 */ 297 CxJsonLiteral literal; 298 } value; 299 }; 300 301 /** 302 * Internally used structure for a parsed token. 303 * 304 * You should never need to use this in your code. 305 */ 306 struct cx_json_token_s { 307 /** 308 * The token type. 309 */ 310 CxJsonTokenType tokentype; 311 /** 312 * True, if the @c content must be passed to cx_strfree(). 313 */ 314 bool allocated; 315 /** 316 * The token text, if any. 317 * 318 * This is not necessarily set when the token type already 319 * uniquely identifies the content. 320 */ 321 cxmutstr content; 322 }; 323 324 /** 325 * The JSON parser interface. 326 */ 327 struct cx_json_s { 328 /** 329 * The allocator used for produced JSON values. 330 */ 331 const CxAllocator *allocator; 332 /** 333 * The input buffer. 334 */ 335 CxBuffer buffer; 336 337 /** 338 * Used internally. 339 * 340 * Remembers the prefix of the last uncompleted token. 341 */ 342 CxJsonToken uncompleted; 343 344 /** 345 * A pointer to an intermediate state of the currently parsed value. 346 * 347 * Never access this value manually. 348 */ 349 CxJsonValue *parsed; 350 351 /** 352 * A pointer to an intermediate state of a currently parsed object member. 353 * 354 * Never access this value manually. 355 */ 356 CxJsonObjValue uncompleted_member; 357 358 /** 359 * State stack. 360 */ 361 CX_ARRAY_DECLARE_SIZED(int, states, unsigned); 362 363 /** 364 * Value buffer stack. 365 */ 366 CX_ARRAY_DECLARE_SIZED(CxJsonValue*, vbuf, unsigned); 367 368 /** 369 * Internally reserved memory for the state stack. 370 */ 371 int states_internal[8]; 372 373 /** 374 * Internally reserved memory for the value buffer stack. 375 */ 376 CxJsonValue* vbuf_internal[8]; 377 }; 378 379 /** 380 * Status codes for the json interface. 381 */ 382 enum cx_json_status { 383 /** 384 * Everything is fine. 385 */ 386 CX_JSON_NO_ERROR, 387 /** 388 * The input buffer does not contain more data. 389 */ 390 CX_JSON_NO_DATA, 391 /** 392 * The input ends unexpectedly. 393 * 394 * Refill the buffer with cxJsonFill() to complete the json data. 395 */ 396 CX_JSON_INCOMPLETE_DATA, 397 /** 398 * Not used as a status and never returned by any function. 399 * 400 * You can use this enumerator to check for all "good" status results 401 * by checking if the status is less than @c CX_JSON_OK. 402 * 403 * A "good" status means, that you can refill data and continue parsing. 404 */ 405 CX_JSON_OK, 406 /** 407 * The input buffer has never been filled. 408 */ 409 CX_JSON_NULL_DATA, 410 /** 411 * Allocating memory for the internal buffer failed. 412 */ 413 CX_JSON_BUFFER_ALLOC_FAILED, 414 /** 415 * Allocating memory for a json value failed. 416 */ 417 CX_JSON_VALUE_ALLOC_FAILED, 418 /** 419 * A number value is incorrectly formatted. 420 */ 421 CX_JSON_FORMAT_ERROR_NUMBER, 422 /** 423 * The tokenizer found something unexpected. 424 */ 425 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN 426 }; 427 428 /** 429 * Typedef for the json status enum. 430 */ 431 typedef enum cx_json_status CxJsonStatus; 432 433 /** 434 * The JSON writer settings. 435 */ 436 struct cx_json_writer_s { 437 /** 438 * Set true to enable pretty output. 439 */ 440 bool pretty; 441 /** 442 * Set false to output the members in the order in which they were added. 443 */ 444 bool sort_members; 445 /** 446 * The maximum number of fractional digits in a number value. 447 * The default value is 6 and values larger than 15 are reduced to 15. 448 * Note, that the actual number of digits may be lower, depending on the concrete number. 449 */ 450 uint8_t frac_max_digits; 451 /** 452 * Set true to use spaces instead of tab characters. 453 * Indentation is only used in pretty output. 454 */ 455 bool indent_space; 456 /** 457 * If @c indent_space is true, this is the number of spaces per tab. 458 * Indentation is only used in pretty output. 459 */ 460 uint8_t indent; 461 /** 462 * Set true to enable escaping of the slash character (solidus). 463 */ 464 bool escape_slash; 465 }; 466 467 /** 468 * Typedef for the json writer. 469 */ 470 typedef struct cx_json_writer_s CxJsonWriter; 471 472 /** 473 * Creates a default writer configuration for compact output. 474 * 475 * @return new JSON writer settings 476 */ 477 cx_attr_nodiscard 478 cx_attr_export 479 CxJsonWriter cxJsonWriterCompact(void); 480 481 /** 482 * Creates a default writer configuration for pretty output. 483 * 484 * @param use_spaces false if you want tabs, true if you want four spaces instead 485 * @return new JSON writer settings 486 */ 487 cx_attr_nodiscard 488 cx_attr_export 489 CxJsonWriter cxJsonWriterPretty(bool use_spaces); 490 491 /** 492 * Writes a JSON value to a buffer or stream. 493 * 494 * This function blocks until either all data is written, or an error occurs. 495 * The write operation is not atomic in the sense that it might happen 496 * that the data is only partially written when an error occurs with no 497 * way to indicate how much data was written. 498 * To avoid this problem, you can use a CxBuffer as @p target which is 499 * unlikely to fail a write operation and either use the buffer's flush 500 * feature to relay the data or use the data in the buffer manually to 501 * write it to the actual target. 502 * 503 * @param target the buffer or stream where to write to 504 * @param value the value that shall be written 505 * @param wfunc the write function to use 506 * @param settings formatting settings (or @c NULL to use a compact default) 507 * @retval zero success 508 * @retval non-zero when no or not all data could be written 509 */ 510 cx_attr_nonnull_arg(1, 2, 3) 511 cx_attr_export 512 int cxJsonWrite( 513 void* target, 514 const CxJsonValue* value, 515 cx_write_func wfunc, 516 const CxJsonWriter* settings 517 ); 518 519 /** 520 * Initializes the json interface. 521 * 522 * @param json the json interface 523 * @param allocator the allocator that shall be used for the produced values 524 * @see cxJsonDestroy() 525 */ 526 cx_attr_nonnull_arg(1) 527 cx_attr_export 528 void cxJsonInit(CxJson *json, const CxAllocator *allocator); 529 530 /** 531 * Destroys the json interface. 532 * 533 * @param json the json interface 534 * @see cxJsonInit() 535 */ 536 cx_attr_nonnull 537 cx_attr_export 538 void cxJsonDestroy(CxJson *json); 539 540 /** 541 * Destroys and re-initializes the json interface. 542 * 543 * You might want to use this, to reset the parser after 544 * encountering a syntax error. 545 * 546 * @param json the json interface 547 */ 548 cx_attr_nonnull 549 static inline void cxJsonReset(CxJson *json) { 550 const CxAllocator *allocator = json->allocator; 551 cxJsonDestroy(json); 552 cxJsonInit(json, allocator); 553 } 554 555 /** 556 * Fills the input buffer. 557 * 558 * @remark The JSON interface tries to avoid copying the input data. 559 * When you use this function and cxJsonNext() interleaving, 560 * no copies are performed. However, you must not free the 561 * pointer to the data in that case. When you invoke the fill 562 * function more than once before calling cxJsonNext(), 563 * the additional data is appended - inevitably leading to 564 * an allocation of a new buffer and copying the previous contents. 565 * 566 * @param json the json interface 567 * @param buf the source buffer 568 * @param len the length of the source buffer 569 * @retval zero success 570 * @retval non-zero internal allocation error 571 * @see cxJsonFill() 572 */ 573 cx_attr_nonnull 574 cx_attr_access_r(2, 3) 575 cx_attr_export 576 int cxJsonFilln(CxJson *json, const char *buf, size_t len); 577 578 #ifdef __cplusplus 579 } // extern "C" 580 581 cx_attr_nonnull 582 static inline int cxJsonFill( 583 CxJson *json, 584 cxstring str 585 ) { 586 return cxJsonFilln(json, str.ptr, str.length); 587 } 588 589 cx_attr_nonnull 590 static inline int cxJsonFill( 591 CxJson *json, 592 cxmutstr str 593 ) { 594 return cxJsonFilln(json, str.ptr, str.length); 595 } 596 597 cx_attr_nonnull 598 cx_attr_cstr_arg(2) 599 static inline int cxJsonFill( 600 CxJson *json, 601 const char *str 602 ) { 603 return cxJsonFilln(json, str, strlen(str)); 604 } 605 606 extern "C" { 607 #else // __cplusplus 608 /** 609 * Fills the input buffer. 610 * 611 * The JSON interface tries to avoid copying the input data. 612 * When you use this function and cxJsonNext() interleaving, 613 * no copies are performed. However, you must not free the 614 * pointer to the data in that case. When you invoke the fill 615 * function more than once before calling cxJsonNext(), 616 * the additional data is appended - inevitably leading to 617 * an allocation of a new buffer and copying the previous contents. 618 * 619 * @param json the json interface 620 * @param str the source string 621 * @retval zero success 622 * @retval non-zero internal allocation error 623 * @see cxJsonFilln() 624 */ 625 #define cxJsonFill(json, str) _Generic((str), \ 626 cxstring: cx_json_fill_cxstr, \ 627 cxmutstr: cx_json_fill_mutstr, \ 628 char*: cx_json_fill_str, \ 629 const char*: cx_json_fill_str) \ 630 (json, str) 631 632 /** 633 * @copydoc cxJsonFill() 634 */ 635 cx_attr_nonnull 636 static inline int cx_json_fill_cxstr( 637 CxJson *json, 638 cxstring str 639 ) { 640 return cxJsonFilln(json, str.ptr, str.length); 641 } 642 643 /** 644 * @copydoc cxJsonFill() 645 */ 646 cx_attr_nonnull 647 static inline int cx_json_fill_mutstr( 648 CxJson *json, 649 cxmutstr str 650 ) { 651 return cxJsonFilln(json, str.ptr, str.length); 652 } 653 654 /** 655 * @copydoc cxJsonFill() 656 */ 657 cx_attr_nonnull 658 cx_attr_cstr_arg(2) 659 static inline int cx_json_fill_str( 660 CxJson *json, 661 const char *str 662 ) { 663 return cxJsonFilln(json, str, strlen(str)); 664 } 665 #endif 666 667 /** 668 * Creates a new (empty) JSON object. 669 * 670 * @param allocator the allocator to use 671 * @return the new JSON object or @c NULL if allocation fails 672 * @see cxJsonObjPutObj() 673 * @see cxJsonArrAddValues() 674 */ 675 cx_attr_nodiscard 676 cx_attr_export 677 CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator); 678 679 /** 680 * Creates a new (empty) JSON array. 681 * 682 * @param allocator the allocator to use 683 * @return the new JSON array or @c NULL if allocation fails 684 * @see cxJsonObjPutArr() 685 * @see cxJsonArrAddValues() 686 */ 687 cx_attr_nodiscard 688 cx_attr_export 689 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator); 690 691 /** 692 * Creates a new JSON number value. 693 * 694 * @param allocator the allocator to use 695 * @param num the numeric value 696 * @return the new JSON value or @c NULL if allocation fails 697 * @see cxJsonObjPutNumber() 698 * @see cxJsonArrAddNumbers() 699 */ 700 cx_attr_nodiscard 701 cx_attr_export 702 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num); 703 704 /** 705 * Creates a new JSON number value based on an integer. 706 * 707 * @param allocator the allocator to use 708 * @param num the numeric value 709 * @return the new JSON value or @c NULL if allocation fails 710 * @see cxJsonObjPutInteger() 711 * @see cxJsonArrAddIntegers() 712 */ 713 cx_attr_nodiscard 714 cx_attr_export 715 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num); 716 717 /** 718 * Creates a new JSON string. 719 * 720 * @param allocator the allocator to use 721 * @param str the string data 722 * @return the new JSON value or @c NULL if allocation fails 723 * @see cxJsonCreateString() 724 * @see cxJsonObjPutString() 725 * @see cxJsonArrAddStrings() 726 */ 727 cx_attr_nodiscard 728 cx_attr_nonnull_arg(2) 729 cx_attr_cstr_arg(2) 730 cx_attr_export 731 CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str); 732 733 /** 734 * Creates a new JSON string. 735 * 736 * @param allocator the allocator to use 737 * @param str the string data 738 * @return the new JSON value or @c NULL if allocation fails 739 * @see cxJsonCreateCxString() 740 * @see cxJsonObjPutCxString() 741 * @see cxJsonArrAddCxStrings() 742 */ 743 cx_attr_nodiscard 744 cx_attr_export 745 CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str); 746 747 /** 748 * Creates a new JSON literal. 749 * 750 * @param allocator the allocator to use 751 * @param lit the type of literal 752 * @return the new JSON value or @c NULL if allocation fails 753 * @see cxJsonObjPutLiteral() 754 * @see cxJsonArrAddLiterals() 755 */ 756 cx_attr_nodiscard 757 cx_attr_export 758 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit); 759 760 /** 761 * Adds number values to a JSON array. 762 * 763 * @param arr the JSON array 764 * @param num the array of values 765 * @param count the number of elements 766 * @retval zero success 767 * @retval non-zero allocation failure 768 */ 769 cx_attr_nonnull 770 cx_attr_access_r(2, 3) 771 cx_attr_export 772 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count); 773 774 /** 775 * Adds number values, of which all are integers, to a JSON array. 776 * 777 * @param arr the JSON array 778 * @param num the array of values 779 * @param count the number of elements 780 * @retval zero success 781 * @retval non-zero allocation failure 782 */ 783 cx_attr_nonnull 784 cx_attr_access_r(2, 3) 785 cx_attr_export 786 int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count); 787 788 /** 789 * Adds strings to a JSON array. 790 * 791 * The strings will be copied with the allocator of the array. 792 * 793 * @param arr the JSON array 794 * @param str the array of strings 795 * @param count the number of elements 796 * @retval zero success 797 * @retval non-zero allocation failure 798 * @see cxJsonArrAddCxStrings() 799 */ 800 cx_attr_nonnull 801 cx_attr_access_r(2, 3) 802 cx_attr_export 803 int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count); 804 805 /** 806 * Adds strings to a JSON array. 807 * 808 * The strings will be copied with the allocator of the array. 809 * 810 * @param arr the JSON array 811 * @param str the array of strings 812 * @param count the number of elements 813 * @retval zero success 814 * @retval non-zero allocation failure 815 * @see cxJsonArrAddStrings() 816 */ 817 cx_attr_nonnull 818 cx_attr_access_r(2, 3) 819 cx_attr_export 820 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count); 821 822 /** 823 * Adds literals to a JSON array. 824 * 825 * @param arr the JSON array 826 * @param lit the array of literal types 827 * @param count the number of elements 828 * @retval zero success 829 * @retval non-zero allocation failure 830 */ 831 cx_attr_nonnull 832 cx_attr_access_r(2, 3) 833 cx_attr_export 834 int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count); 835 836 /** 837 * Add arbitrary values to a JSON array. 838 * 839 * @attention In contrast to all other add functions, this function adds the values 840 * directly to the array instead of copying them. 841 * 842 * @param arr the JSON array 843 * @param val the values 844 * @param count the number of elements 845 * @retval zero success 846 * @retval non-zero allocation failure 847 */ 848 cx_attr_nonnull 849 cx_attr_access_r(2, 3) 850 cx_attr_export 851 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count); 852 853 /** 854 * Adds or replaces a value within a JSON object. 855 * 856 * The value will be directly added and not copied. 857 * 858 * @note If a value with the specified @p name already exists, 859 * it will be (recursively) freed with its own allocator. 860 * 861 * @param obj the JSON object 862 * @param name the name of the value 863 * @param child the value 864 * @retval zero success 865 * @retval non-zero allocation failure 866 */ 867 cx_attr_nonnull 868 cx_attr_export 869 int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child); 870 871 /** 872 * Creates a new JSON object and adds it to an existing object. 873 * 874 * @param obj the target JSON object 875 * @param name the name of the new value 876 * @return the new value or @c NULL if allocation fails 877 * @see cxJsonObjPut() 878 * @see cxJsonCreateObj() 879 */ 880 cx_attr_nonnull 881 cx_attr_export 882 CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name); 883 884 /** 885 * Creates a new JSON array and adds it to an object. 886 * 887 * @param obj the target JSON object 888 * @param name the name of the new value 889 * @return the new value or @c NULL if allocation fails 890 * @see cxJsonObjPut() 891 * @see cxJsonCreateArr() 892 */ 893 cx_attr_nonnull 894 cx_attr_export 895 CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name); 896 897 /** 898 * Creates a new JSON number and adds it to an object. 899 * 900 * @param obj the target JSON object 901 * @param name the name of the new value 902 * @param num the numeric value 903 * @return the new value or @c NULL if allocation fails 904 * @see cxJsonObjPut() 905 * @see cxJsonCreateNumber() 906 */ 907 cx_attr_nonnull 908 cx_attr_export 909 CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num); 910 911 /** 912 * Creates a new JSON number, based on an integer, and adds it to an object. 913 * 914 * @param obj the target JSON object 915 * @param name the name of the new value 916 * @param num the numeric value 917 * @return the new value or @c NULL if allocation fails 918 * @see cxJsonObjPut() 919 * @see cxJsonCreateInteger() 920 */ 921 cx_attr_nonnull 922 cx_attr_export 923 CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num); 924 925 /** 926 * Creates a new JSON string and adds it to an object. 927 * 928 * The string data is copied. 929 * 930 * @param obj the target JSON object 931 * @param name the name of the new value 932 * @param str the string data 933 * @return the new value or @c NULL if allocation fails 934 * @see cxJsonObjPut() 935 * @see cxJsonCreateString() 936 */ 937 cx_attr_nonnull 938 cx_attr_cstr_arg(3) 939 cx_attr_export 940 CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str); 941 942 /** 943 * Creates a new JSON string and adds it to an object. 944 * 945 * The string data is copied. 946 * 947 * @param obj the target JSON object 948 * @param name the name of the new value 949 * @param str the string data 950 * @return the new value or @c NULL if allocation fails 951 * @see cxJsonObjPut() 952 * @see cxJsonCreateCxString() 953 */ 954 cx_attr_nonnull 955 cx_attr_export 956 CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str); 957 958 /** 959 * Creates a new JSON literal and adds it to an object. 960 * 961 * @param obj the target JSON object 962 * @param name the name of the new value 963 * @param lit the type of literal 964 * @return the new value or @c NULL if allocation fails 965 * @see cxJsonObjPut() 966 * @see cxJsonCreateLiteral() 967 */ 968 cx_attr_nonnull 969 cx_attr_export 970 CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit); 971 972 /** 973 * Recursively deallocates the memory of a JSON value. 974 * 975 * @remark The type of each deallocated value will be changed 976 * to #CX_JSON_NOTHING and values of such type will be skipped 977 * by the de-allocation. That means, this function protects 978 * you from double-frees when you are accidentally freeing 979 * a nested value and then the parent value (or vice versa). 980 * 981 * @param value the value 982 */ 983 cx_attr_export 984 void cxJsonValueFree(CxJsonValue *value); 985 986 /** 987 * Tries to obtain the next JSON value. 988 * 989 * Before this function can be called, the input buffer needs 990 * to be filled with cxJsonFill(). 991 * 992 * When this function returns #CX_JSON_INCOMPLETE_DATA, you can 993 * add the missing data with another invocation of cxJsonFill() 994 * and then repeat the call to cxJsonNext(). 995 * 996 * @param json the json interface 997 * @param value a pointer where the next value shall be stored 998 * @retval CX_JSON_NO_ERROR successfully retrieve the @p value 999 * @retval CX_JSON_NO_DATA there is no (more) data in the buffer to read from 1000 * @retval CX_JSON_INCOMPLETE_DATA an incomplete value was read 1001 * and more data needs to be filled 1002 * @retval CX_JSON_NULL_DATA the buffer was never initialized 1003 * @retval CX_JSON_BUFFER_ALLOC_FAILED allocating internal buffer space failed 1004 * @retval CX_JSON_VALUE_ALLOC_FAILED allocating memory for a CxJsonValue failed 1005 * @retval CX_JSON_FORMAT_ERROR_NUMBER the JSON text contains an illegally formatted number 1006 * @retval CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN JSON syntax error 1007 */ 1008 cx_attr_nonnull 1009 cx_attr_access_w(2) 1010 cx_attr_export 1011 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value); 1012 1013 /** 1014 * Checks if the specified value is a JSON object. 1015 * 1016 * @param value a pointer to the value 1017 * @retval true the value is a JSON object 1018 * @retval false otherwise 1019 */ 1020 cx_attr_nonnull 1021 static inline bool cxJsonIsObject(const CxJsonValue *value) { 1022 return value->type == CX_JSON_OBJECT; 1023 } 1024 1025 /** 1026 * Checks if the specified value is a JSON array. 1027 * 1028 * @param value a pointer to the value 1029 * @retval true the value is a JSON array 1030 * @retval false otherwise 1031 */ 1032 cx_attr_nonnull 1033 static inline bool cxJsonIsArray(const CxJsonValue *value) { 1034 return value->type == CX_JSON_ARRAY; 1035 } 1036 1037 /** 1038 * Checks if the specified value is a string. 1039 * 1040 * @param value a pointer to the value 1041 * @retval true the value is a string 1042 * @retval false otherwise 1043 */ 1044 cx_attr_nonnull 1045 static inline bool cxJsonIsString(const CxJsonValue *value) { 1046 return value->type == CX_JSON_STRING; 1047 } 1048 1049 /** 1050 * Checks if the specified value is a JSON number. 1051 * 1052 * This function will return true for both floating point and 1053 * integer numbers. 1054 * 1055 * @param value a pointer to the value 1056 * @retval true the value is a JSON number 1057 * @retval false otherwise 1058 * @see cxJsonIsInteger() 1059 */ 1060 cx_attr_nonnull 1061 static inline bool cxJsonIsNumber(const CxJsonValue *value) { 1062 return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER; 1063 } 1064 1065 /** 1066 * Checks if the specified value is an integer number. 1067 * 1068 * @param value a pointer to the value 1069 * @retval true the value is an integer number 1070 * @retval false otherwise 1071 * @see cxJsonIsNumber() 1072 */ 1073 cx_attr_nonnull 1074 static inline bool cxJsonIsInteger(const CxJsonValue *value) { 1075 return value->type == CX_JSON_INTEGER; 1076 } 1077 1078 /** 1079 * Checks if the specified value is a JSON literal. 1080 * 1081 * JSON literals are @c true, @c false, and @c null. 1082 * 1083 * @param value a pointer to the value 1084 * @retval true the value is a JSON literal 1085 * @retval false otherwise 1086 * @see cxJsonIsTrue() 1087 * @see cxJsonIsFalse() 1088 * @see cxJsonIsNull() 1089 */ 1090 cx_attr_nonnull 1091 static inline bool cxJsonIsLiteral(const CxJsonValue *value) { 1092 return value->type == CX_JSON_LITERAL; 1093 } 1094 1095 /** 1096 * Checks if the specified value is a Boolean literal. 1097 * 1098 * @param value a pointer to the value 1099 * @retval true the value is either @c true or @c false 1100 * @retval false otherwise 1101 * @see cxJsonIsTrue() 1102 * @see cxJsonIsFalse() 1103 */ 1104 cx_attr_nonnull 1105 static inline bool cxJsonIsBool(const CxJsonValue *value) { 1106 return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL; 1107 } 1108 1109 /** 1110 * Checks if the specified value is @c true. 1111 * 1112 * @remark Be advised, that this is not the same as 1113 * testing @c !cxJsonIsFalse(v). 1114 * 1115 * @param value a pointer to the value 1116 * @retval true the value is @c true 1117 * @retval false otherwise 1118 * @see cxJsonIsBool() 1119 * @see cxJsonIsFalse() 1120 */ 1121 cx_attr_nonnull 1122 static inline bool cxJsonIsTrue(const CxJsonValue *value) { 1123 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE; 1124 } 1125 1126 /** 1127 * Checks if the specified value is @c false. 1128 * 1129 * @remark Be advised, that this is not the same as 1130 * testing @c !cxJsonIsTrue(v). 1131 * 1132 * @param value a pointer to the value 1133 * @retval true the value is @c false 1134 * @retval false otherwise 1135 * @see cxJsonIsBool() 1136 * @see cxJsonIsTrue() 1137 */ 1138 cx_attr_nonnull 1139 static inline bool cxJsonIsFalse(const CxJsonValue *value) { 1140 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE; 1141 } 1142 1143 /** 1144 * Checks if the specified value is @c null. 1145 * 1146 * @param value a pointer to the value 1147 * @retval true the value is @c null 1148 * @retval false otherwise 1149 * @see cxJsonIsLiteral() 1150 */ 1151 cx_attr_nonnull 1152 static inline bool cxJsonIsNull(const CxJsonValue *value) { 1153 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL; 1154 } 1155 1156 /** 1157 * Obtains a C string from the given JSON value. 1158 * 1159 * If the @p value is not a string, the behavior is undefined. 1160 * 1161 * @param value the JSON value 1162 * @return the value represented as C string 1163 * @see cxJsonIsString() 1164 */ 1165 cx_attr_nonnull 1166 cx_attr_returns_nonnull 1167 static inline char *cxJsonAsString(const CxJsonValue *value) { 1168 return value->value.string.ptr; 1169 } 1170 1171 /** 1172 * Obtains a UCX string from the given JSON value. 1173 * 1174 * If the @p value is not a string, the behavior is undefined. 1175 * 1176 * @param value the JSON value 1177 * @return the value represented as UCX string 1178 * @see cxJsonIsString() 1179 */ 1180 cx_attr_nonnull 1181 static inline cxstring cxJsonAsCxString(const CxJsonValue *value) { 1182 return cx_strcast(value->value.string); 1183 } 1184 1185 /** 1186 * Obtains a mutable UCX string from the given JSON value. 1187 * 1188 * If the @p value is not a string, the behavior is undefined. 1189 * 1190 * @param value the JSON value 1191 * @return the value represented as mutable UCX string 1192 * @see cxJsonIsString() 1193 */ 1194 cx_attr_nonnull 1195 static inline cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { 1196 return value->value.string; 1197 } 1198 1199 /** 1200 * Obtains a double-precision floating point value from the given JSON value. 1201 * 1202 * If the @p value is not a JSON number, the behavior is undefined. 1203 * 1204 * @param value the JSON value 1205 * @return the value represented as double 1206 * @see cxJsonIsNumber() 1207 */ 1208 cx_attr_nonnull 1209 static inline double cxJsonAsDouble(const CxJsonValue *value) { 1210 if (value->type == CX_JSON_INTEGER) { 1211 return (double) value->value.integer; 1212 } else { 1213 return value->value.number; 1214 } 1215 } 1216 1217 /** 1218 * Obtains a 64-bit signed integer from the given JSON value. 1219 * 1220 * If the @p value is not a JSON number, the behavior is undefined. 1221 * If it is a JSON number, but not an integer, the value will be 1222 * converted to an integer, possibly losing precision. 1223 * 1224 * @param value the JSON value 1225 * @return the value represented as double 1226 * @see cxJsonIsNumber() 1227 * @see cxJsonIsInteger() 1228 */ 1229 cx_attr_nonnull 1230 static inline int64_t cxJsonAsInteger(const CxJsonValue *value) { 1231 if (value->type == CX_JSON_INTEGER) { 1232 return value->value.integer; 1233 } else { 1234 return (int64_t) value->value.number; 1235 } 1236 } 1237 1238 /** 1239 * Obtains a Boolean value from the given JSON value. 1240 * 1241 * If the @p value is not a JSON literal, the behavior is undefined. 1242 * The @c null literal is interpreted as @c false. 1243 * 1244 * @param value the JSON value 1245 * @return the value represented as double 1246 * @see cxJsonIsLiteral() 1247 */ 1248 cx_attr_nonnull 1249 static inline bool cxJsonAsBool(const CxJsonValue *value) { 1250 return value->value.literal == CX_JSON_TRUE; 1251 } 1252 1253 /** 1254 * Returns the size of a JSON array. 1255 * 1256 * If the @p value is not a JSON array, the behavior is undefined. 1257 * 1258 * @param value the JSON value 1259 * @return the size of the array 1260 * @see cxJsonIsArray() 1261 */ 1262 cx_attr_nonnull 1263 static inline size_t cxJsonArrSize(const CxJsonValue *value) { 1264 return value->value.array.array_size; 1265 } 1266 1267 /** 1268 * Returns an element from a JSON array. 1269 * 1270 * If the @p value is not a JSON array, the behavior is undefined. 1271 * 1272 * This function guarantees to return a value. If the index is 1273 * out of bounds, the returned value will be of type 1274 * #CX_JSON_NOTHING, but never @c NULL. 1275 * 1276 * @param value the JSON value 1277 * @param index the index in the array 1278 * @return the value at the specified index 1279 * @see cxJsonIsArray() 1280 */ 1281 cx_attr_nonnull 1282 cx_attr_returns_nonnull 1283 cx_attr_export 1284 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index); 1285 1286 /** 1287 * Returns an iterator over the JSON array elements. 1288 * 1289 * The iterator yields values of type @c CxJsonValue* . 1290 * 1291 * If the @p value is not a JSON array, the behavior is undefined. 1292 * 1293 * @param value the JSON value 1294 * @return an iterator over the array elements 1295 * @see cxJsonIsArray() 1296 */ 1297 cx_attr_nonnull 1298 cx_attr_nodiscard 1299 cx_attr_export 1300 CxIterator cxJsonArrIter(const CxJsonValue *value); 1301 1302 /** 1303 * Returns an iterator over the JSON object members. 1304 * 1305 * The iterator yields values of type @c CxJsonObjValue* which 1306 * contain the name and value of the member. 1307 * 1308 * If the @p value is not a JSON object, the behavior is undefined. 1309 * 1310 * @param value the JSON value 1311 * @return an iterator over the object members 1312 * @see cxJsonIsObject() 1313 */ 1314 cx_attr_nonnull 1315 cx_attr_nodiscard 1316 cx_attr_export 1317 CxIterator cxJsonObjIter(const CxJsonValue *value); 1318 1319 /** 1320 * @copydoc cxJsonObjGet() 1321 */ 1322 cx_attr_nonnull 1323 cx_attr_returns_nonnull 1324 cx_attr_export 1325 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name); 1326 1327 #ifdef __cplusplus 1328 } // extern "C" 1329 1330 static inline CxJsonValue *cxJsonObjGet(const CxJsonValue *value, cxstring name) { 1331 return cx_json_obj_get_cxstr(value, name); 1332 } 1333 1334 static inline CxJsonValue *cxJsonObjGet(const CxJsonValue *value, cxmutstr name) { 1335 return cx_json_obj_get_cxstr(value, cx_strcast(name)); 1336 } 1337 1338 static inline CxJsonValue *cxJsonObjGet(const CxJsonValue *value, const char *name) { 1339 return cx_json_obj_get_cxstr(value, cx_str(name)); 1340 } 1341 1342 extern "C" { 1343 #else 1344 /** 1345 * Returns a value corresponding to a key in a JSON object. 1346 * 1347 * If the @p value is not a JSON object, the behavior is undefined. 1348 * 1349 * This function guarantees to return a JSON value. If the 1350 * object does not contain @p name, the returned JSON value 1351 * will be of type #CX_JSON_NOTHING, but never @c NULL. 1352 * 1353 * @param value the JSON object 1354 * @param name the key to look up 1355 * @return the value corresponding to the key 1356 * @see cxJsonIsObject() 1357 */ 1358 #define cxJsonObjGet(value, name) _Generic((name), \ 1359 cxstring: cx_json_obj_get_cxstr, \ 1360 cxmutstr: cx_json_obj_get_mutstr, \ 1361 char*: cx_json_obj_get_str, \ 1362 const char*: cx_json_obj_get_str) \ 1363 (value, name) 1364 1365 /** 1366 * @copydoc cxJsonObjGet() 1367 */ 1368 cx_attr_nonnull 1369 cx_attr_returns_nonnull 1370 static inline CxJsonValue *cx_json_obj_get_mutstr(const CxJsonValue *value, cxmutstr name) { 1371 return cx_json_obj_get_cxstr(value, cx_strcast(name)); 1372 } 1373 1374 /** 1375 * @copydoc cxJsonObjGet() 1376 */ 1377 cx_attr_nonnull 1378 cx_attr_returns_nonnull 1379 cx_attr_cstr_arg(2) 1380 static inline CxJsonValue *cx_json_obj_get_str(const CxJsonValue *value, const char *name) { 1381 return cx_json_obj_get_cxstr(value, cx_str(name)); 1382 } 1383 #endif 1384 1385 #ifdef __cplusplus 1386 } 1387 #endif 1388 1389 #endif /* UCX_JSON_H */ 1390 1391