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 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 * @param allocator the allocator to use 645 * @param str the string data 646 * @return the new JSON value or @c NULL if allocation fails 647 * @see cxJsonCreateString() 648 * @see cxJsonObjPutString() 649 * @see cxJsonArrAddStrings() 650 */ 651 cx_attr_nodiscard cx_attr_nonnull_arg(2) cx_attr_cstr_arg(2) 652 CX_EXPORT CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str); 653 654 /** 655 * Creates a new JSON string. 656 * 657 * @param allocator the allocator to use 658 * @param str the string data 659 * @return the new JSON value or @c NULL if allocation fails 660 * @see cxJsonCreateCxString() 661 * @see cxJsonObjPutCxString() 662 * @see cxJsonArrAddCxStrings() 663 */ 664 cx_attr_nodiscard 665 CX_EXPORT CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str); 666 667 /** 668 * Creates a new JSON literal. 669 * 670 * @param allocator the allocator to use 671 * @param lit the type of literal 672 * @return the new JSON value or @c NULL if allocation fails 673 * @see cxJsonObjPutLiteral() 674 * @see cxJsonArrAddLiterals() 675 */ 676 cx_attr_nodiscard 677 CX_EXPORT CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit); 678 679 /** 680 * Adds number values to a JSON array. 681 * 682 * @param arr the JSON array 683 * @param num the array of values 684 * @param count the number of elements 685 * @retval zero success 686 * @retval non-zero allocation failure 687 */ 688 cx_attr_nonnull cx_attr_access_r(2, 3) 689 CX_EXPORT int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count); 690 691 /** 692 * Adds number values, of which all are integers, to a JSON array. 693 * 694 * @param arr the JSON array 695 * @param num the array of values 696 * @param count the number of elements 697 * @retval zero success 698 * @retval non-zero allocation failure 699 */ 700 cx_attr_nonnull cx_attr_access_r(2, 3) 701 CX_EXPORT int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count); 702 703 /** 704 * Adds strings to a JSON array. 705 * 706 * The strings will be copied with the allocator of the array. 707 * 708 * @param arr the JSON array 709 * @param str the array of strings 710 * @param count the number of elements 711 * @retval zero success 712 * @retval non-zero allocation failure 713 * @see cxJsonArrAddCxStrings() 714 */ 715 cx_attr_nonnull cx_attr_access_r(2, 3) 716 CX_EXPORT int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count); 717 718 /** 719 * Adds strings to a JSON array. 720 * 721 * The strings will be copied with the allocator of the array. 722 * 723 * @param arr the JSON array 724 * @param str the array of strings 725 * @param count the number of elements 726 * @retval zero success 727 * @retval non-zero allocation failure 728 * @see cxJsonArrAddStrings() 729 */ 730 cx_attr_nonnull cx_attr_access_r(2, 3) 731 CX_EXPORT int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count); 732 733 /** 734 * Adds literals to a JSON array. 735 * 736 * @param arr the JSON array 737 * @param lit the array of literal types 738 * @param count the number of elements 739 * @retval zero success 740 * @retval non-zero allocation failure 741 */ 742 cx_attr_nonnull cx_attr_access_r(2, 3) 743 CX_EXPORT int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count); 744 745 /** 746 * Add arbitrary values to a JSON array. 747 * 748 * @attention In contrast to all other add functions, this function adds the values 749 * directly to the array instead of copying them. 750 * 751 * @param arr the JSON array 752 * @param val the values 753 * @param count the number of elements 754 * @retval zero success 755 * @retval non-zero allocation failure 756 */ 757 cx_attr_nonnull cx_attr_access_r(2, 3) 758 CX_EXPORT int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count); 759 760 /** 761 * Adds or replaces a value within a JSON object. 762 * 763 * The value will be directly added and not copied. 764 * 765 * @note If a value with the specified @p name already exists, 766 * it will be (recursively) freed with its own allocator. 767 * 768 * @param obj the JSON object 769 * @param name the name of the value 770 * @param child the value 771 * @retval zero success 772 * @retval non-zero allocation failure 773 */ 774 cx_attr_nonnull 775 CX_EXPORT int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child); 776 777 /** 778 * Creates a new JSON object and adds it to an existing object. 779 * 780 * @param obj the target JSON object 781 * @param name the name of the new value 782 * @return the new value or @c NULL if allocation fails 783 * @see cxJsonObjPut() 784 * @see cxJsonCreateObj() 785 */ 786 cx_attr_nonnull 787 CX_EXPORT CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name); 788 789 /** 790 * Creates a new JSON array and adds it to an object. 791 * 792 * @param obj the target JSON object 793 * @param name the name of the new value 794 * @return the new value or @c NULL if allocation fails 795 * @see cxJsonObjPut() 796 * @see cxJsonCreateArr() 797 */ 798 cx_attr_nonnull 799 CX_EXPORT CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name); 800 801 /** 802 * Creates a new JSON number and adds it to an object. 803 * 804 * @param obj the target JSON object 805 * @param name the name of the new value 806 * @param num the numeric value 807 * @return the new value or @c NULL if allocation fails 808 * @see cxJsonObjPut() 809 * @see cxJsonCreateNumber() 810 */ 811 cx_attr_nonnull 812 CX_EXPORT CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num); 813 814 /** 815 * Creates a new JSON number, based on an integer, and adds it to an object. 816 * 817 * @param obj the target JSON object 818 * @param name the name of the new value 819 * @param num the numeric value 820 * @return the new value or @c NULL if allocation fails 821 * @see cxJsonObjPut() 822 * @see cxJsonCreateInteger() 823 */ 824 cx_attr_nonnull 825 CX_EXPORT CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num); 826 827 /** 828 * Creates a new JSON string and adds it to an object. 829 * 830 * The string data is copied. 831 * 832 * @param obj the target JSON object 833 * @param name the name of the new value 834 * @param str the string data 835 * @return the new value or @c NULL if allocation fails 836 * @see cxJsonObjPut() 837 * @see cxJsonCreateString() 838 */ 839 cx_attr_nonnull cx_attr_cstr_arg(3) 840 CX_EXPORT CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str); 841 842 /** 843 * Creates a new JSON string and adds it to an object. 844 * 845 * The string data is copied. 846 * 847 * @param obj the target JSON object 848 * @param name the name of the new value 849 * @param str the string data 850 * @return the new value or @c NULL if allocation fails 851 * @see cxJsonObjPut() 852 * @see cxJsonCreateCxString() 853 */ 854 cx_attr_nonnull 855 CX_EXPORT CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str); 856 857 /** 858 * Creates a new JSON literal and adds it to an object. 859 * 860 * @param obj the target JSON object 861 * @param name the name of the new value 862 * @param lit the type of literal 863 * @return the new value or @c NULL if allocation fails 864 * @see cxJsonObjPut() 865 * @see cxJsonCreateLiteral() 866 */ 867 cx_attr_nonnull 868 CX_EXPORT CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit); 869 870 /** 871 * Recursively deallocates the memory of a JSON value. 872 * 873 * @remark The type of each deallocated value will be changed 874 * to #CX_JSON_NOTHING, and values of such a type will be skipped 875 * by the deallocation. That means this function protects 876 * you from double-frees when you are accidentally freeing 877 * a nested value and then the parent value (or vice versa). 878 * 879 * @param value the value 880 */ 881 CX_EXPORT void cxJsonValueFree(CxJsonValue *value); 882 883 /** 884 * Tries to obtain the next JSON value. 885 * 886 * Before this function can be called, the input buffer needs 887 * to be filled with cxJsonFill(). 888 * 889 * When this function returns #CX_JSON_INCOMPLETE_DATA, you can 890 * add the missing data with another invocation of cxJsonFill() 891 * and then repeat the call to cxJsonNext(). 892 * 893 * @param json the JSON interface 894 * @param value a pointer where the next value shall be stored 895 * @retval CX_JSON_NO_ERROR successfully retrieve the @p value 896 * @retval CX_JSON_NO_DATA there is no (more) data in the buffer to read from 897 * @retval CX_JSON_INCOMPLETE_DATA an incomplete value was read 898 * and more data needs to be filled 899 * @retval CX_JSON_NULL_DATA the buffer was never initialized 900 * @retval CX_JSON_BUFFER_ALLOC_FAILED allocating internal buffer space failed 901 * @retval CX_JSON_VALUE_ALLOC_FAILED allocating memory for a CxJsonValue failed 902 * @retval CX_JSON_FORMAT_ERROR_NUMBER the JSON text contains an illegally formatted number 903 * @retval CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN JSON syntax error 904 */ 905 cx_attr_nonnull cx_attr_access_w(2) 906 CX_EXPORT CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value); 907 908 /** 909 * Checks if the specified value is a JSON object. 910 * 911 * @param value a pointer to the value 912 * @retval true the value is a JSON object 913 * @retval false otherwise 914 */ 915 cx_attr_nonnull 916 CX_INLINE bool cxJsonIsObject(const CxJsonValue *value) { 917 return value->type == CX_JSON_OBJECT; 918 } 919 920 /** 921 * Checks if the specified value is a JSON array. 922 * 923 * @param value a pointer to the value 924 * @retval true the value is a JSON array 925 * @retval false otherwise 926 */ 927 cx_attr_nonnull 928 CX_INLINE bool cxJsonIsArray(const CxJsonValue *value) { 929 return value->type == CX_JSON_ARRAY; 930 } 931 932 /** 933 * Checks if the specified value is a string. 934 * 935 * @param value a pointer to the value 936 * @retval true the value is a string 937 * @retval false otherwise 938 */ 939 cx_attr_nonnull 940 CX_INLINE bool cxJsonIsString(const CxJsonValue *value) { 941 return value->type == CX_JSON_STRING; 942 } 943 944 /** 945 * Checks if the specified value is a JSON number. 946 * 947 * This function will return true for both floating-point and 948 * integer numbers. 949 * 950 * @param value a pointer to the value 951 * @retval true the value is a JSON number 952 * @retval false otherwise 953 * @see cxJsonIsInteger() 954 */ 955 cx_attr_nonnull 956 CX_INLINE bool cxJsonIsNumber(const CxJsonValue *value) { 957 return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER; 958 } 959 960 /** 961 * Checks if the specified value is an integer number. 962 * 963 * @param value a pointer to the value 964 * @retval true the value is an integer number 965 * @retval false otherwise 966 * @see cxJsonIsNumber() 967 */ 968 cx_attr_nonnull 969 CX_INLINE bool cxJsonIsInteger(const CxJsonValue *value) { 970 return value->type == CX_JSON_INTEGER; 971 } 972 973 /** 974 * Checks if the specified value is a JSON literal. 975 * 976 * JSON literals are @c true, @c false, and @c null. 977 * 978 * @param value a pointer to the value 979 * @retval true the value is a JSON literal 980 * @retval false otherwise 981 * @see cxJsonIsTrue() 982 * @see cxJsonIsFalse() 983 * @see cxJsonIsNull() 984 */ 985 cx_attr_nonnull 986 CX_INLINE bool cxJsonIsLiteral(const CxJsonValue *value) { 987 return value->type == CX_JSON_LITERAL; 988 } 989 990 /** 991 * Checks if the specified value is a Boolean literal. 992 * 993 * @param value a pointer to the value 994 * @retval true the value is either @c true or @c false 995 * @retval false otherwise 996 * @see cxJsonIsTrue() 997 * @see cxJsonIsFalse() 998 */ 999 cx_attr_nonnull 1000 CX_INLINE bool cxJsonIsBool(const CxJsonValue *value) { 1001 return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL; 1002 } 1003 1004 /** 1005 * Checks if the specified value is @c true. 1006 * 1007 * @remark Be advised that this is different from 1008 * testing @c !cxJsonIsFalse(v). 1009 * 1010 * @param value a pointer to the value 1011 * @retval true the value is @c true 1012 * @retval false otherwise 1013 * @see cxJsonIsBool() 1014 * @see cxJsonIsFalse() 1015 */ 1016 cx_attr_nonnull 1017 CX_INLINE bool cxJsonIsTrue(const CxJsonValue *value) { 1018 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE; 1019 } 1020 1021 /** 1022 * Checks if the specified value is @c false. 1023 * 1024 * @remark Be advised that this is different from 1025 * testing @c !cxJsonIsTrue(v). 1026 * 1027 * @param value a pointer to the value 1028 * @retval true the value is @c false 1029 * @retval false otherwise 1030 * @see cxJsonIsBool() 1031 * @see cxJsonIsTrue() 1032 */ 1033 cx_attr_nonnull 1034 CX_INLINE bool cxJsonIsFalse(const CxJsonValue *value) { 1035 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE; 1036 } 1037 1038 /** 1039 * Checks if the specified value is @c null. 1040 * 1041 * @param value a pointer to the value 1042 * @retval true the value is @c null 1043 * @retval false otherwise 1044 * @see cxJsonIsLiteral() 1045 */ 1046 cx_attr_nonnull 1047 CX_INLINE bool cxJsonIsNull(const CxJsonValue *value) { 1048 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL; 1049 } 1050 1051 /** 1052 * Obtains a C string from the given JSON value. 1053 * 1054 * If the @p value is not a string, the behavior is undefined. 1055 * 1056 * @param value the JSON value 1057 * @return the value represented as C string 1058 * @see cxJsonIsString() 1059 */ 1060 cx_attr_nonnull cx_attr_returns_nonnull 1061 CX_EXPORT char *cxJsonAsString(const CxJsonValue *value); 1062 1063 /** 1064 * Obtains a UCX string from the given JSON value. 1065 * 1066 * If the @p value is not a string, the behavior is undefined. 1067 * 1068 * @param value the JSON value 1069 * @return the value represented as UCX string 1070 * @see cxJsonIsString() 1071 */ 1072 cx_attr_nonnull 1073 CX_EXPORT cxstring cxJsonAsCxString(const CxJsonValue *value); 1074 1075 /** 1076 * Obtains a mutable UCX string from the given JSON value. 1077 * 1078 * If the @p value is not a string, the behavior is undefined. 1079 * 1080 * @param value the JSON value 1081 * @return the value represented as mutable UCX string 1082 * @see cxJsonIsString() 1083 */ 1084 cx_attr_nonnull 1085 CX_EXPORT cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value); 1086 1087 /** 1088 * Obtains a double-precision floating-point value from the given JSON value. 1089 * 1090 * If the @p value is not a JSON number, the behavior is undefined. 1091 * 1092 * @param value the JSON value 1093 * @return the value represented as double 1094 * @see cxJsonIsNumber() 1095 */ 1096 cx_attr_nonnull 1097 CX_EXPORT double cxJsonAsDouble(const CxJsonValue *value); 1098 1099 /** 1100 * Obtains a 64-bit signed integer from the given JSON value. 1101 * 1102 * If the @p value is not a JSON number, the behavior is undefined. 1103 * If it is a JSON number, but not an integer, the value will be 1104 * converted to an integer, possibly losing precision. 1105 * 1106 * @param value the JSON value 1107 * @return the value represented as double 1108 * @see cxJsonIsNumber() 1109 * @see cxJsonIsInteger() 1110 */ 1111 cx_attr_nonnull 1112 CX_EXPORT int64_t cxJsonAsInteger(const CxJsonValue *value); 1113 1114 /** 1115 * Obtains a Boolean value from the given JSON value. 1116 * 1117 * If the @p value is not a JSON literal, the behavior is undefined. 1118 * The @c null literal is interpreted as @c false. 1119 * 1120 * @param value the JSON value 1121 * @return the value represented as double 1122 * @see cxJsonIsLiteral() 1123 */ 1124 cx_attr_nonnull 1125 CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) { 1126 return value->value.literal == CX_JSON_TRUE; 1127 } 1128 1129 /** 1130 * Returns the size of a JSON array. 1131 * 1132 * If the @p value is not a JSON array, the behavior is undefined. 1133 * 1134 * @param value the JSON value 1135 * @return the size of the array 1136 * @see cxJsonIsArray() 1137 */ 1138 cx_attr_nonnull 1139 CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) { 1140 return value->value.array.array_size; 1141 } 1142 1143 /** 1144 * Returns an element from a JSON array. 1145 * 1146 * If the @p value is not a JSON array, the behavior is undefined. 1147 * 1148 * This function guarantees to return a value. If the index is 1149 * out of bounds, the returned value will be of type 1150 * #CX_JSON_NOTHING, but never @c NULL. 1151 * 1152 * @param value the JSON value 1153 * @param index the index in the array 1154 * @return the value at the specified index 1155 * @see cxJsonIsArray() 1156 */ 1157 cx_attr_nonnull cx_attr_returns_nonnull 1158 CX_EXPORT CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index); 1159 1160 /** 1161 * Removes an element from a JSON array. 1162 * 1163 * If the @p value is not a JSON array, the behavior is undefined. 1164 * 1165 * This function, in contrast to cxJsonArrayGet(), returns @c NULL 1166 * when the index is out of bounds. 1167 * 1168 * @param value the JSON value 1169 * @param index the index in the array 1170 * @return the removed value from the specified index or @c NULL when the index was out of bounds 1171 * @see cxJsonIsArray() 1172 */ 1173 cx_attr_nonnull 1174 CX_EXPORT CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index); 1175 1176 /** 1177 * Returns an iterator over the JSON array elements. 1178 * 1179 * The iterator yields values of type @c CxJsonValue* . 1180 * 1181 * If the @p value is not a JSON array, the behavior is undefined. 1182 * 1183 * @param value the JSON value 1184 * @return an iterator over the array elements 1185 * @see cxJsonIsArray() 1186 */ 1187 cx_attr_nonnull cx_attr_nodiscard 1188 CX_EXPORT CxIterator cxJsonArrIter(const CxJsonValue *value); 1189 1190 /** 1191 * Returns an iterator over the JSON object members. 1192 * 1193 * The iterator yields values of type @c CxJsonObjValue* which 1194 * contain the name and value of the member. 1195 * 1196 * If the @p value is not a JSON object, the behavior is undefined. 1197 * 1198 * @param value the JSON value 1199 * @return an iterator over the object members 1200 * @see cxJsonIsObject() 1201 */ 1202 cx_attr_nonnull cx_attr_nodiscard 1203 CX_EXPORT CxIterator cxJsonObjIter(const CxJsonValue *value); 1204 1205 /** 1206 * Internal function, do not use. 1207 * @param value the JSON object 1208 * @param name the key to look up 1209 * @return the value corresponding to the key 1210 */ 1211 cx_attr_nonnull cx_attr_returns_nonnull 1212 CX_EXPORT CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name); 1213 1214 /** 1215 * Returns a value corresponding to a key in a JSON object. 1216 * 1217 * If the @p value is not a JSON object, the behavior is undefined. 1218 * 1219 * This function guarantees to return a JSON value. If the 1220 * object does not contain @p name, the returned JSON value 1221 * will be of type #CX_JSON_NOTHING, but never @c NULL. 1222 * 1223 * @param value the JSON object 1224 * @param name the key to look up 1225 * @return the value corresponding to the key 1226 * @see cxJsonIsObject() 1227 */ 1228 #define cxJsonObjGet(value, name) cx_json_obj_get(value, cx_strcast(name)) 1229 1230 /** 1231 * Internal function, do not use. 1232 * @param value the JSON object 1233 * @param name the key to look up 1234 * @return the value corresponding to the key or @c NULL when the key is not part of the object 1235 */ 1236 cx_attr_nonnull 1237 CX_EXPORT CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name); 1238 1239 /** 1240 * Removes and returns a value corresponding to a key in a JSON object. 1241 * 1242 * If the @p value is not a JSON object, the behavior is undefined. 1243 * 1244 * This function, in contrast to cxJsonObjGet() returns @c NULL when the 1245 * object does not contain @p name. 1246 * 1247 * @param value the JSON object 1248 * @param name the key to look up 1249 * @return the value corresponding to the key or @c NULL when the key is not part of the object 1250 * @see cxJsonIsObject() 1251 */ 1252 #define cxJsonObjRemove(value, name) cx_json_obj_remove(value, cx_strcast(name)) 1253 1254 #ifdef __cplusplus 1255 } 1256 #endif 1257 1258 #endif /* UCX_JSON_H */ 1259 1260