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