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