1 #pragma once 2 #ifndef IWJSON_H 3 #define IWJSON_H 4 5 /************************************************************************************************** 6 * MIT License 7 * 8 * Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com> 9 * 10 * Permission is hereby granted, free of charge, to any person obtaining a copy 11 * of this software and associated documentation files (the "Software"), to deal 12 * in the Software without restriction, including without limitation the rights 13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 * copies of the Software, and to permit persons to whom the Software is 15 * furnished to do so, subject to the following conditions: 16 * 17 * The above copyright notice and this permission notice shall be included in all 18 * copies or substantial portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 * SOFTWARE. 27 *************************************************************************************************/ 28 29 /** @file 30 * 31 * @brief JSON serialization and patching routines. 32 * 33 * Supported standards: 34 * 35 * - [JSON Patch](https://tools.ietf.org/html/rfc6902) 36 * - [JSON Merge patch](https://tools.ietf.org/html/rfc7386) 37 * - [JSON Path specification](https://tools.ietf.org/html/rfc6901) 38 * 39 * JSON document can be represented in three different formats: 40 * 41 * - Plain JSON text. 42 * 43 * - @ref JBL Memory compact binary format [Binn](https://github.com/liteserver/binn) 44 * Used for JSON serialization but lacks of data modification flexibility. 45 * 46 * - @ref JBL_NODE In memory JSON document presented as tree. Convenient for in-place 47 * document modification and patching. 48 * 49 * Library function allows conversion of JSON document between above formats. 50 */ 51 52 #include "iwlog.h" 53 #include "iwpool.h" 54 #include "iwxstr.h" 55 #include <stdbool.h> 56 57 IW_EXTERN_C_START 58 59 /** 60 * @brief JSON document in compact binary format [Binn](https://github.com/liteserver/binn) 61 */ 62 struct _JBL; 63 typedef struct _JBL*JBL; 64 65 typedef enum { 66 _JBL_ERROR_START = (IW_ERROR_START + 6000UL), 67 JBL_ERROR_INVALID_BUFFER, /**< Invalid JBL buffer (JBL_ERROR_INVALID_BUFFER) */ 68 JBL_ERROR_CREATION, /**< Cannot create JBL object (JBL_ERROR_CREATION) */ 69 JBL_ERROR_INVALID, /**< Invalid JBL object (JBL_ERROR_INVALID) */ 70 JBL_ERROR_PARSE_JSON, /**< Failed to parse JSON string (JBL_ERROR_PARSE_JSON) */ 71 JBL_ERROR_PARSE_UNQUOTED_STRING, /**< Unquoted JSON string (JBL_ERROR_PARSE_UNQUOTED_STRING) */ 72 JBL_ERROR_PARSE_INVALID_CODEPOINT, 73 /**< Invalid unicode codepoint/escape sequence 74 (JBL_ERROR_PARSE_INVALID_CODEPOINT) */ 75 JBL_ERROR_PARSE_INVALID_UTF8, /**< Invalid utf8 string (JBL_ERROR_PARSE_INVALID_UTF8) */ 76 JBL_ERROR_JSON_POINTER, /**< Invalid JSON pointer (rfc6901) path (JBL_ERROR_JSON_POINTER) */ 77 JBL_ERROR_PATH_NOTFOUND, /**< JSON object not matched the path specified (JBL_ERROR_PATH_NOTFOUND) */ 78 JBL_ERROR_PATCH_INVALID, /**< Invalid JSON patch specified (JBL_ERROR_PATCH_INVALID) */ 79 JBL_ERROR_PATCH_INVALID_OP, /**< Invalid JSON patch operation specified (JBL_ERROR_PATCH_INVALID_OP) */ 80 JBL_ERROR_PATCH_NOVALUE, /**< No value specified in JSON patch (JBL_ERROR_PATCH_NOVALUE) */ 81 JBL_ERROR_PATCH_TARGET_INVALID, 82 /**< Could not find target object to set value (JBL_ERROR_PATCH_TARGET_INVALID) 83 */ 84 JBL_ERROR_PATCH_INVALID_VALUE, /**< Invalid value specified by patch (JBL_ERROR_PATCH_INVALID_VALUE) */ 85 JBL_ERROR_PATCH_INVALID_ARRAY_INDEX, 86 /**< Invalid array index in JSON patch path 87 (JBL_ERROR_PATCH_INVALID_ARRAY_INDEX) */ 88 JBL_ERROR_NOT_AN_OBJECT, /**< JBL is not an object (JBL_ERROR_NOT_AN_OBJECT) */ 89 JBL_ERROR_TYPE_MISMATCHED, 90 /**< Type of JBL object mismatched user type constraints 91 (JBL_ERROR_TYPE_MISMATCHED) */ 92 JBL_ERROR_PATCH_TEST_FAILED, /**< JSON patch test operation failed (JBL_ERROR_PATCH_TEST_FAILED) */ 93 JBL_ERROR_MAX_NESTING_LEVEL_EXCEEDED, 94 /**< Reached the maximal object nesting level: 1000 95 (JBL_ERROR_MAX_NESTING_LEVEL_EXCEEDED) */ 96 _JBL_ERROR_END, 97 } jbl_ecode_t; 98 99 typedef struct _JBL_iterator { 100 unsigned char *pnext; 101 unsigned char *plimit; 102 int type; 103 int count; 104 int current; 105 } JBL_iterator; 106 107 typedef uint8_t jbl_print_flags_t; 108 #define JBL_PRINT_PRETTY ((jbl_print_flags_t) 0x01U) 109 #define JBL_PRINT_CODEPOINTS ((jbl_print_flags_t) 0x02U) 110 111 typedef uint8_t jbn_visitor_cmd_t; 112 #define JBL_VCMD_OK ((jbn_visitor_cmd_t) 0x00U) 113 #define JBL_VCMD_TERMINATE ((jbn_visitor_cmd_t) 0x01U) 114 #define JBL_VCMD_SKIP_NESTED ((jbn_visitor_cmd_t) 0x02U) 115 #define JBN_VCMD_DELETE ((jbn_visitor_cmd_t) 0x04U) 116 117 118 typedef enum { 119 JBV_NONE = 0, // Do not reorder 120 JBV_NULL, 121 JBV_BOOL, // Do not reorder 122 JBV_I64, 123 JBV_F64, 124 JBV_STR, 125 JBV_OBJECT, // Do not reorder 126 JBV_ARRAY, 127 } jbl_type_t; 128 129 /** 130 * @brief JSON document as in-memory tree (DOM tree). 131 */ 132 typedef struct _JBL_NODE { 133 struct _JBL_NODE *next; 134 struct _JBL_NODE *prev; 135 struct _JBL_NODE *parent; /**< Optional parent */ 136 const char *key; 137 int klidx; 138 uint32_t flags; /**< Utility node flags */ 139 140 // Do not sort/add members after this point (offsetof usage below) 141 struct _JBL_NODE *child; 142 int vsize; 143 jbl_type_t type; 144 union { 145 const char *vptr; 146 bool vbool; 147 int64_t vi64; 148 double vf64; 149 }; 150 } *JBL_NODE; 151 152 /** 153 * @brief JSON Patch operation according to rfc6902 154 */ 155 typedef enum { 156 JBP_ADD = 1, 157 JBP_REMOVE, 158 JBP_REPLACE, 159 JBP_COPY, 160 JBP_MOVE, 161 JBP_TEST, 162 // Non standard operations 163 JBP_INCREMENT, /**< Value increment */ 164 JBP_ADD_CREATE, /**< Create intermediate object nodes for missing path segments */ 165 JBP_SWAP, /**< Swap values of two nodes */ 166 } jbp_patch_t; 167 168 /** 169 * @brief JSON patch specification 170 */ 171 typedef struct _JBL_PATCH { 172 jbp_patch_t op; 173 const char *path; 174 const char *from; 175 const char *vjson; 176 JBL_NODE vnode; 177 } JBL_PATCH; 178 179 /** 180 * @brief JSON pointer rfc6901 181 * @see jbl_ptr_alloc() 182 */ 183 typedef struct _JBL_PTR { 184 uint64_t op; /**< Opaque data associated with pointer */ 185 int cnt; /**< Number of nodes */ 186 int sz; /**< Size of JBL_PTR allocated area */ 187 char *n[1]; /**< Path nodes */ 188 } *JBL_PTR; 189 190 /** Prints JSON to some oputput specified by `op` */ 191 typedef iwrc (*jbl_json_printer)(const char *data, int size, char ch, int count, void *op); 192 193 IW_EXPORT void iwjson_ftoa(long double val, char buf[IWNUMBUF_SIZE], size_t *out_len); 194 195 /** 196 * @brief Create empty binary JSON object. 197 * 198 * @note `jblp` should be disposed by `jbl_destroy()` 199 * @see `jbl_fill_from_node()` 200 * @param [out] jblp Pointer to be initialized by new object. 201 */ 202 IW_EXPORT WUR iwrc jbl_create_empty_object(JBL *jblp); 203 204 /** 205 * @brief Create empty binary JSON array. 206 * 207 * @note `jblp` should be disposed by `jbl_destroy()` 208 * @see `jbl_fill_from_node()` 209 * @param [out] jblp Pointer to be initialized by new object. 210 */ 211 IW_EXPORT WUR iwrc jbl_create_empty_array(JBL *jblp); 212 213 /** 214 * @brief Sets arbitrary user data associated with JBL object. 215 * 216 * @param jbl JBL container 217 * @param user_data User data pointer. Optional. 218 * @param user_data_free_fn User data dispose function. Optional. 219 */ 220 IW_EXPORT void jbl_set_user_data(JBL jbl, void *user_data, void (*user_data_free_fn)(void*)); 221 222 /** 223 * @brief Returns user data associated with given `jbl` container. 224 * 225 * @param jbl JBL container. 226 */ 227 IW_EXPORT void* jbl_get_user_data(JBL jbl); 228 229 /** 230 * @brief Set integer JBL object property value 231 * or add a new entry to end of array JBL object. 232 * 233 * In the case when `jbl` object is array value will be added to end array. 234 * 235 * @warning `jbl` object must writable in other words created with 236 * `jbl_create_empty_object()` or `jbl_create_empty_array()` 237 * 238 * @param jbl JBL container 239 * @param key Object key. Does't makes sense for array objects. 240 * @param v Value to set 241 */ 242 IW_EXPORT iwrc jbl_set_int64(JBL jbl, const char *key, int64_t v); 243 244 /** 245 * @brief Set double JBL object property value 246 * or add a new entry to end of array JBL object. 247 * 248 * In the case when `jbl` object is array value will be added to end array. 249 * 250 * @warning `jbl` object must writable in other words created with 251 * `jbl_create_empty_object()` or `jbl_create_empty_array()` 252 * 253 * @param jbl JBL container 254 * @param key Object key. Does't makes sense for array objects. 255 * @param v Value to set 256 */ 257 IW_EXPORT iwrc jbl_set_f64(JBL jbl, const char *key, double v); 258 259 /** 260 * @brief Set string JBL object property value 261 * or add a new entry to end of array JBL object. 262 * 263 * In the case when `jbl` object is array value will be added to end array. 264 * 265 * @warning `jbl` object must writable in other words created with 266 * `jbl_create_empty_object()` or `jbl_create_empty_array()` 267 * 268 * @param jbl JBL container 269 * @param key Object key. Does't makes sense for array objects. 270 * @param v Value to set 271 */ 272 IW_EXPORT iwrc jbl_set_string(JBL jbl, const char *key, const char *v); 273 274 IW_EXPORT iwrc jbl_set_string_printf(JBL jbl, const char *key, const char *format, ...); 275 276 /** 277 * @brief Set bool JBL object property value 278 * or add a new entry to end of array JBL object. 279 * 280 * In the case when `jbl` object is array value will be added to end array. 281 * 282 * @warning `jbl` object must writable in other words created with 283 * `jbl_create_empty_object()` or `jbl_create_empty_array()` 284 * 285 * @param jbl JBL container 286 * @param key Object key. Does't makes sense for array objects. 287 * @param v Value to set 288 */ 289 IW_EXPORT iwrc jbl_set_bool(JBL jbl, const char *key, bool v); 290 291 292 /** 293 * @brief Set null JBL object property value 294 * or add a new entry to end of array JBL object. 295 * 296 * In the case when `jbl` object is array value will be added to end array. 297 * 298 * @warning `jbl` object must writable in other words created with 299 * `jbl_create_empty_object()` or `jbl_create_empty_array()` 300 * 301 * @param jbl JBL container 302 * @param key Object key. Does't makes sense for array objects. 303 * @param v Value to set 304 */ 305 IW_EXPORT iwrc jbl_set_null(JBL jbl, const char *key); 306 307 IW_EXPORT iwrc jbl_set_empty_array(JBL jbl, const char *key); 308 309 IW_EXPORT iwrc jbl_set_empty_object(JBL jbl, const char *key); 310 311 /** 312 * @brief Set nested JBL object property value 313 * or add a new entry to end of array JBL object. 314 * 315 * In the case when `jbl` object is array value will be added to end array. 316 * 317 * @warning `jbl` object must writable in other words created with 318 * `jbl_create_empty_object()` or `jbl_create_empty_array()` 319 * 320 * @param jbl JBL container 321 * @param key Object key. Does't makes sense for array objects. 322 * @param v Value to set 323 */ 324 IW_EXPORT iwrc jbl_set_nested(JBL jbl, const char *key, JBL nested); 325 326 /** 327 * @brief Initialize new `JBL` document by `binn` data from buffer. 328 * @note Created document will be allocated by `malloc()` 329 * and should be destroyed by `jbl_destroy()`. 330 * 331 * @param [out] jblp Pointer initialized by created JBL document. Not zero. 332 * @param buf Memory buffer with `binn` data. Not zero. 333 * @param bufsz Size of `buf` 334 * @param keep_on_destroy If true `buf` not will be freed by `jbl_destroy()` 335 */ 336 IW_EXPORT iwrc jbl_from_buf_keep(JBL *jblp, void *buf, size_t bufsz, bool keep_on_destroy); 337 338 /** 339 * @brief Clones the given `src` JBL object into newly allocated `targetp` object. 340 * 341 * JBL object stored into `targetp` should be disposed by `jbl_destroy()`. 342 * 343 * @param src Source object to clone 344 * @param targetp Pointer on target object. 345 */ 346 IW_EXPORT iwrc jbl_clone(JBL src, JBL *targetp); 347 348 /** 349 * @brief Copy all keys from `src` object into `target` object. 350 * @note Function does not care about keys duplication. 351 * 352 * @param src Source JBL object. Must be object. 353 * @param target Target JBL object. Must be object. 354 */ 355 IW_EXPORT iwrc jbl_object_copy_to(JBL src, JBL target); 356 357 /** 358 * @brief Clones the given `src` JBL_NODE object into new `targetp` instance. 359 * Memory allocateted by given memor `pool` instance. 360 * 361 * @param src Source object to clone 362 * @param target Pointer on new instance 363 * @param pool Memory pool used for allocations during clone object construction 364 */ 365 IW_EXPORT iwrc jbn_clone(JBL_NODE src, JBL_NODE *targetp, IWPOOL *pool); 366 367 /** 368 * @brief Assign a JSON node value from `from` node into `target` node. 369 * Context elements of `target` node: `parent`, `next` are not touched. 370 * 371 * @param target Node 372 * @param from 373 * @return IW_EXPORT jbn_apply_from 374 */ 375 IW_EXPORT void jbn_apply_from(JBL_NODE target, JBL_NODE from); 376 377 /** 378 * @brief Copies JSON subtree under given `src_path` into `target` object under `target_path`. 379 * If some tree exists under `target_path` it will be replaced by copied subtree. 380 * 381 * Copied subtree will be allocated in using given memory `pool`. 382 * 383 * @param src Source JSON tree. 384 * @param src_path Path where copied subtree located. If src_path is `/` then `src` object itself will be cloned. 385 * @param target Target JSON tree. 386 * @param target_path Path to place copied subtree. 387 * @param overwrite_on_nulls If true `null` values will be copied to `src` object as well. 388 * @param no_src_clone If true object pointed by `src_path` object will not be cloned into `pool` before applying patch. 389 * It is a dangerous option if you use same memory pool for source and target objects. 390 * Do not set it to `true` until you clearly understand what are you doing. 391 * @param pool Memory pool used for allocations 392 */ 393 IW_EXPORT iwrc jbn_copy_path( 394 JBL_NODE src, 395 const char *src_path, 396 JBL_NODE target, 397 const char *target_path, 398 bool overwrite_on_nulls, 399 bool no_src_clone, 400 IWPOOL *pool); 401 402 /** 403 * @brief Copies a set of values pointed by `paths` zero terminated array 404 * of `src` object into respective paths of `target` object. 405 * 406 * @param src Source object whose keys will be copied. 407 * @param target Target object to recieve key values of `src` obejct 408 * @param paths Zero terminated array of pointers to zero terminated key names. 409 * @param overwrite_on_nulls If true `null` values will be copied to `src` object as well. 410 * @param no_src_clone If true copied objects will not be cloned into given `pool` before copying. 411 * It is a dangerous option if you use same memory pool for source and target objects. 412 * Do not set it to `true` until you clearly understand what are you doing. 413 * @param pool Memory pool used for allocations 414 */ 415 IW_EXPORT iwrc jbn_copy_paths( 416 JBL_NODE src, 417 JBL_NODE target, 418 const char **paths, 419 bool overwrite_on_nulls, 420 bool no_src_clone, 421 IWPOOL *pool); 422 423 /** 424 * @brief Clones a given `src` JBL object and stores it in memory allocated from `pool`. 425 * 426 * @param src Source object to clone 427 * @param targetp Pointer on target object 428 * @param pool Memory pool 429 */ 430 IW_EXPORT iwrc jbl_clone_into_pool(JBL src, JBL *targetp, IWPOOL *pool); 431 432 /** 433 * @brief Constructs new `JBL` object from JSON string. 434 * @note `jblp` should be disposed by `jbl_destroy()` 435 * @param [out] jblp Pointer initialized by created JBL document. Not zero. 436 * @param jsonstr JSON string to be converted 437 */ 438 IW_EXPORT iwrc jbl_from_json(JBL *jblp, const char *jsonstr); 439 440 441 IW_EXPORT iwrc jbl_from_json_printf(JBL *jblp, const char *format, ...); 442 443 IW_EXPORT iwrc jbl_from_json_printf_va(JBL *jblp, const char *format, va_list va); 444 445 /** 446 * @brief Get type of `jbl` value. 447 */ 448 IW_EXPORT jbl_type_t jbl_type(JBL jbl); 449 450 /** 451 * @brief Get number of child elements in `jbl` container (object/array) or zero. 452 */ 453 IW_EXPORT size_t jbl_count(JBL jbl); 454 455 /** 456 * @brief Get size of undelying data buffer of `jbl` value passed. 457 */ 458 IW_EXPORT size_t jbl_size(JBL jbl); 459 460 /** 461 * @brief Returns size of JBL underlying data structure 462 */ 463 IW_EXPORT size_t jbl_structure_size(void); 464 465 IW_EXPORT iwrc jbl_from_buf_keep_onstack(JBL jbl, void *buf, size_t bufsz); 466 467 /** 468 * @brief Interpret `jbl` value as `int32_t`. 469 * Returns zero if value cannot be converted. 470 */ 471 IW_EXPORT int32_t jbl_get_i32(JBL jbl); 472 473 /** 474 * @brief Interpret `jbl` value as `int64_t`. 475 * Returns zero if value cannot be converted. 476 */ 477 IW_EXPORT int64_t jbl_get_i64(JBL jbl); 478 479 /** 480 * @brief Interpret `jbl` value as `double` value. 481 * Returns zero if value cannot be converted. 482 */ 483 IW_EXPORT double jbl_get_f64(JBL jbl); 484 485 /** 486 * @brief Interpret `jbl` value as `\0` terminated character array. 487 * Returns zero if value cannot be converted. 488 */ 489 IW_EXPORT const char* jbl_get_str(JBL jbl); 490 491 IW_EXPORT iwrc jbl_object_get_i64(JBL jbl, const char *key, int64_t *out); 492 493 IW_EXPORT iwrc jbl_object_get_f64(JBL jbl, const char *key, double *out); 494 495 IW_EXPORT iwrc jbl_object_get_bool(JBL jbl, const char *key, bool *out); 496 497 IW_EXPORT iwrc jbl_object_get_str(JBL jbl, const char *key, const char **out); 498 499 IW_EXPORT iwrc jbl_object_get_fill_jbl(JBL jbl, const char *key, JBL out); 500 501 IW_EXPORT jbl_type_t jbl_object_get_type(JBL jbl, const char *key); 502 503 /** 504 * @brief Same as `jbl_get_str()` but copies at most `bufsz` into target `buf`. 505 * Target buffer not touched if `jbl` value cannot be converted. 506 */ 507 IW_EXPORT size_t jbl_copy_strn(JBL jbl, char *buf, size_t bufsz); 508 509 /** 510 * @brief Finds value in `jbl` document pointed by rfc6901 `path` and store it into `res`. 511 * 512 * @note `res` should be disposed by `jbl_destroy()`. 513 * @note If value is not fount `res` will be set to zero. 514 * @param jbl JBL document. Not zero. 515 * @param path rfc6901 JSON pointer. Not zero. 516 * @param [out] res Output value holder 517 */ 518 IW_EXPORT iwrc jbl_at(JBL jbl, const char *path, JBL *res); 519 520 IW_EXPORT iwrc jbn_at(JBL_NODE node, const char *path, JBL_NODE *res); 521 522 IW_EXPORT int jbn_path_compare(JBL_NODE n1, JBL_NODE n2, const char *path, jbl_type_t vtype, iwrc *rcp); 523 524 IW_EXPORT int jbn_paths_compare( 525 JBL_NODE n1, const char *n1path, JBL_NODE n2, const char *n2path, jbl_type_t vtype, 526 iwrc *rcp); 527 528 IW_EXPORT int jbn_path_compare_str(JBL_NODE n, const char *path, const char *sv, iwrc *rcp); 529 530 IW_EXPORT int jbn_path_compare_i64(JBL_NODE n, const char *path, int64_t iv, iwrc *rcp); 531 532 IW_EXPORT int jbn_path_compare_f64(JBL_NODE n, const char *path, double fv, iwrc *rcp); 533 534 IW_EXPORT int jbn_path_compare_bool(JBL_NODE n, const char *path, bool bv, iwrc *rcp); 535 536 /** 537 * @brief @brief Finds value in `jbl` document pointed by `jp` structure and store it into `res`. 538 * 539 * @note `res` should be disposed by `jbl_destroy()`. 540 * @note If value is not fount `res` will be set to zero. 541 * @see `jbl_ptr_alloc()` 542 * @param jbl JBL document. Not zero. 543 * @param jp JSON pointer. 544 * @param [out] res Output value holder 545 */ 546 IW_EXPORT iwrc jbl_at2(JBL jbl, JBL_PTR jp, JBL *res); 547 548 IW_EXPORT iwrc jbn_at2(JBL_NODE node, JBL_PTR jp, JBL_NODE *res); 549 550 /** 551 * @brief Represent `jbl` document as raw data buffer. 552 * 553 * @note Caller do not require release `buf` explicitly. 554 * @param jbl JBL document. Not zero. 555 * @param [out] buf Pointer to data buffer. Not zero. 556 * @param [out] size Pointer to data buffer size. Not zero. 557 */ 558 IW_EXPORT iwrc jbl_as_buf(JBL jbl, void **buf, size_t *size); 559 560 /** 561 * @brief Prints JBL document as JSON string. 562 * 563 * @see jbl_fstream_json_printer() 564 * @see jbl_xstr_json_printer() 565 * @see jbl_count_json_printer() 566 * 567 * @param jbl JBL document. Not zero. 568 * @param pt JSON printer function pointer. Not zero. 569 * @param op Pointer to user data for JSON printer function. 570 * @param pf JSON printing mode. 571 */ 572 IW_EXPORT iwrc jbl_as_json(JBL jbl, jbl_json_printer pt, void *op, jbl_print_flags_t pf); 573 574 /** 575 * @brief JSON printer to stdlib `FILE*`pointer. Eg: `stderr`, `stdout` 576 * @param op `FILE*` pointer 577 */ 578 IW_EXPORT iwrc jbl_fstream_json_printer(const char *data, int size, char ch, int count, void *op); 579 580 /** 581 * @brief JSON printer to extended string buffer `IWXSTR` 582 * @param op `IWXSTR*` pointer 583 */ 584 IW_EXPORT iwrc jbl_xstr_json_printer(const char *data, int size, char ch, int count, void *op); 585 586 /** 587 * @brief Just counts bytes in JSON text. 588 * @param op `int*` Pointer to counter number. 589 */ 590 IW_EXPORT iwrc jbl_count_json_printer(const char *data, int size, char ch, int count, void *op); 591 592 /** 593 * @brief Destroys JBL document and releases its heap resources. 594 * @note Will set `jblp` to zero. 595 * @param jblp Pointer holder of JBL document. Not zero. 596 */ 597 IW_EXPORT void jbl_destroy(JBL *jblp); 598 599 /** 600 * @brief Initializes placeholder for jbl iteration. 601 * Must be freed by `jbl_destroy()` after iteration. 602 * @param [out] jblp Pointer to be initialized by new object. 603 */ 604 IW_EXPORT iwrc jbl_create_iterator_holder(JBL *jblp); 605 606 /** 607 * @brief Initialize allocated iterator over given `jbl` object. 608 * 609 * @param jbl JBL object to iterate 610 * @param iter Iterator state placeholder allocated by `jbl_create_iter_placeholder()` 611 */ 612 IW_EXPORT iwrc jbl_iterator_init(JBL jbl, JBL_iterator *iter); 613 614 /** 615 * @brief Get next value from JBL_iterator. 616 * Returns `false` if iteration is over. 617 * 618 * @param iter Iterator object. 619 * @param holder Holder to object pointed by current iteration. 620 * @param pkey Key value holder. Zero in the case of iteration over array. 621 * @param klen Key length or array index in the case of iteration over array. 622 */ 623 IW_EXPORT bool jbl_iterator_next(JBL_iterator *iter, JBL holder, char **pkey, int *klen); 624 625 //--- JBL_NODE 626 627 /** 628 * @brief Converts `jbl` value to `JBL_NODE` tree. 629 * @note `node` resources will be released when `pool` destroyed. 630 * 631 * @param jbl JSON document in compact `binn` format. Not zero. 632 * @param [out] node Holder of new `JBL_NODE` value. Not zero. 633 * @param clone_strings If `true` JSON keys and string values will be cloned into given `pool` 634 * otherwise only pointers to strings will be assigned. 635 * Use `true` if you want to be completely safe when given `jbl` 636 * object will be destroyed. 637 * @param pool Memory used to allocate new `JBL_NODE` tree. Not zero. 638 */ 639 IW_EXPORT iwrc jbl_to_node(JBL jbl, JBL_NODE *node, bool clone_strings, IWPOOL *pool); 640 641 /** 642 * @brief Converts `json` text to `JBL_NODE` tree. 643 * @note `node` resources will be released when `pool` destroyed. 644 * 645 * @param json JSON text 646 * @param [out] node Holder of new `JBL_NODE` value. Not zero. 647 * @param pool Memory used to allocate new `JBL_NODE` tree. Not zero. 648 */ 649 IW_EXPORT iwrc jbn_from_json(const char *json, JBL_NODE *node, IWPOOL *pool); 650 651 IW_EXPORT iwrc jbn_from_json_printf(JBL_NODE *node, IWPOOL *pool, const char *format, ...); 652 653 IW_EXPORT iwrc jbn_from_json_printf_va(JBL_NODE *node, IWPOOL *pool, const char *format, va_list va); 654 655 /** 656 * @brief Prints JBL_NODE document as JSON string. 657 * 658 * @see jbl_fstream_json_printer() 659 * @see jbl_xstr_json_printer() 660 * @see jbl_count_json_printer() 661 * 662 * @param node `JBL_NODE` document. Not zero. 663 * @param pt JSON printer function. Not zero. 664 * @param op Pointer to user data for JSON printer function. 665 * @param pf JSON printing mode. 666 */ 667 IW_EXPORT iwrc jbn_as_json(JBL_NODE node, jbl_json_printer pt, void *op, jbl_print_flags_t pf); 668 669 /** 670 * @brief Fill `jbl` document by data from `node`. 671 * 672 * Common use case: 673 * Create empty document with `jbl_create_empty_object()` `jbl_create_empty_array()` 674 * then fill it with `jbl_fill_from_node()` 675 * 676 * @param jbl JBL document to be filled. Not zero. 677 * @param node Source tree node. Not zero. 678 */ 679 IW_EXPORT iwrc jbl_fill_from_node(JBL jbl, JBL_NODE node); 680 681 /** 682 * @brief Converts `node` object into JBL form. 683 * 684 * @param jblp JBL pointer holder. Not zero. 685 * @param node Source tree node. Not zero. 686 * @return IW_EXPORT jbl_from_node 687 */ 688 IW_EXPORT iwrc jbl_from_node(JBL *jblp, JBL_NODE node); 689 690 /** 691 * @brief Compares JSON tree nodes. 692 * 693 * - Primitive JSON values compared as is. 694 * - JSON arrays compared by values held in the same position in array. 695 * - JSON objects compared by corresponding values held under lexicographically sorted keys. 696 * 697 * @param n1 698 * @param n2 699 * @param [out] rcp 700 * 701 * @return - Not zero if `n1` and `n2` have different types. 702 * - Zero if `n1` and `n2` are equal. 703 * - Greater than zero if `n1` greater than `n2` 704 * - Lesser than zero if `n1` lesser than `n2` 705 */ 706 IW_EXPORT int jbn_compare_nodes(JBL_NODE n1, JBL_NODE n2, iwrc *rcp); 707 708 /** 709 * @brief Add item to the `parent` container. 710 */ 711 IW_EXPORT void jbn_add_item(JBL_NODE parent, JBL_NODE node); 712 713 /** 714 * @brief Adds string JSON node to the given `parent` node. 715 * Key and value are copied into allocated node. 716 * 717 * @param parent Parent holder. 718 * @param key Child node key cloned into node. Can be zero if parent is an array. 719 * @param val Child node value copied. 720 * @param vlen Langth of child node value. 721 * If `vlen` is lesser then zero length of `val` will be determined my `strlen`. 722 * @param node_out Optional placeholder for new node. 723 * @param pool Allocation pool. 724 */ 725 IW_EXPORT iwrc jbn_add_item_str( 726 JBL_NODE parent, const char *key, const char *val, int vlen, JBL_NODE *node_out, 727 IWPOOL *pool); 728 729 /** 730 * @brief Adds null JSON value to the given `parent` node. 731 * 732 * @param parent Parent holder. 733 * @param key Child node key cloned into node. Can be zero if parent is an array. 734 * @param pool Allocation pool. 735 */ 736 IW_EXPORT iwrc jbn_add_item_null(JBL_NODE parent, const char *key, IWPOOL *pool); 737 738 /** 739 * @brief Adds integer JSON node to the given `parent` node. 740 * 741 * @param parent Parent holder. 742 * @param key Child node key cloned into node. Can be zero if parent is an array. 743 * @param val Integer value. 744 * @param node_out Optional placeholder for new node. 745 * @param pool Allocation pool. 746 */ 747 IW_EXPORT iwrc jbn_add_item_i64(JBL_NODE parent, const char *key, int64_t val, JBL_NODE *node_out, IWPOOL *pool); 748 749 /** 750 * @brief Adds fp number JSON node to the given `parent` node. 751 * 752 * @param parent Parent holder. 753 * @param key Child node key cloned into node. Can be zero if parent is an array. 754 * @param val Floating point value. 755 * @param node_out Optional placeholder for new node. 756 * @param pool Allocation pool. 757 */ 758 IW_EXPORT iwrc jbn_add_item_f64(JBL_NODE parent, const char *key, double val, JBL_NODE *node_out, IWPOOL *pool); 759 760 /** 761 * @brief Add nested object under the given `key` 762 * 763 * @param parent Parent holder 764 * @param key Child node key cloned into node. Can be zero if parent is an array. 765 * @param node_out [out] Pointer to new node, can be zero. 766 * @param pool Allocation pool 767 * @return IW_EXPORT jbn_add_item_obj 768 */ 769 IW_EXPORT iwrc jbn_add_item_obj(JBL_NODE parent, const char *key, JBL_NODE *node_out, IWPOOL *pool); 770 771 /** 772 * @brief Add nested array under the given `key` 773 * 774 * @param parent Parent holder 775 * @param key Child node key cloned into node. Can be zero if parent is an array. 776 * @param node_out [out] Pointer to new node, can be zero. 777 * @param pool Allocation pool 778 * @return IW_EXPORT jbn_add_item_obj 779 */ 780 IW_EXPORT iwrc jbn_add_item_arr(JBL_NODE parent, const char *key, JBL_NODE *node_out, IWPOOL *pool); 781 782 /** 783 * @brief Adds boolean JSON node to the given `parent` node. 784 * 785 * @param parent Parent holder. 786 * @param key Child node key cloned into node. Can be zero if parent is an array. 787 * @param val Boolean node value. 788 * @param node_out [out] Pointer to new node, can be zero. 789 * @param pool Allocation pool. 790 */ 791 IW_EXPORT iwrc jbn_add_item_bool(JBL_NODE parent, const char *key, bool val, JBL_NODE *node_out, IWPOOL *pool); 792 793 /** 794 * @brief Add item from the `parent` container. 795 */ 796 IW_EXPORT void jbn_remove_item(JBL_NODE parent, JBL_NODE child); 797 798 /** 799 * @brief Remove subtree from `target` node pointed by `path` 800 */ 801 IW_EXPORT JBL_NODE jbn_detach2(JBL_NODE target, JBL_PTR path); 802 803 IW_EXPORT JBL_NODE jbn_detach(JBL_NODE target, const char *path); 804 805 /** 806 * @brief Reset tree `node` data. 807 */ 808 IW_EXPORT void jbn_data(JBL_NODE node); 809 810 /** 811 * @brief Returns number of child elements of given node. 812 * 813 * @param node JBL node 814 */ 815 IW_EXPORT int jbn_length(JBL_NODE node); 816 817 /** 818 * @brief Parses rfc6901 JSON path. 819 * @note `jpp` structure should be disposed by `free()`. 820 * 821 * @param path JSON path string. Not zero. 822 * @param [out] jpp Holder for parsed path structure. Not zero. 823 */ 824 IW_EXPORT iwrc jbl_ptr_alloc(const char *path, JBL_PTR *jpp); 825 826 /** 827 * @brief Parses rfc6901 JSON path. 828 * 829 * @param path JSON path string. Not zero. 830 * @param [out] jpp JSON path string. Not zero. 831 * @param pool Pool used for memory allocation. Not zero. 832 */ 833 IW_EXPORT iwrc jbl_ptr_alloc_pool(const char *path, JBL_PTR *jpp, IWPOOL *pool); 834 835 /** 836 * @brief Compare JSON pointers. 837 */ 838 IW_EXPORT int jbl_ptr_cmp(JBL_PTR p1, JBL_PTR p2); 839 840 /** 841 * @brief Serialize JSON pointer to as text. 842 * @param ptr JSON pointer. Not zero. 843 * @param xstr Output string buffer. Not zero. 844 */ 845 IW_EXPORT iwrc jbl_ptr_serialize(JBL_PTR ptr, IWXSTR *xstr); 846 847 /** 848 * @brief JBL_NODE visitor context 849 */ 850 typedef struct _JBN_VCTX { 851 JBL_NODE root; /**< Root node from which started visitor */ 852 void *op; /**< Arbitrary opaque data */ 853 void *result; 854 IWPOOL *pool; /**< Pool placeholder, initialization is responsibility of `JBN_VCTX` creator */ 855 int pos; /**< Aux position, not actually used by visitor core */ 856 bool terminate; /**< It `true` document traversal will be terminated immediately. */ 857 } JBN_VCTX; 858 859 /** 860 * Call with lvl: `-1` means end of visiting whole object tree. 861 */ 862 typedef jbn_visitor_cmd_t (*JBN_VISITOR)(int lvl, JBL_NODE n, const char *key, int klidx, JBN_VCTX *vctx, iwrc *rc); 863 864 IW_EXPORT iwrc jbn_visit(JBL_NODE node, int lvl, JBN_VCTX *vctx, JBN_VISITOR visitor); 865 866 //--- PATCHING 867 868 IW_EXPORT iwrc jbn_patch_auto(JBL_NODE root, JBL_NODE patch, IWPOOL *pool); 869 870 IW_EXPORT iwrc jbn_merge_patch(JBL_NODE root, JBL_NODE patch, IWPOOL *pool); 871 872 IW_EXPORT iwrc jbn_patch(JBL_NODE root, const JBL_PATCH *patch, size_t cnt, IWPOOL *pool); 873 874 IW_EXPORT iwrc jbn_merge_patch_from_json(JBL_NODE root, const char *patchjson, IWPOOL *pool); 875 876 IW_EXPORT iwrc jbl_patch(JBL jbl, const JBL_PATCH *patch, size_t cnt); 877 878 IW_EXPORT iwrc jbl_patch_from_json(JBL jbl, const char *patchjson); 879 880 IW_EXPORT iwrc jbl_merge_patch(JBL jbl, const char *patchjson); 881 882 IW_EXPORT iwrc jbl_merge_patch_jbl(JBL jbl, JBL patch); 883 884 885 IW_EXPORT iwrc jbl_init(void); 886 887 IW_EXTERN_C_END 888 #endif 889