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