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 an integer. 94 */ 95 CX_JSON_TOKEN_INTEGER, 96 /** 97 * A number token that cannot be represented as an 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 a 64-bit signed integer. 200 */ 201 typedef int64_t CxJsonInteger; 202 /** 203 * Type alias for a 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 the type is #CX_JSON_ARRAY. 276 */ 277 CxJsonArray array; 278 /** 279 * The object data if the type is #CX_JSON_OBJECT. 280 */ 281 CxJsonObject object; 282 /** 283 * The string data if the type is #CX_JSON_STRING. 284 */ 285 CxJsonString string; 286 /** 287 * The integer if the type is #CX_JSON_INTEGER. 288 */ 289 CxJsonInteger integer; 290 /** 291 * The number if the type is #CX_JSON_NUMBER. 292 */ 293 CxJsonNumber number; 294 /** 295 * The literal type if the 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_EXPORT CxJsonWriter cxJsonWriterCompact(void); 479 480 /** 481 * Creates a default writer configuration for pretty output. 482 * 483 * @param use_spaces false if you want tabs, true if you want four spaces instead 484 * @return new JSON writer settings 485 */ 486 cx_attr_nodiscard 487 CX_EXPORT CxJsonWriter cxJsonWriterPretty(bool use_spaces); 488 489 /** 490 * Writes a JSON value to a buffer or stream. 491 * 492 * This function blocks until either all data is written, or an error occurs. 493 * The write operation is not atomic in the sense that it might happen 494 * that the data is only partially written when an error occurs with no 495 * way to indicate how much data was written. 496 * To avoid this problem, you can use a CxBuffer as @p target which is 497 * unlikely to fail a write operation. You can, for example, use the buffer's flush 498 * feature to relay the data. 499 * 500 * @param target the buffer or stream where to write to 501 * @param value the value that shall be written 502 * @param wfunc the write function to use 503 * @param settings formatting settings (or @c NULL to use a compact default) 504 * @retval zero success 505 * @retval non-zero when no or not all data could be written 506 */ 507 cx_attr_nonnull_arg(1, 2, 3) 508 CX_EXPORT int cxJsonWrite(void* target, const CxJsonValue* value, 509 cx_write_func wfunc, const CxJsonWriter* settings); 510 511 /** 512 * Initializes the JSON interface. 513 * 514 * @param json the JSON interface 515 * @param allocator the allocator that shall be used for the produced values 516 * @see cxJsonDestroy() 517 */ 518 cx_attr_nonnull_arg(1) 519 CX_EXPORT void cxJsonInit(CxJson *json, const CxAllocator *allocator); 520 521 /** 522 * Destroys the JSON interface. 523 * 524 * @param json the JSON interface 525 * @see cxJsonInit() 526 */ 527 cx_attr_nonnull 528 CX_EXPORT void cxJsonDestroy(CxJson *json); 529 530 /** 531 * Destroys and re-initializes the JSON interface. 532 * 533 * You might want to use this to reset the parser after 534 * encountering a syntax error. 535 * 536 * @param json the JSON interface 537 */ 538 cx_attr_nonnull 539 CX_EXPORT void cxJsonReset(CxJson *json); 540 541 /** 542 * Fills the input buffer. 543 * 544 * @remark The JSON interface tries to avoid copying the input data. 545 * When you use this function and cxJsonNext() interleaving, 546 * no copies are performed. However, you must not free the 547 * pointer to the data in that case. When you invoke the fill 548 * function more than once before calling cxJsonNext(), 549 * the additional data is appended - inevitably leading to 550 * an allocation of a new buffer and copying the previous contents. 551 * 552 * @param json the JSON interface 553 * @param buf the source buffer 554 * @param len the length of the source buffer 555 * @retval zero success 556 * @retval non-zero internal allocation error 557 * @see cxJsonFill() 558 */ 559 cx_attr_nonnull_arg(1) cx_attr_access_r(2, 3) 560 CX_EXPORT int cxJsonFilln(CxJson *json, const char *buf, size_t len); 561 562 563 /** 564 * Internal function, do not use. 565 * 566 * @param json the JSON interface 567 * @param str the string 568 * @retval zero success 569 * @retval non-zero internal allocation error 570 */ 571 cx_attr_nonnull 572 CX_INLINE int cx_json_fill(CxJson *json, cxstring str) { 573 return cxJsonFilln(json, str.ptr, str.length); 574 } 575 576 /** 577 * Fills the input buffer. 578 * 579 * The JSON interface tries to avoid copying the input data. 580 * When you use this function and cxJsonNext() interleaving, 581 * no copies are performed. However, you must not free the 582 * pointer to the data in that case. When you invoke the fill 583 * function more than once before calling cxJsonNext(), 584 * the additional data is appended - inevitably leading to 585 * an allocation of a new buffer and copying the previous contents. 586 * 587 * @param json the JSON interface 588 * @param str the source string 589 * @retval zero success 590 * @retval non-zero internal allocation error 591 * @see cxJsonFilln() 592 */ 593 #define cxJsonFill(json, str) cx_json_fill(json, cx_strcast(str)) 594 595 /** 596 * Creates a new (empty) JSON object. 597 * 598 * @param allocator the allocator to use 599 * @return the new JSON object or @c NULL if allocation fails 600 * @see cxJsonObjPutObj() 601 * @see cxJsonArrAddValues() 602 */ 603 cx_attr_nodiscard 604 CX_EXPORT CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator); 605 606 /** 607 * Creates a new (empty) JSON array. 608 * 609 * @param allocator the allocator to use 610 * @return the new JSON array or @c NULL if allocation fails 611 * @see cxJsonObjPutArr() 612 * @see cxJsonArrAddValues() 613 */ 614 cx_attr_nodiscard 615 CX_EXPORT CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator); 616 617 /** 618 * Creates a new JSON number value. 619 * 620 * @param allocator the allocator to use 621 * @param num the numeric value 622 * @return the new JSON value or @c NULL if allocation fails 623 * @see cxJsonObjPutNumber() 624 * @see cxJsonArrAddNumbers() 625 */ 626 cx_attr_nodiscard 627 CX_EXPORT CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num); 628 629 /** 630 * Creates a new JSON number value based on an integer. 631 * 632 * @param allocator the allocator to use 633 * @param num the numeric value 634 * @return the new JSON value or @c NULL if allocation fails 635 * @see cxJsonObjPutInteger() 636 * @see cxJsonArrAddIntegers() 637 */ 638 cx_attr_nodiscard 639 CX_EXPORT CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num); 640 641 /** 642 * Creates a new JSON string. 643 * 644 * Internal function - use cxJsonCreateString() instead. 645 * 646 * @param allocator the allocator to use 647 * @param str the string data 648 * @return the new JSON value or @c NULL if allocation fails 649 * @see cxJsonObjPutString() 650 * @see cxJsonArrAddCxStrings() 651 */ 652 cx_attr_nodiscard 653 CX_EXPORT CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str); 654 655 /** 656 * Creates a new JSON string. 657 * 658 * @param allocator (@c CxAllocator*) the allocator to use 659 * @param str the string 660 * @return (@c CxJsonValue*) the new JSON value or @c NULL if allocation fails 661 * @see cxJsonObjPutString() 662 * @see cxJsonArrAddCxStrings() 663 */ 664 #define cxJsonCreateString(allocator, str) cx_json_create_string(allocator, cx_strcast(str)) 665 666 /** 667 * Creates a new JSON literal. 668 * 669 * @param allocator the allocator to use 670 * @param lit the type of literal 671 * @return the new JSON value or @c NULL if allocation fails 672 * @see cxJsonObjPutLiteral() 673 * @see cxJsonArrAddLiterals() 674 */ 675 cx_attr_nodiscard 676 CX_EXPORT CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit); 677 678 /** 679 * Adds number values to a JSON array. 680 * 681 * @param arr the JSON array 682 * @param num the array of values 683 * @param count the number of elements 684 * @retval zero success 685 * @retval non-zero allocation failure 686 */ 687 cx_attr_nonnull cx_attr_access_r(2, 3) 688 CX_EXPORT int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count); 689 690 /** 691 * Adds number values, of which all are integers, to a JSON array. 692 * 693 * @param arr the JSON array 694 * @param num the array of values 695 * @param count the number of elements 696 * @retval zero success 697 * @retval non-zero allocation failure 698 */ 699 cx_attr_nonnull cx_attr_access_r(2, 3) 700 CX_EXPORT int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count); 701 702 /** 703 * Adds strings to a JSON array. 704 * 705 * The strings will be copied with the allocator of the array. 706 * 707 * @param arr the JSON array 708 * @param str the array of strings 709 * @param count the number of elements 710 * @retval zero success 711 * @retval non-zero allocation failure 712 * @see cxJsonArrAddCxStrings() 713 */ 714 cx_attr_nonnull cx_attr_access_r(2, 3) 715 CX_EXPORT int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count); 716 717 /** 718 * Adds strings to a JSON array. 719 * 720 * The strings will be copied with the allocator of the array. 721 * 722 * @param arr the JSON array 723 * @param str the array of strings 724 * @param count the number of elements 725 * @retval zero success 726 * @retval non-zero allocation failure 727 * @see cxJsonArrAddStrings() 728 */ 729 cx_attr_nonnull cx_attr_access_r(2, 3) 730 CX_EXPORT int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count); 731 732 /** 733 * Adds literals to a JSON array. 734 * 735 * @param arr the JSON array 736 * @param lit the array of literal types 737 * @param count the number of elements 738 * @retval zero success 739 * @retval non-zero allocation failure 740 */ 741 cx_attr_nonnull cx_attr_access_r(2, 3) 742 CX_EXPORT int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count); 743 744 /** 745 * Add arbitrary values to a JSON array. 746 * 747 * @attention In contrast to all other add functions, this function adds the values 748 * directly to the array instead of copying them. 749 * 750 * @param arr the JSON array 751 * @param val the values 752 * @param count the number of elements 753 * @retval zero success 754 * @retval non-zero allocation failure 755 */ 756 cx_attr_nonnull cx_attr_access_r(2, 3) 757 CX_EXPORT int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count); 758 759 /** 760 * Adds or replaces a value within a JSON object. 761 * 762 * Internal function - use cxJsonObjPut(). 763 * 764 * @param obj the JSON object 765 * @param name the name of the value 766 * @param child the value 767 * @retval zero success 768 * @retval non-zero allocation failure 769 */ 770 cx_attr_nonnull 771 CX_EXPORT int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child); 772 773 /** 774 * Adds or replaces a value within a JSON object. 775 * 776 * The value will be directly added and not copied. 777 * 778 * @note If a value with the specified @p name already exists, 779 * it will be (recursively) freed with its own allocator. 780 * 781 * @param obj (@c CxJsonValue*) the JSON object 782 * @param name (any string) the name of the value 783 * @param child (@c CxJsonValue*) the value 784 * @retval zero success 785 * @retval non-zero allocation failure 786 */ 787 #define cxJsonObjPut(obj, name, child) cx_json_obj_put(obj, cx_strcast(name), child) 788 789 /** 790 * Creates a new JSON object and adds it to an existing object. 791 * 792 * Internal function - use cxJsonObjPutObj(). 793 * 794 * @param obj the target JSON object 795 * @param name the name of the new value 796 * @return the new value or @c NULL if allocation fails 797 * @see cxJsonObjPut() 798 * @see cxJsonCreateObj() 799 */ 800 cx_attr_nonnull 801 CX_EXPORT CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name); 802 803 /** 804 * Creates a new JSON object and adds it to an existing object. 805 * 806 * @param obj (@c CxJsonValue*) the target JSON object 807 * @param name (any string) the name of the new value 808 * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails 809 * @see cxJsonObjPut() 810 * @see cxJsonCreateObj() 811 */ 812 #define cxJsonObjPutObj(obj, name) cx_json_obj_put_obj(obj, cx_strcast(name)) 813 814 /** 815 * Creates a new JSON array and adds it to an object. 816 * 817 * Internal function - use cxJsonObjPutArr(). 818 * 819 * @param obj the target JSON object 820 * @param name the name of the new value 821 * @return the new value or @c NULL if allocation fails 822 * @see cxJsonObjPut() 823 * @see cxJsonCreateArr() 824 */ 825 cx_attr_nonnull 826 CX_EXPORT CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name); 827 828 /** 829 * Creates a new JSON array and adds it to an object. 830 * 831 * @param obj (@c CxJsonValue*) the target JSON object 832 * @param name (any string) the name of the new value 833 * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails 834 * @see cxJsonObjPut() 835 * @see cxJsonCreateArr() 836 */ 837 #define cxJsonObjPutArr(obj, name) cx_json_obj_put_arr(obj, cx_strcast(name)) 838 839 /** 840 * Creates a new JSON number and adds it to an object. 841 * 842 * Internal function - use cxJsonObjPutNumber(). 843 * 844 * @param obj the target JSON object 845 * @param name the name of the new value 846 * @param num the numeric value 847 * @return the new value or @c NULL if allocation fails 848 * @see cxJsonObjPut() 849 * @see cxJsonCreateNumber() 850 */ 851 cx_attr_nonnull 852 CX_EXPORT CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, double num); 853 854 /** 855 * Creates a new JSON number and adds it to an object. 856 * 857 * @param obj (@c CxJsonValue*) the target JSON object 858 * @param name (any string) the name of the new value 859 * @param num (@c double) the numeric value 860 * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails 861 * @see cxJsonObjPut() 862 * @see cxJsonCreateNumber() 863 */ 864 #define cxJsonObjPutNumber(obj, name, num) cx_json_obj_put_number(obj, cx_strcast(name), num) 865 866 /** 867 * Creates a new JSON number, based on an integer, and adds it to an object. 868 * 869 * Internal function - use cxJsonObjPutInteger(). 870 * 871 * @param obj the target JSON object 872 * @param name the name of the new value 873 * @param num the numeric value 874 * @return the new value or @c NULL if allocation fails 875 * @see cxJsonObjPut() 876 * @see cxJsonCreateInteger() 877 */ 878 cx_attr_nonnull 879 CX_EXPORT CxJsonValue* cx_json_obj_put_integer(CxJsonValue* obj, cxstring name, int64_t num); 880 881 /** 882 * Creates a new JSON number, based on an integer, and adds it to an object. 883 * 884 * @param obj (@c CxJsonValue*) the target JSON object 885 * @param name (any string) the name of the new value 886 * @param num (@c int64_t) the numeric value 887 * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails 888 * @see cxJsonObjPut() 889 * @see cxJsonCreateInteger() 890 */ 891 #define cxJsonObjPutInteger(obj, name, num) cx_json_obj_put_integer(obj, cx_strcast(name), num) 892 893 /** 894 * Creates a new JSON string and adds it to an object. 895 * 896 * Internal function - use cxJsonObjPutString() 897 * 898 * @param obj the target JSON object 899 * @param name the name of the new value 900 * @param str the string data 901 * @return the new value or @c NULL if allocation fails 902 * @see cxJsonObjPut() 903 * @see cxJsonCreateString() 904 */ 905 cx_attr_nonnull 906 CX_EXPORT CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, cxstring str); 907 908 /** 909 * Creates a new JSON string and adds it to an object. 910 * 911 * The string data is copied. 912 * 913 * @param obj (@c CxJsonValue*) the target JSON object 914 * @param name (any string) the name of the new value 915 * @param str (any string) the string data 916 * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails 917 * @see cxJsonObjPut() 918 * @see cxJsonCreateString() 919 */ 920 #define cxJsonObjPutString(obj, name, str) cx_json_obj_put_string(obj, cx_strcast(name), cx_strcast(str)) 921 922 /** 923 * Creates a new JSON literal and adds it to an object. 924 * 925 * Internal function - use cxJsonObjPutLiteral(). 926 * 927 * @param obj the target JSON object 928 * @param name the name of the new value 929 * @param lit the type of literal 930 * @return the new value or @c NULL if allocation fails 931 * @see cxJsonObjPut() 932 * @see cxJsonCreateLiteral() 933 */ 934 cx_attr_nonnull 935 CX_EXPORT CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, CxJsonLiteral lit); 936 937 /** 938 * Creates a new JSON literal and adds it to an object. 939 * 940 * @param obj (@c CxJsonValue*) the target JSON object 941 * @param name (any string) the name of the new value 942 * @param lit (@c CxJsonLiteral) the type of literal 943 * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails 944 * @see cxJsonObjPut() 945 * @see cxJsonCreateLiteral() 946 */ 947 #define cxJsonObjPutLiteral(obj, name, lit) cx_json_obj_put_literal(obj, cx_strcast(name), lit) 948 949 /** 950 * Recursively deallocates the memory of a JSON value. 951 * 952 * @remark The type of each deallocated value will be changed 953 * to #CX_JSON_NOTHING, and values of such a type will be skipped 954 * by the deallocation. That means this function protects 955 * you from double-frees when you are accidentally freeing 956 * a nested value and then the parent value (or vice versa). 957 * 958 * @param value the value 959 */ 960 CX_EXPORT void cxJsonValueFree(CxJsonValue *value); 961 962 /** 963 * Tries to obtain the next JSON value. 964 * 965 * Before this function can be called, the input buffer needs 966 * to be filled with cxJsonFill(). 967 * 968 * When this function returns #CX_JSON_INCOMPLETE_DATA, you can 969 * add the missing data with another invocation of cxJsonFill() 970 * and then repeat the call to cxJsonNext(). 971 * 972 * @param json the JSON interface 973 * @param value a pointer where the next value shall be stored 974 * @retval CX_JSON_NO_ERROR successfully retrieve the @p value 975 * @retval CX_JSON_NO_DATA there is no (more) data in the buffer to read from 976 * @retval CX_JSON_INCOMPLETE_DATA an incomplete value was read 977 * and more data needs to be filled 978 * @retval CX_JSON_NULL_DATA the buffer was never initialized 979 * @retval CX_JSON_BUFFER_ALLOC_FAILED allocating internal buffer space failed 980 * @retval CX_JSON_VALUE_ALLOC_FAILED allocating memory for a CxJsonValue failed 981 * @retval CX_JSON_FORMAT_ERROR_NUMBER the JSON text contains an illegally formatted number 982 * @retval CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN JSON syntax error 983 */ 984 cx_attr_nonnull cx_attr_access_w(2) 985 CX_EXPORT CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value); 986 987 /** 988 * Checks if the specified value is a JSON object. 989 * 990 * @param value a pointer to the value 991 * @retval true the value is a JSON object 992 * @retval false otherwise 993 */ 994 cx_attr_nonnull 995 CX_INLINE bool cxJsonIsObject(const CxJsonValue *value) { 996 return value->type == CX_JSON_OBJECT; 997 } 998 999 /** 1000 * Checks if the specified value is a JSON array. 1001 * 1002 * @param value a pointer to the value 1003 * @retval true the value is a JSON array 1004 * @retval false otherwise 1005 */ 1006 cx_attr_nonnull 1007 CX_INLINE bool cxJsonIsArray(const CxJsonValue *value) { 1008 return value->type == CX_JSON_ARRAY; 1009 } 1010 1011 /** 1012 * Checks if the specified value is a string. 1013 * 1014 * @param value a pointer to the value 1015 * @retval true the value is a string 1016 * @retval false otherwise 1017 */ 1018 cx_attr_nonnull 1019 CX_INLINE bool cxJsonIsString(const CxJsonValue *value) { 1020 return value->type == CX_JSON_STRING; 1021 } 1022 1023 /** 1024 * Checks if the specified value is a JSON number. 1025 * 1026 * This function will return true for both floating-point and 1027 * integer numbers. 1028 * 1029 * @param value a pointer to the value 1030 * @retval true the value is a JSON number 1031 * @retval false otherwise 1032 * @see cxJsonIsInteger() 1033 */ 1034 cx_attr_nonnull 1035 CX_INLINE bool cxJsonIsNumber(const CxJsonValue *value) { 1036 return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER; 1037 } 1038 1039 /** 1040 * Checks if the specified value is an integer number. 1041 * 1042 * @param value a pointer to the value 1043 * @retval true the value is an integer number 1044 * @retval false otherwise 1045 * @see cxJsonIsNumber() 1046 */ 1047 cx_attr_nonnull 1048 CX_INLINE bool cxJsonIsInteger(const CxJsonValue *value) { 1049 return value->type == CX_JSON_INTEGER; 1050 } 1051 1052 /** 1053 * Checks if the specified value is a JSON literal. 1054 * 1055 * JSON literals are @c true, @c false, and @c null. 1056 * 1057 * @param value a pointer to the value 1058 * @retval true the value is a JSON literal 1059 * @retval false otherwise 1060 * @see cxJsonIsTrue() 1061 * @see cxJsonIsFalse() 1062 * @see cxJsonIsNull() 1063 */ 1064 cx_attr_nonnull 1065 CX_INLINE bool cxJsonIsLiteral(const CxJsonValue *value) { 1066 return value->type == CX_JSON_LITERAL; 1067 } 1068 1069 /** 1070 * Checks if the specified value is a Boolean literal. 1071 * 1072 * @param value a pointer to the value 1073 * @retval true the value is either @c true or @c false 1074 * @retval false otherwise 1075 * @see cxJsonIsTrue() 1076 * @see cxJsonIsFalse() 1077 */ 1078 cx_attr_nonnull 1079 CX_INLINE bool cxJsonIsBool(const CxJsonValue *value) { 1080 return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL; 1081 } 1082 1083 /** 1084 * Checks if the specified value is @c true. 1085 * 1086 * @remark Be advised that this is different from 1087 * testing @c !cxJsonIsFalse(v). 1088 * 1089 * @param value a pointer to the value 1090 * @retval true the value is @c true 1091 * @retval false otherwise 1092 * @see cxJsonIsBool() 1093 * @see cxJsonIsFalse() 1094 */ 1095 cx_attr_nonnull 1096 CX_INLINE bool cxJsonIsTrue(const CxJsonValue *value) { 1097 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE; 1098 } 1099 1100 /** 1101 * Checks if the specified value is @c false. 1102 * 1103 * @remark Be advised that this is different from 1104 * testing @c !cxJsonIsTrue(v). 1105 * 1106 * @param value a pointer to the value 1107 * @retval true the value is @c false 1108 * @retval false otherwise 1109 * @see cxJsonIsBool() 1110 * @see cxJsonIsTrue() 1111 */ 1112 cx_attr_nonnull 1113 CX_INLINE bool cxJsonIsFalse(const CxJsonValue *value) { 1114 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE; 1115 } 1116 1117 /** 1118 * Checks if the specified value is @c null. 1119 * 1120 * @param value a pointer to the value 1121 * @retval true the value is @c null 1122 * @retval false otherwise 1123 * @see cxJsonIsLiteral() 1124 */ 1125 cx_attr_nonnull 1126 CX_INLINE bool cxJsonIsNull(const CxJsonValue *value) { 1127 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL; 1128 } 1129 1130 /** 1131 * Obtains a C string from the given JSON value. 1132 * 1133 * If the @p value is not a string, the behavior is undefined. 1134 * 1135 * @param value the JSON value 1136 * @return the value represented as C string 1137 * @see cxJsonIsString() 1138 */ 1139 cx_attr_nonnull cx_attr_returns_nonnull 1140 CX_EXPORT char *cxJsonAsString(const CxJsonValue *value); 1141 1142 /** 1143 * Obtains a UCX 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 UCX string 1149 * @see cxJsonIsString() 1150 */ 1151 cx_attr_nonnull 1152 CX_EXPORT cxstring cxJsonAsCxString(const CxJsonValue *value); 1153 1154 /** 1155 * Obtains a mutable 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 mutable UCX string 1161 * @see cxJsonIsString() 1162 */ 1163 cx_attr_nonnull 1164 CX_EXPORT cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value); 1165 1166 /** 1167 * Obtains a double-precision floating-point value from the given JSON value. 1168 * 1169 * If the @p value is not a JSON number, the behavior is undefined. 1170 * 1171 * @param value the JSON value 1172 * @return the value represented as double 1173 * @see cxJsonIsNumber() 1174 */ 1175 cx_attr_nonnull 1176 CX_EXPORT double cxJsonAsDouble(const CxJsonValue *value); 1177 1178 /** 1179 * Obtains a 64-bit signed integer from the given JSON value. 1180 * 1181 * If the @p value is not a JSON number, the behavior is undefined. 1182 * If it is a JSON number, but not an integer, the value will be 1183 * converted to an integer, possibly losing precision. 1184 * 1185 * @param value the JSON value 1186 * @return the value represented as double 1187 * @see cxJsonIsNumber() 1188 * @see cxJsonIsInteger() 1189 */ 1190 cx_attr_nonnull 1191 CX_EXPORT int64_t cxJsonAsInteger(const CxJsonValue *value); 1192 1193 /** 1194 * Obtains a Boolean value from the given JSON value. 1195 * 1196 * If the @p value is not a JSON literal, the behavior is undefined. 1197 * The @c null literal is interpreted as @c false. 1198 * 1199 * @param value the JSON value 1200 * @return the value represented as double 1201 * @see cxJsonIsLiteral() 1202 */ 1203 cx_attr_nonnull 1204 CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) { 1205 return value->value.literal == CX_JSON_TRUE; 1206 } 1207 1208 /** 1209 * Returns the size of a JSON array. 1210 * 1211 * If the @p value is not a JSON array, the behavior is undefined. 1212 * 1213 * @param value the JSON value 1214 * @return the size of the array 1215 * @see cxJsonIsArray() 1216 */ 1217 cx_attr_nonnull 1218 CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) { 1219 return value->value.array.array_size; 1220 } 1221 1222 /** 1223 * Returns an element from a JSON array. 1224 * 1225 * If the @p value is not a JSON array, the behavior is undefined. 1226 * 1227 * This function guarantees to return a value. If the index is 1228 * out of bounds, the returned value will be of type 1229 * #CX_JSON_NOTHING, but never @c NULL. 1230 * 1231 * @param value the JSON value 1232 * @param index the index in the array 1233 * @return the value at the specified index 1234 * @see cxJsonIsArray() 1235 */ 1236 cx_attr_nonnull cx_attr_returns_nonnull 1237 CX_EXPORT CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index); 1238 1239 /** 1240 * Removes an element from a JSON array. 1241 * 1242 * If the @p value is not a JSON array, the behavior is undefined. 1243 * 1244 * This function, in contrast to cxJsonArrayGet(), returns @c NULL 1245 * when the index is out of bounds. 1246 * 1247 * @param value the JSON value 1248 * @param index the index in the array 1249 * @return the removed value from the specified index or @c NULL when the index was out of bounds 1250 * @see cxJsonIsArray() 1251 */ 1252 cx_attr_nonnull 1253 CX_EXPORT CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index); 1254 1255 /** 1256 * Returns an iterator over the JSON array elements. 1257 * 1258 * The iterator yields values of type @c CxJsonValue* . 1259 * 1260 * If the @p value is not a JSON array, the behavior is undefined. 1261 * 1262 * @param value the JSON value 1263 * @return an iterator over the array elements 1264 * @see cxJsonIsArray() 1265 */ 1266 cx_attr_nonnull cx_attr_nodiscard 1267 CX_EXPORT CxIterator cxJsonArrIter(const CxJsonValue *value); 1268 1269 /** 1270 * Returns the size of a JSON object. 1271 * 1272 * If the @p value is not a JSON object, the behavior is undefined. 1273 * 1274 * @param value the JSON value 1275 * @return the size of the object, i.e., the number of key/value pairs 1276 * @see cxJsonIsObject() 1277 */ 1278 cx_attr_nonnull 1279 CX_INLINE size_t cxJsonObjSize(const CxJsonValue *value) { 1280 return value->value.object.values_size; 1281 } 1282 1283 /** 1284 * Returns an iterator over the JSON object members. 1285 * 1286 * The iterator yields values of type @c CxJsonObjValue* which 1287 * contain the name and value of the member. 1288 * 1289 * If the @p value is not a JSON object, the behavior is undefined. 1290 * 1291 * @param value the JSON value 1292 * @return an iterator over the object members 1293 * @see cxJsonIsObject() 1294 */ 1295 cx_attr_nonnull cx_attr_nodiscard 1296 CX_EXPORT CxIterator cxJsonObjIter(const CxJsonValue *value); 1297 1298 /** 1299 * Internal function, do not use. 1300 * @param value the JSON object 1301 * @param name the key to look up 1302 * @return the value corresponding to the key 1303 */ 1304 cx_attr_nonnull cx_attr_returns_nonnull 1305 CX_EXPORT CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name); 1306 1307 /** 1308 * Returns a value corresponding to a key in a JSON object. 1309 * 1310 * If the @p value is not a JSON object, the behavior is undefined. 1311 * 1312 * This function guarantees to return a JSON value. If the 1313 * object does not contain @p name, the returned JSON value 1314 * will be of type #CX_JSON_NOTHING, but never @c NULL. 1315 * 1316 * @param value the JSON object 1317 * @param name the key to look up 1318 * @return the value corresponding to the key 1319 * @see cxJsonIsObject() 1320 */ 1321 #define cxJsonObjGet(value, name) cx_json_obj_get(value, cx_strcast(name)) 1322 1323 /** 1324 * Internal function, do not use. 1325 * @param value the JSON object 1326 * @param name the key to look up 1327 * @return the value corresponding to the key or @c NULL when the key is not part of the object 1328 */ 1329 cx_attr_nonnull 1330 CX_EXPORT CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name); 1331 1332 /** 1333 * Removes and returns a value corresponding to a key in a JSON object. 1334 * 1335 * If the @p value is not a JSON object, the behavior is undefined. 1336 * 1337 * This function, in contrast to cxJsonObjGet() returns @c NULL when the 1338 * object does not contain @p name. 1339 * 1340 * @param value the JSON object 1341 * @param name the key to look up 1342 * @return the value corresponding to the key or @c NULL when the key is not part of the object 1343 * @see cxJsonIsObject() 1344 */ 1345 #define cxJsonObjRemove(value, name) cx_json_obj_remove(value, cx_strcast(name)) 1346 1347 #ifdef __cplusplus 1348 } 1349 #endif 1350 1351 #endif /* UCX_JSON_H */ 1352 1353