• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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