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