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