• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "jbl.h"
2 #include <ctype.h>
3 #include <stdarg.h>
4 #include <ejdb2/iowow/iwconv.h>
5 #include "jbl_internal.h"
6 #include "utf8proc.h"
7 #include "convert.h"
8 
9 #define _STRX(x) #x
10 #define _STR(x)  _STRX(x)
11 
_jbl_printf_estimate_size(const char * format,va_list ap)12 IW_INLINE int _jbl_printf_estimate_size(const char *format, va_list ap) {
13   char buf[1];
14   return vsnprintf(buf, sizeof(buf), format, ap) + 1;
15 }
16 
17 IW_INLINE void _jbn_remove_item(JBL_NODE parent, JBL_NODE child);
18 static void _jbn_add_item(JBL_NODE parent, JBL_NODE node);
19 
jbl_create_empty_object(JBL * jblp)20 iwrc jbl_create_empty_object(JBL *jblp) {
21   *jblp = calloc(1, sizeof(**jblp));
22   if (!*jblp) {
23     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
24   }
25   binn_create(&(*jblp)->bn, BINN_OBJECT, 0, 0);
26   return 0;
27 }
28 
jbl_create_empty_array(JBL * jblp)29 iwrc jbl_create_empty_array(JBL *jblp) {
30   *jblp = calloc(1, sizeof(**jblp));
31   if (!*jblp) {
32     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
33   }
34   binn_create(&(*jblp)->bn, BINN_LIST, 0, 0);
35   return 0;
36 }
37 
jbl_set_user_data(JBL jbl,void * user_data,void (* user_data_free_fn)(void *))38 void jbl_set_user_data(JBL jbl, void *user_data, void (*user_data_free_fn)(void*)) {
39   binn_set_user_data(&jbl->bn, user_data, user_data_free_fn);
40 }
41 
jbl_get_user_data(JBL jbl)42 void *jbl_get_user_data(JBL jbl) {
43   return jbl->bn.user_data;
44 }
45 
jbl_set_int64(JBL jbl,const char * key,int64_t v)46 iwrc jbl_set_int64(JBL jbl, const char *key, int64_t v) {
47   jbl_type_t t = jbl_type(jbl);
48   if (((t != JBV_OBJECT) && (t != JBV_ARRAY)) || !jbl->bn.writable) {
49     return JBL_ERROR_CREATION;
50   }
51   binn *bv = &jbl->bn;
52   if (key) {
53     if (t == JBV_OBJECT) {
54       if (!binn_object_set_int64(bv, key, v)) {
55         return JBL_ERROR_CREATION;
56       }
57     } else {
58       return JBL_ERROR_CREATION;
59     }
60     return 0;
61   } else if (t == JBV_ARRAY) {
62     if (!binn_list_add_int64(bv, v)) {
63       return JBL_ERROR_CREATION;
64     }
65     return 0;
66   }
67   return JBL_ERROR_INVALID;
68 }
69 
jbl_set_f64(JBL jbl,const char * key,double v)70 iwrc jbl_set_f64(JBL jbl, const char *key, double v) {
71   jbl_type_t t = jbl_type(jbl);
72   if (((t != JBV_OBJECT) && (t != JBV_ARRAY)) || !jbl->bn.writable) {
73     return JBL_ERROR_CREATION;
74   }
75   binn *bv = &jbl->bn;
76   if (key) {
77     if (t == JBV_OBJECT) {
78       if (!binn_object_set_double(bv, key, v)) {
79         return JBL_ERROR_CREATION;
80       }
81     } else {
82       return JBL_ERROR_CREATION;
83     }
84     return 0;
85   } else if (t == JBV_ARRAY) {
86     if (!binn_list_add_double(bv, v)) {
87       return JBL_ERROR_CREATION;
88     }
89     return 0;
90   }
91   return JBL_ERROR_INVALID;
92 }
93 
jbl_set_string(JBL jbl,const char * key,const char * v)94 iwrc jbl_set_string(JBL jbl, const char *key, const char *v) {
95   jbl_type_t t = jbl_type(jbl);
96   if (((t != JBV_OBJECT) && (t != JBV_ARRAY)) || !jbl->bn.writable) {
97     return JBL_ERROR_CREATION;
98   }
99   binn *bv = &jbl->bn;
100   if (key) {
101     if (t == JBV_OBJECT) {
102       if (!binn_object_set_str(bv, key, v)) {
103         return JBL_ERROR_CREATION;
104       }
105     } else {
106       return JBL_ERROR_CREATION;
107     }
108     return 0;
109   } else if (t == JBV_ARRAY) {
110     if (!binn_list_add_const_str(bv, v)) {
111       return JBL_ERROR_CREATION;
112     }
113     return 0;
114   }
115   return JBL_ERROR_INVALID;
116 }
117 
jbl_set_string_printf(JBL jbl,const char * key,const char * format,...)118 iwrc jbl_set_string_printf(JBL jbl, const char *key, const char *format, ...) {
119   iwrc rc = 0;
120   va_list ap;
121 
122   va_start(ap, format);
123   int size = _jbl_printf_estimate_size(format, ap);
124   va_end(ap);
125 
126   va_start(ap, format);
127   char *buf = malloc(size);
128   RCGA(buf, finish);
129   vsnprintf(buf, size, format, ap);
130   va_end(ap);
131 
132   rc = jbl_set_string(jbl, key, buf);
133 finish:
134   free(buf);
135   return rc;
136 }
137 
jbl_from_json_printf_va(JBL * jblp,const char * format,va_list va)138 iwrc jbl_from_json_printf_va(JBL *jblp, const char *format, va_list va) {
139   iwrc rc = 0;
140   va_list cva;
141 
142   va_copy(cva, va);
143   int size = _jbl_printf_estimate_size(format, va);
144   char *buf = malloc(size);
145   RCGA(buf, finish);
146   vsnprintf(buf, size, format, cva);
147   va_end(cva);
148 
149   rc = jbl_from_json(jblp, buf);
150 
151 finish:
152   free(buf);
153   return rc;
154 }
155 
jbl_from_json_printf(JBL * jblp,const char * format,...)156 iwrc jbl_from_json_printf(JBL *jblp, const char *format, ...) {
157   va_list ap;
158 
159   va_start(ap, format);
160   iwrc rc = jbl_from_json_printf_va(jblp, format, ap);
161   va_end(ap);
162   return rc;
163 }
164 
jbn_from_json_printf_va(JBL_NODE * node,IWPOOL * pool,const char * format,va_list va)165 iwrc jbn_from_json_printf_va(JBL_NODE *node, IWPOOL *pool, const char *format, va_list va) {
166   iwrc rc = 0;
167   va_list cva;
168 
169   va_copy(cva, va);
170   int size = _jbl_printf_estimate_size(format, va);
171   char *buf = malloc(size);
172   RCGA(buf, finish);
173   vsnprintf(buf, size, format, cva);
174   va_end(cva);
175 
176   rc = jbn_from_json(buf, node, pool);
177 
178 finish:
179   free(buf);
180   return rc;
181 }
182 
jbn_from_json_printf(JBL_NODE * node,IWPOOL * pool,const char * format,...)183 iwrc jbn_from_json_printf(JBL_NODE *node, IWPOOL *pool, const char *format, ...) {
184   va_list ap;
185 
186   va_start(ap, format);
187   iwrc rc = jbn_from_json_printf_va(node, pool, format, ap);
188   va_end(ap);
189   return rc;
190 }
191 
jbl_set_bool(JBL jbl,const char * key,bool v)192 iwrc jbl_set_bool(JBL jbl, const char *key, bool v) {
193   jbl_type_t t = jbl_type(jbl);
194   if (((t != JBV_OBJECT) && (t != JBV_ARRAY)) || !jbl->bn.writable) {
195     return JBL_ERROR_CREATION;
196   }
197   binn *bv = &jbl->bn;
198   if (key) {
199     if (t == JBV_OBJECT) {
200       if (!binn_object_set_bool(bv, key, v)) {
201         return JBL_ERROR_CREATION;
202       }
203     } else {
204       return JBL_ERROR_CREATION;
205     }
206     return 0;
207   } else if (t == JBV_ARRAY) {
208     if (!binn_list_add_bool(bv, v)) {
209       return JBL_ERROR_CREATION;
210     }
211     return 0;
212   }
213   return JBL_ERROR_INVALID;
214 }
215 
jbl_set_null(JBL jbl,const char * key)216 iwrc jbl_set_null(JBL jbl, const char *key) {
217   jbl_type_t t = jbl_type(jbl);
218   if (((t != JBV_OBJECT) && (t != JBV_ARRAY)) || !jbl->bn.writable) {
219     return JBL_ERROR_CREATION;
220   }
221   binn *bv = &jbl->bn;
222   if (key) {
223     if (t == JBV_OBJECT) {
224       if (!binn_object_set_null(bv, key)) {
225         return JBL_ERROR_CREATION;
226       }
227     } else {
228       return JBL_ERROR_CREATION;
229     }
230     return 0;
231   } else if (t == JBV_ARRAY) {
232     if (!binn_list_add_null(bv)) {
233       return JBL_ERROR_CREATION;
234     }
235     return 0;
236   }
237   return JBL_ERROR_INVALID;
238 }
239 
jbl_set_empty_array(JBL jbl,const char * key)240 iwrc jbl_set_empty_array(JBL jbl, const char *key) {
241   JBL v = 0;
242   iwrc rc = jbl_create_empty_array(&v);
243   RCGO(rc, finish);
244   rc = jbl_set_nested(jbl, key, v);
245 finish:
246   jbl_destroy(&v);
247   return rc;
248 }
249 
jbl_set_empty_object(JBL jbl,const char * key)250 iwrc jbl_set_empty_object(JBL jbl, const char *key) {
251   JBL v = 0;
252   iwrc rc = jbl_create_empty_object(&v);
253   RCGO(rc, finish);
254   rc = jbl_set_nested(jbl, key, v);
255 finish:
256   jbl_destroy(&v);
257   return rc;
258 }
259 
jbl_set_nested(JBL jbl,const char * key,JBL v)260 iwrc jbl_set_nested(JBL jbl, const char *key, JBL v) {
261   jbl_type_t t = jbl_type(jbl);
262   if (((t != JBV_OBJECT) && (t != JBV_ARRAY)) || !jbl->bn.writable) {
263     return JBL_ERROR_CREATION;
264   }
265   binn *bv = &jbl->bn;
266   if (key) {
267     if (t == JBV_OBJECT) {
268       if (!binn_object_set_value(bv, key, &v->bn)) {
269         return JBL_ERROR_CREATION;
270       }
271     } else {
272       return JBL_ERROR_CREATION;
273     }
274     return 0;
275   } else if (t == JBV_ARRAY) {
276     if (!binn_list_add_value(bv, &v->bn)) {
277       return JBL_ERROR_CREATION;
278     }
279     return 0;
280   }
281   return JBL_ERROR_INVALID;
282 }
283 
jbl_from_buf_keep(JBL * jblp,void * buf,size_t bufsz,bool keep_on_destroy)284 iwrc jbl_from_buf_keep(JBL *jblp, void *buf, size_t bufsz, bool keep_on_destroy) {
285   int type, size = 0, count = 0;
286   if ((bufsz < MIN_BINN_SIZE) || !binn_is_valid_header(buf, &type, &count, &size, NULL)) {
287     return JBL_ERROR_INVALID_BUFFER;
288   }
289   if (size > bufsz) {
290     return JBL_ERROR_INVALID_BUFFER;
291   }
292   *jblp = calloc(1, sizeof(**jblp));
293   if (!*jblp) {
294     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
295   }
296   JBL jbl = *jblp;
297   jbl->bn.header = BINN_MAGIC;
298   jbl->bn.type = type;
299   jbl->bn.ptr = buf;
300   jbl->bn.size = size;
301   jbl->bn.count = count;
302   jbl->bn.freefn = keep_on_destroy ? 0 : free;
303   return 0;
304 }
305 
jbl_clone(JBL src,JBL * targetp)306 iwrc jbl_clone(JBL src, JBL *targetp) {
307   *targetp = calloc(1, sizeof(**targetp));
308   JBL t = *targetp;
309   if (!t) {
310     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
311   }
312   binn *bn = binn_copy(&src->bn);
313   if (!bn) {
314     return JBL_ERROR_CREATION;
315   }
316   t->node = 0;
317   bn->allocated = 0;
318   memcpy(&t->bn, bn, sizeof(*bn));
319   free(bn);
320   return 0;
321 }
322 
jbl_object_copy_to(JBL src,JBL target)323 IW_EXPORT iwrc jbl_object_copy_to(JBL src, JBL target) {
324   iwrc rc = 0;
325   // According to binn spec keys are not null terminated
326   // and key length is not more than 255 bytes
327   char *key, kbuf[256];
328   int klen;
329   JBL holder = 0;
330   JBL_iterator it;
331 
332   if ((jbl_type(src) != JBV_OBJECT) || (jbl_type(target) != JBV_OBJECT)) {
333     return JBL_ERROR_NOT_AN_OBJECT;
334   }
335   RCC(rc, finish, jbl_create_iterator_holder(&holder));
336   RCC(rc, finish, jbl_iterator_init(src, &it));
337   while (jbl_iterator_next(&it, holder, &key, &klen)) {
338     memcpy(kbuf, key, klen);
339     kbuf[klen] = '\0';
340     RCC(rc, finish, jbl_set_nested(target, kbuf, holder));
341   }
342 
343 finish:
344   jbl_destroy(&holder);
345   return rc;
346 }
347 
jbl_clone_into_pool(JBL src,JBL * targetp,IWPOOL * pool)348 iwrc jbl_clone_into_pool(JBL src, JBL *targetp, IWPOOL *pool) {
349   *targetp = 0;
350   if (src->bn.writable && src->bn.dirty) {
351     if (!binn_save_header(&src->bn)) {
352       return JBL_ERROR_INVALID;
353     }
354   }
355   JBL jbl = iwpool_alloc(sizeof(*jbl) + src->bn.size, pool);
356   if (!jbl) {
357     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
358   }
359   jbl->node = 0;
360   memcpy(&jbl->bn, &src->bn, sizeof(jbl->bn));
361   jbl->bn.ptr = (char*) jbl + sizeof(*jbl);
362   memcpy(jbl->bn.ptr, src->bn.ptr, src->bn.size);
363   jbl->bn.freefn = 0;
364   *targetp = jbl;
365   return 0;
366 }
367 
jbl_from_buf_keep_onstack(JBL jbl,void * buf,size_t bufsz)368 iwrc jbl_from_buf_keep_onstack(JBL jbl, void *buf, size_t bufsz) {
369   int type, size = 0, count = 0;
370   if ((bufsz < MIN_BINN_SIZE) || !binn_is_valid_header(buf, &type, &count, &size, NULL)) {
371     return JBL_ERROR_INVALID_BUFFER;
372   }
373   if (size > bufsz) {
374     return JBL_ERROR_INVALID_BUFFER;
375   }
376   memset(jbl, 0, sizeof(*jbl));
377   jbl->bn.header = BINN_MAGIC;
378   jbl->bn.type = type;
379   jbl->bn.ptr = buf;
380   jbl->bn.size = size;
381   jbl->bn.count = count;
382   return 0;
383 }
384 
jbl_from_buf_keep_onstack2(JBL jbl,void * buf)385 iwrc jbl_from_buf_keep_onstack2(JBL jbl, void *buf) {
386   int type, size = 0, count = 0;
387   if (!binn_is_valid_header(buf, &type, &count, &size, NULL)) {
388     return JBL_ERROR_INVALID_BUFFER;
389   }
390   memset(jbl, 0, sizeof(*jbl));
391   jbl->bn.header = BINN_MAGIC;
392   jbl->bn.type = type;
393   jbl->bn.ptr = buf;
394   jbl->bn.size = size;
395   jbl->bn.count = count;
396   return 0;
397 }
398 
jbl_destroy(JBL * jblp)399 void jbl_destroy(JBL *jblp) {
400   if (*jblp) {
401     JBL jbl = *jblp;
402     binn_free(&jbl->bn);
403     free(jbl);
404     *jblp = 0;
405   }
406 }
407 
jbl_create_iterator_holder(JBL * jblp)408 iwrc jbl_create_iterator_holder(JBL *jblp) {
409   *jblp = calloc(1, sizeof(**jblp));
410   if (!*jblp) {
411     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
412   }
413   return 0;
414 }
415 
jbl_iterator_init(JBL jbl,JBL_iterator * iter)416 iwrc jbl_iterator_init(JBL jbl, JBL_iterator *iter) {
417   int btype = jbl->bn.type;
418   if ((btype != BINN_OBJECT) && (btype != BINN_LIST) && (btype != BINN_MAP)) {
419     memset(iter, 0, sizeof(*iter));
420     return 0;
421   }
422   binn_iter *biter = (binn_iter*) iter;
423   if (!binn_iter_init(biter, &jbl->bn, btype)) {
424     return JBL_ERROR_CREATION;
425   }
426   return 0;
427 }
428 
jbl_iterator_next(JBL_iterator * iter,JBL holder,char ** pkey,int * klen)429 bool jbl_iterator_next(JBL_iterator *iter, JBL holder, char **pkey, int *klen) {
430   binn_iter *biter = (binn_iter*) iter;
431   if (pkey) {
432     *pkey = 0;
433   }
434   if (klen) {
435     *klen = 0;
436   }
437   if (!iter || (iter->type == 0)) {
438     return false;
439   }
440   if (iter->type == BINN_LIST) {
441     if (klen) {
442       *klen = iter->current;
443     }
444     return binn_list_next(biter, &holder->bn);
445   } else {
446     return binn_read_next_pair2(iter->type, biter, klen, pkey, &holder->bn);
447   }
448   return false;
449 }
450 
_jbl_binn_type(int btype)451 IW_INLINE jbl_type_t _jbl_binn_type(int btype) {
452   switch (btype) {
453     case BINN_NULL:
454       return JBV_NULL;
455     case BINN_STRING:
456       return JBV_STR;
457     case BINN_OBJECT:
458     case BINN_MAP:
459       return JBV_OBJECT;
460     case BINN_LIST:
461       return JBV_ARRAY;
462     case BINN_BOOL:
463     case BINN_TRUE:
464     case BINN_FALSE:
465       return JBV_BOOL;
466     case BINN_UINT8:
467     case BINN_UINT16:
468     case BINN_UINT32:
469     case BINN_UINT64:
470     case BINN_INT8:
471     case BINN_INT16:
472     case BINN_INT32:
473     case BINN_INT64:
474       return JBV_I64;
475     case BINN_FLOAT32:
476     case BINN_FLOAT64:
477       return JBV_F64;
478     default:
479       return JBV_NONE;
480   }
481 }
482 
jbl_type(JBL jbl)483 jbl_type_t jbl_type(JBL jbl) {
484   if (jbl) {
485     return _jbl_binn_type(jbl->bn.type);
486   }
487   return JBV_NONE;
488 }
489 
jbl_count(JBL jbl)490 size_t jbl_count(JBL jbl) {
491   return (size_t) jbl->bn.count;
492 }
493 
jbl_size(JBL jbl)494 size_t jbl_size(JBL jbl) {
495   return (size_t) jbl->bn.size;
496 }
497 
jbl_structure_size(void)498 size_t jbl_structure_size(void) {
499   return sizeof(struct _JBL);
500 }
501 
jbl_from_json(JBL * jblp,const char * jsonstr)502 iwrc jbl_from_json(JBL *jblp, const char *jsonstr) {
503   *jblp = 0;
504   iwrc rc = 0;
505   IWPOOL *pool = iwpool_create(2 * strlen(jsonstr));
506   if (!pool) {
507     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
508   }
509   JBL jbl;
510   JBL_NODE node;
511   rc = jbn_from_json(jsonstr, &node, pool);
512   RCGO(rc, finish);
513   if (node->type == JBV_OBJECT) {
514     rc = jbl_create_empty_object(&jbl);
515     RCGO(rc, finish);
516   } else if (node->type == JBV_ARRAY) {
517     rc = jbl_create_empty_array(&jbl);
518     RCGO(rc, finish);
519   } else {
520     // TODO: Review
521     rc = JBL_ERROR_CREATION;
522     goto finish;
523   }
524   rc = jbl_fill_from_node(jbl, node);
525   if (!rc) {
526     *jblp = jbl;
527   }
528 
529 finish:
530   iwpool_destroy(pool);
531   return rc;
532 }
533 
_jbl_write_double(double num,jbl_json_printer pt,void * op)534 iwrc _jbl_write_double(double num, jbl_json_printer pt, void *op) {
535   size_t sz;
536   char buf[JBNUMBUF_SIZE];
537   jbi_ftoa(num, buf, &sz);
538   return pt(buf, -1, 0, 0, op);
539 }
540 
_jbl_write_int(int64_t num,jbl_json_printer pt,void * op)541 iwrc _jbl_write_int(int64_t num, jbl_json_printer pt, void *op) {
542   char buf[JBNUMBUF_SIZE];
543   int sz = iwitoa(num, buf, sizeof(buf));
544   return pt(buf, sz, 0, 0, op);
545 }
546 
_jbl_write_string(const char * str,int len,jbl_json_printer pt,void * op,jbl_print_flags_t pf)547 iwrc _jbl_write_string(const char *str, int len, jbl_json_printer pt, void *op, jbl_print_flags_t pf) {
548   iwrc rc = pt(0, 0, '"', 1, op);
549   RCRET(rc);
550   static const char *specials = "btnvfr";
551   const uint8_t *p = (const uint8_t*) str;
552 
553 #define PT(data_, size_, ch_, count_) do { \
554     rc = pt((const char*) (data_), size_, ch_, count_, op); \
555     RCRET(rc); \
556 } while (0)
557 
558   if (len < 0) {
559     len = (int) strlen(str);
560   }
561   for (size_t i = 0; i < len; i++) {
562     uint8_t ch = p[i];
563     if ((ch == '"') || (ch == '\\')) {
564       PT(0, 0, '\\', 1);
565       PT(0, 0, ch, 1);
566     } else if ((ch >= '\b') && (ch <= '\r')) {
567       PT(0, 0, '\\', 1);
568       PT(0, 0, specials[ch - '\b'], 1);
569     } else if (isprint(ch)) {
570       PT(0, 0, ch, 1);
571     } else if (pf & JBL_PRINT_CODEPOINTS) {
572       char sbuf[7]; // escaped unicode seq
573       utf8proc_int32_t cp;
574       utf8proc_ssize_t sz = utf8proc_iterate(p + i, len - i, &cp);
575       if (sz < 0) {
576         return JBL_ERROR_PARSE_INVALID_UTF8;
577       }
578       if (cp > 0x0010000UL) {
579         uint32_t hs = 0xD800, ls = 0xDC00; // surrogates
580         cp -= 0x0010000UL;
581         hs |= ((cp >> 10) & 0x3FF);
582         ls |= (cp & 0x3FF);
583         snprintf(sbuf, 7, "\\u%04X", hs);
584         PT(sbuf, 6, 0, 0);
585         snprintf(sbuf, 7, "\\u%04X", ls);
586         PT(sbuf, 6, 0, 0);
587       } else {
588         snprintf(sbuf, 7, "\\u%04X", cp);
589         PT(sbuf, 6, 0, 0);
590       }
591       i += sz - 1;
592     } else {
593       PT(0, 0, ch, 1);
594     }
595   }
596   rc = pt(0, 0, '"', 1, op);
597   return rc;
598 #undef PT
599 }
600 
_jbl_as_json(binn * bn,jbl_json_printer pt,void * op,int lvl,jbl_print_flags_t pf)601 static iwrc _jbl_as_json(binn *bn, jbl_json_printer pt, void *op, int lvl, jbl_print_flags_t pf) {
602   iwrc rc = 0;
603   binn bv;
604   binn_iter iter;
605   int lv;
606   int64_t llv;
607   double dv;
608   char key[MAX_BIN_KEY_LEN + 1];
609   bool pretty = pf & JBL_PRINT_PRETTY;
610 
611 #define PT(data_, size_, ch_, count_) do { \
612     rc = pt(data_, size_, ch_, count_, op); \
613     RCGO(rc, finish); \
614 } while (0)
615 
616   switch (bn->type) {
617 
618     case BINN_LIST:
619       if (!binn_iter_init(&iter, bn, bn->type)) {
620         rc = JBL_ERROR_INVALID;
621         goto finish;
622       }
623       PT(0, 0, '[', 1);
624       if (bn->count && pretty) {
625         PT(0, 0, '\n', 1);
626       }
627       for (int i = 0; binn_list_next(&iter, &bv); ++i) {
628         if (pretty) {
629           PT(0, 0, ' ', lvl + 1);
630         }
631         rc = _jbl_as_json(&bv, pt, op, lvl + 1, pf);
632         RCGO(rc, finish);
633         if (i < bn->count - 1) {
634           PT(0, 0, ',', 1);
635         }
636         if (pretty) {
637           PT(0, 0, '\n', 1);
638         }
639       }
640       if (bn->count && pretty) {
641         PT(0, 0, ' ', lvl);
642       }
643       PT(0, 0, ']', 1);
644       break;
645 
646     case BINN_OBJECT:
647     case BINN_MAP:
648       if (!binn_iter_init(&iter, bn, bn->type)) {
649         rc = JBL_ERROR_INVALID;
650         goto finish;
651       }
652       PT(0, 0, '{', 1);
653       if (bn->count && pretty) {
654         PT(0, 0, '\n', 1);
655       }
656       if (bn->type == BINN_OBJECT) {
657         for (int i = 0; binn_object_next(&iter, key, &bv); ++i) {
658           if (pretty) {
659             PT(0, 0, ' ', lvl + 1);
660           }
661           rc = _jbl_write_string(key, -1, pt, op, pf);
662           RCGO(rc, finish);
663           if (pretty) {
664             PT(": ", -1, 0, 0);
665           } else {
666             PT(0, 0, ':', 1);
667           }
668           rc = _jbl_as_json(&bv, pt, op, lvl + 1, pf);
669           RCGO(rc, finish);
670           if (i < bn->count - 1) {
671             PT(0, 0, ',', 1);
672           }
673           if (pretty) {
674             PT(0, 0, '\n', 1);
675           }
676         }
677       } else {
678         for (int i = 0; binn_map_next(&iter, &lv, &bv); ++i) {
679           if (pretty) {
680             PT(0, 0, ' ', lvl + 1);
681           }
682           PT(0, 0, '"', 1);
683           rc = _jbl_write_int(lv, pt, op);
684           RCGO(rc, finish);
685           PT(0, 0, '"', 1);
686           if (pretty) {
687             PT(": ", -1, 0, 0);
688           } else {
689             PT(0, 0, ':', 1);
690           }
691           rc = _jbl_as_json(&bv, pt, op, lvl + 1, pf);
692           RCGO(rc, finish);
693           if (i < bn->count - 1) {
694             PT(0, 0, ',', 1);
695           }
696           if (pretty) {
697             PT(0, 0, '\n', 1);
698           }
699         }
700       }
701       if (bn->count && pretty) {
702         PT(0, 0, ' ', lvl);
703       }
704       PT(0, 0, '}', 1);
705       break;
706 
707     case BINN_STRING:
708       rc = _jbl_write_string(bn->ptr, -1, pt, op, pf);
709       break;
710     case BINN_UINT8:
711       llv = bn->vuint8;
712       goto loc_int;
713     case BINN_UINT16:
714       llv = bn->vuint16;
715       goto loc_int;
716     case BINN_UINT32:
717       llv = bn->vuint32;
718       goto loc_int;
719     case BINN_INT8:
720       llv = bn->vint8; // NOLINT(bugprone-signed-char-misuse)
721       goto loc_int;
722     case BINN_INT16:
723       llv = bn->vint16;
724       goto loc_int;
725     case BINN_INT32:
726       llv = bn->vint32;
727       goto loc_int;
728     case BINN_INT64:
729       llv = bn->vint64;
730       goto loc_int;
731     case BINN_UINT64: // overflow?
732       llv = (int64_t) bn->vuint64;
733 loc_int:
734       rc = _jbl_write_int(llv, pt, op);
735       break;
736 
737     case BINN_FLOAT32:
738       dv = bn->vfloat;
739       goto loc_float;
740     case BINN_FLOAT64:
741       dv = bn->vdouble;
742 loc_float:
743       rc = _jbl_write_double(dv, pt, op);
744       break;
745 
746     case BINN_TRUE:
747       PT("true", 4, 0, 0);
748       break;
749     case BINN_FALSE:
750       PT("false", 5, 0, 0);
751       break;
752     case BINN_BOOL:
753       PT(bn->vbool ? "true" : "false", -1, 0, 1);
754       break;
755     case BINN_NULL:
756       PT("null", 4, 0, 0);
757       break;
758     default:
759       iwlog_ecode_error3(IW_ERROR_ASSERTION);
760       rc = IW_ERROR_ASSERTION;
761       break;
762   }
763 
764 finish:
765   return rc;
766 #undef PT
767 }
768 
jbl_as_json(JBL jbl,jbl_json_printer pt,void * op,jbl_print_flags_t pf)769 iwrc jbl_as_json(JBL jbl, jbl_json_printer pt, void *op, jbl_print_flags_t pf) {
770   if (!jbl || !pt) {
771     return IW_ERROR_INVALID_ARGS;
772   }
773   return _jbl_as_json(&jbl->bn, pt, op, 0, pf);
774 }
775 
jbl_fstream_json_printer(const char * data,int size,char ch,int count,void * op)776 iwrc jbl_fstream_json_printer(const char *data, int size, char ch, int count, void *op) {
777   FILE *file = op;
778   if (!file) {
779     return IW_ERROR_INVALID_ARGS;
780   }
781   if (!data) {
782     if (count) {
783       char cbuf[count]; // TODO: review overflow
784       memset(cbuf, ch, sizeof(cbuf));
785       size_t wc = fwrite(cbuf, 1, count, file);
786       if (wc != sizeof(cbuf)) {
787         return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
788       }
789     }
790   } else {
791     if (size < 0) {
792       size = (int) strlen(data);
793     }
794     if (!count) {
795       count = 1;
796     }
797     for (int i = 0; i < count; ++i) {
798       if (fprintf(file, "%.*s", size, data) < 0) {
799         return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
800       }
801     }
802   }
803   return 0;
804 }
805 
jbl_xstr_json_printer(const char * data,int size,char ch,int count,void * op)806 iwrc jbl_xstr_json_printer(const char *data, int size, char ch, int count, void *op) {
807   IWXSTR *xstr = op;
808   if (!xstr) {
809     return IW_ERROR_INVALID_ARGS;
810   }
811   if (!data) {
812     if (count) {
813       for (int i = 0; i < count; ++i) {
814         iwrc rc = iwxstr_cat(xstr, &ch, 1);
815         RCRET(rc);
816       }
817     }
818   } else {
819     if (size < 0) {
820       size = (int) strlen(data);
821     }
822     if (!count) {
823       count = 1;
824     }
825     for (int i = 0; i < count; ++i) {
826       iwrc rc = iwxstr_cat(xstr, data, size);
827       RCRET(rc);
828     }
829   }
830   return 0;
831 }
832 
jbl_count_json_printer(const char * data,int size,char ch,int count,void * op)833 iwrc jbl_count_json_printer(const char *data, int size, char ch, int count, void *op) {
834   int *cnt = op;
835   if (!data) {
836     *cnt = *cnt + count;
837   } else {
838     if (size < 0) {
839       size = (int) strlen(data);
840     }
841     if (!count) {
842       count = 1;
843     }
844     *cnt = *cnt + count * size;
845   }
846   return 0;
847 }
848 
jbl_get_i64(JBL jbl)849 int64_t jbl_get_i64(JBL jbl) {
850   assert(jbl);
851   switch (jbl->bn.type) {
852     case BINN_UINT8:
853       return jbl->bn.vuint8;
854     case BINN_UINT16:
855       return jbl->bn.vuint16;
856     case BINN_UINT32:
857       return jbl->bn.vuint32;
858     case BINN_UINT64:
859       return jbl->bn.vuint64;
860     case BINN_INT8:
861       return jbl->bn.vint8;
862     case BINN_INT16:
863       return jbl->bn.vint16;
864     case BINN_INT32:
865       return jbl->bn.vint32;
866     case BINN_INT64:
867       return jbl->bn.vint64;
868     case BINN_BOOL:
869       return jbl->bn.vbool;
870     case BINN_FLOAT32:
871       return (int64_t) jbl->bn.vfloat;
872     case BINN_FLOAT64:
873       return (int64_t) jbl->bn.vdouble;
874     default:
875       return 0;
876   }
877 }
878 
jbl_get_i32(JBL jbl)879 int32_t jbl_get_i32(JBL jbl) {
880   return (int32_t) jbl_get_i64(jbl);
881 }
882 
jbl_get_f64(JBL jbl)883 double jbl_get_f64(JBL jbl) {
884   assert(jbl);
885   switch (jbl->bn.type) {
886     case BINN_FLOAT64:
887       return jbl->bn.vdouble;
888     case BINN_FLOAT32:
889       return jbl->bn.vfloat;
890     case BINN_UINT8:
891       return jbl->bn.vuint8;
892     case BINN_UINT16:
893       return jbl->bn.vuint16;
894     case BINN_UINT32:
895       return jbl->bn.vuint32;
896     case BINN_UINT64:
897       return jbl->bn.vuint64;
898     case BINN_INT8:
899       return jbl->bn.vint8;
900     case BINN_INT16:
901       return jbl->bn.vint16;
902     case BINN_INT32:
903       return jbl->bn.vint32;
904     case BINN_INT64:
905       return jbl->bn.vint64;
906     case BINN_BOOL:
907       return jbl->bn.vbool;
908     default:
909       return 0.0;
910   }
911 }
912 
jbl_get_str(JBL jbl)913 const char *jbl_get_str(JBL jbl) {
914   assert(jbl && jbl->bn.type == BINN_STRING);
915   if (jbl->bn.type != BINN_STRING) {
916     return 0;
917   } else {
918     return jbl->bn.ptr;
919   }
920 }
921 
jbl_copy_strn(JBL jbl,char * buf,size_t bufsz)922 size_t jbl_copy_strn(JBL jbl, char *buf, size_t bufsz) {
923   assert(jbl && buf && jbl->bn.type == BINN_STRING);
924   if (jbl->bn.type != BINN_STRING) {
925     return 0;
926   }
927   size_t slen = strlen(jbl->bn.ptr);
928   size_t ret = MIN(slen, bufsz);
929   memcpy(buf, jbl->bn.ptr, ret);
930   return ret;
931 }
932 
jbl_object_get_type(JBL jbl,const char * key)933 jbl_type_t jbl_object_get_type(JBL jbl, const char *key) {
934   if (jbl->bn.type != BINN_OBJECT) {
935     return JBV_NONE;
936   }
937   binn bv;
938   if (!binn_object_get_value(&jbl->bn, key, &bv)) {
939     return JBV_NONE;
940   }
941   return _jbl_binn_type(bv.type);
942 }
943 
jbl_object_get_i64(JBL jbl,const char * key,int64_t * out)944 iwrc jbl_object_get_i64(JBL jbl, const char *key, int64_t *out) {
945   *out = 0;
946   if (jbl->bn.type != BINN_OBJECT) {
947     return JBL_ERROR_NOT_AN_OBJECT;
948   }
949   int64 v;
950   if (!binn_object_get_int64(&jbl->bn, key, &v)) {
951     return JBL_ERROR_CREATION;
952   }
953   *out = v;
954   return 0;
955 }
956 
jbl_object_get_f64(JBL jbl,const char * key,double * out)957 iwrc jbl_object_get_f64(JBL jbl, const char *key, double *out) {
958   *out = 0.0;
959   if (jbl->bn.type != BINN_OBJECT) {
960     return JBL_ERROR_NOT_AN_OBJECT;
961   }
962   if (!binn_object_get_double(&jbl->bn, key, out)) {
963     return JBL_ERROR_CREATION;
964   }
965   return 0;
966 }
967 
jbl_object_get_bool(JBL jbl,const char * key,bool * out)968 iwrc jbl_object_get_bool(JBL jbl, const char *key, bool *out) {
969   *out = false;
970   if (jbl->bn.type != BINN_OBJECT) {
971     return JBL_ERROR_NOT_AN_OBJECT;
972   }
973   BOOL v;
974   if (!binn_object_get_bool(&jbl->bn, key, &v)) {
975     return JBL_ERROR_CREATION;
976   }
977   *out = v;
978   return 0;
979 }
980 
jbl_object_get_str(JBL jbl,const char * key,const char ** out)981 iwrc jbl_object_get_str(JBL jbl, const char *key, const char **out) {
982   *out = 0;
983   if (jbl->bn.type != BINN_OBJECT) {
984     return JBL_ERROR_NOT_AN_OBJECT;
985   }
986   if (!binn_object_get_str(&jbl->bn, key, (char**) out)) {
987     return JBL_ERROR_CREATION;
988   }
989   return 0;
990 }
991 
jbl_object_get_fill_jbl(JBL jbl,const char * key,JBL out)992 iwrc jbl_object_get_fill_jbl(JBL jbl, const char *key, JBL out) {
993   if (jbl->bn.type != BINN_OBJECT) {
994     return JBL_ERROR_NOT_AN_OBJECT;
995   }
996   binn_free(&out->bn);
997   if (!binn_object_get_value(&jbl->bn, key, &out->bn)) {
998     return JBL_ERROR_CREATION;
999   }
1000   return 0;
1001 }
1002 
jbl_as_buf(JBL jbl,void ** buf,size_t * size)1003 iwrc jbl_as_buf(JBL jbl, void **buf, size_t *size) {
1004   assert(jbl && buf && size);
1005   if (jbl->bn.writable && jbl->bn.dirty) {
1006     if (!binn_save_header(&jbl->bn)) {
1007       return JBL_ERROR_INVALID;
1008     }
1009   }
1010   *buf = jbl->bn.ptr;
1011   *size = (size_t) jbl->bn.size;
1012   return 0;
1013 }
1014 
1015 //----------------------------------------------------------------------------------------------------------
1016 
_jbl_ptr_pool(const char * path,JBL_PTR * jpp,IWPOOL * pool)1017 static iwrc _jbl_ptr_pool(const char *path, JBL_PTR *jpp, IWPOOL *pool) {
1018   iwrc rc = 0;
1019   int cnt = 0, len, sz, doff;
1020   int i, j, k;
1021   JBL_PTR jp;
1022   char *jpr; // raw pointer to jp
1023   *jpp = 0;
1024   if (!path || (path[0] != '/')) {
1025     return JBL_ERROR_JSON_POINTER;
1026   }
1027   for (i = 0; path[i]; ++i) {
1028     if (path[i] == '/') {
1029       ++cnt;
1030     }
1031   }
1032   len = i;
1033   if ((len > 1) && (path[len - 1] == '/')) {
1034     return JBL_ERROR_JSON_POINTER;
1035   }
1036   sz = (int) (sizeof(struct _JBL_PTR) + cnt * sizeof(char*) + len);
1037   if (pool) {
1038     jp = iwpool_alloc(sz, pool);
1039   } else {
1040     jp = malloc(sz);
1041   }
1042   if (!jp) {
1043     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1044   }
1045   jpr = (char*) jp;
1046   jp->cnt = cnt;
1047   jp->sz = sz;
1048 
1049   doff = offsetof(struct _JBL_PTR, n) + cnt * sizeof(char*);
1050   assert(sz - doff >= len);
1051 
1052   for (i = 0, j = 0, cnt = 0; path[i] && cnt < jp->cnt; ++i, ++j) {
1053     if (path[i++] == '/') {
1054       jp->n[cnt] = jpr + doff + j;
1055       for (k = 0; ; ++i, ++k) {
1056         if (!path[i] || (path[i] == '/')) {
1057           --i;
1058           *(jp->n[cnt] + k) = '\0';
1059           break;
1060         }
1061         if (path[i] == '~') {
1062           if (path[i + 1] == '0') {
1063             *(jp->n[cnt] + k) = '~';
1064           } else if (path[i + 1] == '1') {
1065             *(jp->n[cnt] + k) = '/';
1066           }
1067           ++i;
1068         } else {
1069           *(jp->n[cnt] + k) = path[i];
1070         }
1071       }
1072       j += k;
1073       ++cnt;
1074     }
1075   }
1076   *jpp = jp;
1077   return rc;
1078 }
1079 
jbl_ptr_alloc(const char * path,JBL_PTR * jpp)1080 iwrc jbl_ptr_alloc(const char *path, JBL_PTR *jpp) {
1081   return _jbl_ptr_pool(path, jpp, 0);
1082 }
1083 
jbl_ptr_alloc_pool(const char * path,JBL_PTR * jpp,IWPOOL * pool)1084 iwrc jbl_ptr_alloc_pool(const char *path, JBL_PTR *jpp, IWPOOL *pool) {
1085   return _jbl_ptr_pool(path, jpp, pool);
1086 }
1087 
jbl_ptr_cmp(JBL_PTR p1,JBL_PTR p2)1088 int jbl_ptr_cmp(JBL_PTR p1, JBL_PTR p2) {
1089   if (p1->sz != p2->sz) {
1090     return p1->sz - p2->sz;
1091   }
1092   if (p1->cnt != p2->cnt) {
1093     return p1->cnt - p2->cnt;
1094   }
1095   for (int i = 0; i < p1->cnt; ++i) {
1096     int r = strcmp(p1->n[i], p2->n[i]);
1097     if (r) {
1098       return r;
1099     }
1100   }
1101   return 0;
1102 }
1103 
jbl_ptr_serialize(JBL_PTR ptr,IWXSTR * xstr)1104 iwrc jbl_ptr_serialize(JBL_PTR ptr, IWXSTR *xstr) {
1105   for (int i = 0; i < ptr->cnt; ++i) {
1106     iwrc rc = iwxstr_cat(xstr, "/", 1);
1107     RCRET(rc);
1108     rc = iwxstr_cat(xstr, ptr->n[i], strlen(ptr->n[i]));
1109     RCRET(rc);
1110   }
1111   return 0;
1112 }
1113 
_jbl_visit(binn_iter * iter,int lvl,JBL_VCTX * vctx,JBL_VISITOR visitor)1114 iwrc _jbl_visit(binn_iter *iter, int lvl, JBL_VCTX *vctx, JBL_VISITOR visitor) {
1115   iwrc rc = 0;
1116   binn *bn = vctx->bn;
1117   jbl_visitor_cmd_t cmd;
1118   int idx;
1119   binn bv;
1120 
1121   if (lvl > JBL_MAX_NESTING_LEVEL) {
1122     return JBL_ERROR_MAX_NESTING_LEVEL_EXCEEDED;
1123   }
1124   if (!iter) {
1125     binn_iter it;
1126     if (!BINN_IS_CONTAINER_TYPE(bn->type)) {
1127       return JBL_ERROR_INVALID;
1128     }
1129     if (!binn_iter_init(&it, bn, bn->type)) {
1130       return JBL_ERROR_INVALID;
1131     }
1132     rc = _jbl_visit(&it, 0, vctx, visitor);
1133     return rc;
1134   }
1135 
1136   switch (iter->type) {
1137     case BINN_OBJECT: {
1138       char key[MAX_BIN_KEY_LEN + 1];
1139       while (!vctx->terminate && binn_object_next(iter, key, &bv)) {
1140         cmd = visitor(lvl, &bv, key, -1, vctx, &rc);
1141         RCRET(rc);
1142         if (cmd & JBL_VCMD_TERMINATE) {
1143           vctx->terminate = true;
1144           break;
1145         }
1146         if (!(cmd & JBL_VCMD_SKIP_NESTED) && BINN_IS_CONTAINER_TYPE(bv.type)) {
1147           binn_iter it;
1148           if (!binn_iter_init(&it, &bv, bv.type)) {
1149             return JBL_ERROR_INVALID;
1150           }
1151           rc = _jbl_visit(&it, lvl + 1, vctx, visitor);
1152           RCRET(rc);
1153         }
1154       }
1155       break;
1156     }
1157     case BINN_MAP: {
1158       while (!vctx->terminate && binn_map_next(iter, &idx, &bv)) {
1159         cmd = visitor(lvl, &bv, 0, idx, vctx, &rc);
1160         RCRET(rc);
1161         if (cmd & JBL_VCMD_TERMINATE) {
1162           vctx->terminate = true;
1163           break;
1164         }
1165         if (!(cmd & JBL_VCMD_SKIP_NESTED) && BINN_IS_CONTAINER_TYPE(bv.type)) {
1166           binn_iter it;
1167           if (!binn_iter_init(&it, &bv, bv.type)) {
1168             return JBL_ERROR_INVALID;
1169           }
1170           rc = _jbl_visit(&it, lvl + 1, vctx, visitor);
1171           RCRET(rc);
1172         }
1173       }
1174       break;
1175     }
1176     case BINN_LIST: {
1177       for (idx = 0; !vctx->terminate && binn_list_next(iter, &bv); ++idx) {
1178         cmd = visitor(lvl, &bv, 0, idx, vctx, &rc);
1179         RCRET(rc);
1180         if (cmd & JBL_VCMD_TERMINATE) {
1181           vctx->terminate = true;
1182           break;
1183         }
1184         if (!(cmd & JBL_VCMD_SKIP_NESTED) && BINN_IS_CONTAINER_TYPE(bv.type)) {
1185           binn_iter it;
1186           if (!binn_iter_init(&it, &bv, bv.type)) {
1187             return JBL_ERROR_INVALID;
1188           }
1189           rc = _jbl_visit(&it, lvl + 1, vctx, visitor);
1190           RCRET(rc);
1191         }
1192       }
1193       break;
1194     }
1195   }
1196   return rc;
1197 }
1198 
jbn_visit(JBL_NODE node,int lvl,JBN_VCTX * vctx,JBN_VISITOR visitor)1199 iwrc jbn_visit(JBL_NODE node, int lvl, JBN_VCTX *vctx, JBN_VISITOR visitor) {
1200   iwrc rc = 0;
1201   if (lvl > JBL_MAX_NESTING_LEVEL) {
1202     return JBL_ERROR_MAX_NESTING_LEVEL_EXCEEDED;
1203   }
1204   if (!node) {
1205     node = vctx->root;
1206     lvl = 0;
1207     if (!node) {
1208       return IW_ERROR_INVALID_ARGS;
1209     }
1210   }
1211   JBL_NODE n = node;
1212   switch (node->type) {
1213     case JBV_OBJECT:
1214     case JBV_ARRAY: {
1215       for (n = n->child; !vctx->terminate && n; n = n->next) {
1216         jbn_visitor_cmd_t cmd = visitor(lvl, n, n->key, n->klidx, vctx, &rc);
1217         RCRET(rc);
1218         if (cmd & JBL_VCMD_TERMINATE) {
1219           vctx->terminate = true;
1220         }
1221         if (cmd & JBN_VCMD_DELETE) {
1222           JBL_NODE nn = n->next; // Keep pointer to next
1223           _jbn_remove_item(node, n);
1224           n->next = nn;
1225         } else if (!(cmd & JBL_VCMD_SKIP_NESTED) && (n->type >= JBV_OBJECT)) {
1226           rc = jbn_visit(n, lvl + 1, vctx, visitor);
1227           RCRET(rc);
1228         }
1229       }
1230       break;
1231     }
1232     default:
1233       break;
1234   }
1235   RCRET(rc);
1236   if (lvl == 0) {
1237     visitor(-1, node, 0, 0, vctx, &rc);
1238   }
1239   return rc;
1240 }
1241 
_jbl_visitor_update_jptr_cursor(JBL_VCTX * vctx,int lvl,const char * key,int idx)1242 IW_INLINE bool _jbl_visitor_update_jptr_cursor(JBL_VCTX *vctx, int lvl, const char *key, int idx) {
1243   JBL_PTR jp = vctx->op;
1244   if (lvl < jp->cnt) {
1245     if (vctx->pos >= lvl) {
1246       vctx->pos = lvl - 1;
1247     }
1248     if (vctx->pos + 1 == lvl) {
1249       const char *keyptr;
1250       char buf[JBNUMBUF_SIZE];
1251       if (key) {
1252         keyptr = key;
1253       } else {
1254         iwitoa(idx, buf, JBNUMBUF_SIZE);
1255         keyptr = buf;
1256       }
1257       if (!strcmp(keyptr, jp->n[lvl]) || ((jp->n[lvl][0] == '*') && (jp->n[lvl][1] == '\0'))) {
1258         vctx->pos = lvl;
1259         return (jp->cnt == lvl + 1);
1260       }
1261     }
1262   }
1263   return false;
1264 }
1265 
_jbn_visitor_update_jptr_cursor(JBN_VCTX * vctx,int lvl,const char * key,int idx)1266 IW_INLINE bool _jbn_visitor_update_jptr_cursor(JBN_VCTX *vctx, int lvl, const char *key, int idx) {
1267   JBL_PTR jp = vctx->op;
1268   if (lvl < jp->cnt) {
1269     if (vctx->pos >= lvl) {
1270       vctx->pos = lvl - 1;
1271     }
1272     if (vctx->pos + 1 == lvl) {
1273       const char *keyptr;
1274       char buf[JBNUMBUF_SIZE];
1275       if (key) {
1276         keyptr = key;
1277       } else {
1278         iwitoa(idx, buf, JBNUMBUF_SIZE);
1279         keyptr = buf;
1280         idx = (int) strlen(keyptr);
1281       }
1282       int jplen = (int) strlen(jp->n[lvl]);
1283       if ((  (idx == jplen)
1284           && !strncmp(keyptr, jp->n[lvl], idx)) || ((jp->n[lvl][0] == '*') && (jp->n[lvl][1] == '\0') )) {
1285         vctx->pos = lvl;
1286         return (jp->cnt == lvl + 1);
1287       }
1288     }
1289   }
1290   return false;
1291 }
1292 
_jbl_get_visitor2(int lvl,binn * bv,const char * key,int idx,JBL_VCTX * vctx,iwrc * rc)1293 static jbl_visitor_cmd_t _jbl_get_visitor2(int lvl, binn *bv, const char *key, int idx, JBL_VCTX *vctx, iwrc *rc) {
1294   JBL_PTR jp = vctx->op;
1295   assert(jp);
1296   if (_jbl_visitor_update_jptr_cursor(vctx, lvl, key, idx)) { // Pointer matched
1297     JBL jbl = vctx->result;
1298     memcpy(&jbl->bn, bv, sizeof(*bv));
1299     vctx->found = true;
1300     return JBL_VCMD_TERMINATE;
1301   } else if (jp->cnt < lvl + 1) {
1302     return JBL_VCMD_SKIP_NESTED;
1303   }
1304   return JBL_VCMD_OK;
1305 }
1306 
_jbl_get_visitor(int lvl,binn * bv,const char * key,int idx,JBL_VCTX * vctx,iwrc * rc)1307 static jbl_visitor_cmd_t _jbl_get_visitor(int lvl, binn *bv, const char *key, int idx, JBL_VCTX *vctx, iwrc *rc) {
1308   JBL_PTR jp = vctx->op;
1309   assert(jp);
1310   if (_jbl_visitor_update_jptr_cursor(vctx, lvl, key, idx)) { // Pointer matched
1311     JBL jbl = malloc(sizeof(struct _JBL));
1312     if (!jbl) {
1313       *rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
1314       return JBL_VCMD_TERMINATE;
1315     }
1316     memcpy(&jbl->bn, bv, sizeof(*bv));
1317     vctx->result = jbl;
1318     return JBL_VCMD_TERMINATE;
1319   } else if (jp->cnt < lvl + 1) {
1320     return JBL_VCMD_SKIP_NESTED;
1321   }
1322   return JBL_VCMD_OK;
1323 }
1324 
_jbl_at(JBL jbl,JBL_PTR jp,JBL res)1325 bool _jbl_at(JBL jbl, JBL_PTR jp, JBL res) {
1326   JBL_VCTX vctx = {
1327     .bn     = &jbl->bn,
1328     .op     = jp,
1329     .pos    = -1,
1330     .result = res
1331   };
1332   _jbl_visit(0, 0, &vctx, _jbl_get_visitor2);
1333   return vctx.found;
1334 }
1335 
jbl_at2(JBL jbl,JBL_PTR jp,JBL * res)1336 iwrc jbl_at2(JBL jbl, JBL_PTR jp, JBL *res) {
1337   JBL_VCTX vctx = {
1338     .bn  = &jbl->bn,
1339     .op  = jp,
1340     .pos = -1
1341   };
1342   iwrc rc = _jbl_visit(0, 0, &vctx, _jbl_get_visitor);
1343   if (rc) {
1344     *res = 0;
1345   } else {
1346     if (!vctx.result) {
1347       rc = JBL_ERROR_PATH_NOTFOUND;
1348       *res = 0;
1349     } else {
1350       *res = (JBL) vctx.result;
1351     }
1352   }
1353   return rc;
1354 }
1355 
jbl_at(JBL jbl,const char * path,JBL * res)1356 iwrc jbl_at(JBL jbl, const char *path, JBL *res) {
1357   JBL_PTR jp;
1358   iwrc rc = _jbl_ptr_pool(path, &jp, 0);
1359   if (rc) {
1360     *res = 0;
1361     return rc;
1362   }
1363   rc = jbl_at2(jbl, jp, res);
1364   free(jp);
1365   return rc;
1366 }
1367 
_jbn_get_visitor(int lvl,JBL_NODE n,const char * key,int klidx,JBN_VCTX * vctx,iwrc * rc)1368 static jbn_visitor_cmd_t _jbn_get_visitor(int lvl, JBL_NODE n, const char *key, int klidx, JBN_VCTX *vctx, iwrc *rc) {
1369   if (lvl < 0) { // EOF
1370     return JBL_VCMD_OK;
1371   }
1372   JBL_PTR jp = vctx->op;
1373   assert(jp);
1374   if (_jbn_visitor_update_jptr_cursor(vctx, lvl, key, klidx)) { // Pointer matched
1375     vctx->result = n;
1376     return JBL_VCMD_TERMINATE;
1377   } else if (jp->cnt < lvl + 1) {
1378     return JBL_VCMD_SKIP_NESTED;
1379   }
1380   return JBL_VCMD_OK;
1381 }
1382 
jbn_at2(JBL_NODE node,JBL_PTR jp,JBL_NODE * res)1383 iwrc jbn_at2(JBL_NODE node, JBL_PTR jp, JBL_NODE *res) {
1384   JBN_VCTX vctx = {
1385     .root = node,
1386     .op   = jp,
1387     .pos  = -1
1388   };
1389   iwrc rc = jbn_visit(node, 0, &vctx, _jbn_get_visitor);
1390   if (rc) {
1391     *res = 0;
1392   } else {
1393     if (!vctx.result) {
1394       rc = JBL_ERROR_PATH_NOTFOUND;
1395       *res = 0;
1396     } else {
1397       *res = (JBL_NODE) vctx.result;
1398     }
1399   }
1400   return rc;
1401 }
1402 
jbn_at(JBL_NODE node,const char * path,JBL_NODE * res)1403 iwrc jbn_at(JBL_NODE node, const char *path, JBL_NODE *res) {
1404   JBL_PTR jp;
1405   iwrc rc = _jbl_ptr_pool(path, &jp, 0);
1406   if (rc) {
1407     *res = 0;
1408     return rc;
1409   }
1410   rc = jbn_at2(node, jp, res);
1411   free(jp);
1412   return rc;
1413 }
1414 
jbn_paths_compare(JBL_NODE n1,const char * n1path,JBL_NODE n2,const char * n2path,jbl_type_t vtype,iwrc * rcp)1415 int jbn_paths_compare(JBL_NODE n1, const char *n1path, JBL_NODE n2, const char *n2path, jbl_type_t vtype, iwrc *rcp) {
1416   *rcp = 0;
1417   JBL_NODE v1 = 0, v2 = 0;
1418   iwrc rc = jbn_at(n1, n1path, &v1);
1419   if (rc && (rc != JBL_ERROR_PATH_NOTFOUND)) {
1420     *rcp = rc;
1421     return -2;
1422   }
1423   rc = jbn_at(n2, n2path, &v2);
1424   if (rc && (rc != JBL_ERROR_PATH_NOTFOUND)) {
1425     *rcp = rc;
1426     return -2;
1427   }
1428   if (vtype) {
1429     if (((v1 == 0) || (v1->type != vtype)) || ((v2 == 0) || (v2->type != vtype))) {
1430       *rcp = JBL_ERROR_TYPE_MISMATCHED;
1431       return -2;
1432     }
1433   }
1434   return _jbl_compare_nodes(v1, v2, rcp);
1435 }
1436 
jbn_path_compare(JBL_NODE n1,JBL_NODE n2,const char * path,jbl_type_t vtype,iwrc * rcp)1437 int jbn_path_compare(JBL_NODE n1, JBL_NODE n2, const char *path, jbl_type_t vtype, iwrc *rcp) {
1438   return jbn_paths_compare(n1, path, n2, path, vtype, rcp);
1439 }
1440 
jbn_path_compare_str(JBL_NODE n,const char * path,const char * sv,iwrc * rcp)1441 int jbn_path_compare_str(JBL_NODE n, const char *path, const char *sv, iwrc *rcp) {
1442   *rcp = 0;
1443   JBL_NODE v;
1444   iwrc rc = jbn_at(n, path, &v);
1445   if (rc) {
1446     *rcp = rc;
1447     return -2;
1448   }
1449   struct _JBL_NODE cn = {
1450     .type  = JBV_STR,
1451     .vptr  = sv,
1452     .vsize = (int) strlen(sv)
1453   };
1454   return _jbl_compare_nodes(v, &cn, rcp);
1455 }
1456 
jbn_path_compare_i64(JBL_NODE n,const char * path,int64_t iv,iwrc * rcp)1457 int jbn_path_compare_i64(JBL_NODE n, const char *path, int64_t iv, iwrc *rcp) {
1458   *rcp = 0;
1459   JBL_NODE v;
1460   iwrc rc = jbn_at(n, path, &v);
1461   if (rc) {
1462     *rcp = rc;
1463     return -2;
1464   }
1465   struct _JBL_NODE cn = {
1466     .type = JBV_I64,
1467     .vi64 = iv
1468   };
1469   return _jbl_compare_nodes(v, &cn, rcp);
1470 }
1471 
jbn_path_compare_f64(JBL_NODE n,const char * path,double fv,iwrc * rcp)1472 int jbn_path_compare_f64(JBL_NODE n, const char *path, double fv, iwrc *rcp) {
1473   *rcp = 0;
1474   JBL_NODE v;
1475   iwrc rc = jbn_at(n, path, &v);
1476   if (rc) {
1477     *rcp = rc;
1478     return -2;
1479   }
1480   struct _JBL_NODE cn = {
1481     .type = JBV_F64,
1482     .vf64 = fv
1483   };
1484   return _jbl_compare_nodes(v, &cn, rcp);
1485 }
1486 
jbn_path_compare_bool(JBL_NODE n,const char * path,bool bv,iwrc * rcp)1487 int jbn_path_compare_bool(JBL_NODE n, const char *path, bool bv, iwrc *rcp) {
1488   *rcp = 0;
1489   JBL_NODE v;
1490   iwrc rc = jbn_at(n, path, &v);
1491   if (rc) {
1492     *rcp = rc;
1493     return -2;
1494   }
1495   struct _JBL_NODE cn = {
1496     .type  = JBV_BOOL,
1497     .vbool = bv
1498   };
1499   return _jbl_compare_nodes(v, &cn, rcp);
1500 }
1501 
_jbl_node_reset_data(JBL_NODE target)1502 IW_INLINE void _jbl_node_reset_data(JBL_NODE target) {
1503   jbl_type_t t = target->type;
1504   memset(((uint8_t*) target) + offsetof(struct _JBL_NODE, child),
1505          0,
1506          sizeof(struct _JBL_NODE) - offsetof(struct _JBL_NODE, child));
1507   target->type = t;
1508 }
1509 
_jbl_copy_node_data(JBL_NODE target,JBL_NODE value)1510 IW_INLINE void _jbl_copy_node_data(JBL_NODE target, JBL_NODE value) {
1511   memcpy(((uint8_t*) target) + offsetof(struct _JBL_NODE, child),
1512          ((uint8_t*) value) + offsetof(struct _JBL_NODE, child),
1513          sizeof(struct _JBL_NODE) - offsetof(struct _JBL_NODE, child));
1514 }
1515 
_jbl_increment_node_data(JBL_NODE target,JBL_NODE value)1516 iwrc _jbl_increment_node_data(JBL_NODE target, JBL_NODE value) {
1517   if ((value->type != JBV_I64) && (value->type != JBV_F64)) {
1518     return JBL_ERROR_PATCH_INVALID_VALUE;
1519   }
1520   if (target->type == JBV_I64) {
1521     if (value->type == JBV_I64) {
1522       target->vi64 += value->vi64;
1523     } else {
1524       target->vi64 += (int64_t) value->vf64;
1525     }
1526     return 0;
1527   } else if (target->type == JBV_F64) {
1528     if (value->type == JBV_F64) {
1529       target->vf64 += value->vf64;
1530     } else {
1531       target->vf64 += (double) value->vi64;
1532     }
1533     return 0;
1534   } else {
1535     return JBL_ERROR_PATCH_TARGET_INVALID;
1536   }
1537 }
1538 
jbn_data(JBL_NODE node)1539 void jbn_data(JBL_NODE node) {
1540   _jbl_node_reset_data(node);
1541 }
1542 
jbn_length(JBL_NODE node)1543 int jbn_length(JBL_NODE node) {
1544   int ret = 0;
1545   for (JBL_NODE n = node->child; n; n = n->next) {
1546     ++ret;
1547   }
1548   return ret;
1549 }
1550 
_jbn_add_item(JBL_NODE parent,JBL_NODE node)1551 static void _jbn_add_item(JBL_NODE parent, JBL_NODE node) {
1552   assert(parent && node);
1553   node->next = 0;
1554   node->prev = 0;
1555   node->parent = parent;
1556   if (parent->child) {
1557     JBL_NODE prev = parent->child->prev;
1558     parent->child->prev = node;
1559     if (prev) { // -V1051
1560       prev->next = node;
1561       node->prev = prev;
1562     } else {
1563       parent->child->next = node;
1564       node->prev = parent->child;
1565     }
1566   } else {
1567     parent->child = node;
1568   }
1569   if (parent->type == JBV_ARRAY) {
1570     node->key = 0;
1571     if (node->prev) {
1572       node->klidx = node->prev->klidx + 1;
1573     } else {
1574       node->klidx = 0;
1575     }
1576   }
1577 }
1578 
jbn_add_item(JBL_NODE parent,JBL_NODE node)1579 void jbn_add_item(JBL_NODE parent, JBL_NODE node) {
1580   _jbn_add_item(parent, node);
1581 }
1582 
jbn_add_item_str(JBL_NODE parent,const char * key,const char * val,int vlen,JBL_NODE * node_out,IWPOOL * pool)1583 iwrc jbn_add_item_str(JBL_NODE parent, const char *key, const char *val, int vlen, JBL_NODE *node_out, IWPOOL *pool) {
1584   if (!parent || !pool || (parent->type < JBV_OBJECT)) {
1585     return IW_ERROR_INVALID_ARGS;
1586   }
1587   iwrc rc = 0;
1588   JBL_NODE n = iwpool_calloc(sizeof(*n), pool);
1589   if (!n) {
1590     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1591   }
1592   if (parent->type == JBV_OBJECT) {
1593     if (!key) {
1594       return IW_ERROR_INVALID_ARGS;
1595     }
1596     n->key = iwpool_strdup(pool, key, &rc);
1597     RCGO(rc, finish);
1598     n->klidx = (int) strlen(n->key);
1599   }
1600   n->type = JBV_STR;
1601   if (val) {
1602     if (vlen < 0) {
1603       vlen = (int) strlen(val);
1604     }
1605     n->vptr = iwpool_strndup(pool, val, vlen, &rc);
1606     RCGO(rc, finish);
1607     n->vsize = vlen;
1608   }
1609   jbn_add_item(parent, n);
1610   if (node_out) {
1611     *node_out = n;
1612   }
1613 finish:
1614   return rc;
1615 }
1616 
jbn_add_item_null(JBL_NODE parent,const char * key,IWPOOL * pool)1617 iwrc jbn_add_item_null(JBL_NODE parent, const char *key, IWPOOL *pool) {
1618   if (!parent || !pool || (parent->type < JBV_OBJECT)) {
1619     return IW_ERROR_INVALID_ARGS;
1620   }
1621   iwrc rc = 0;
1622   JBL_NODE n = iwpool_calloc(sizeof(*n), pool);
1623   if (!n) {
1624     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1625   }
1626   if (parent->type == JBV_OBJECT) {
1627     if (!key) {
1628       return IW_ERROR_INVALID_ARGS;
1629     }
1630     n->key = iwpool_strdup(pool, key, &rc);
1631     RCGO(rc, finish);
1632     n->klidx = (int) strlen(n->key);
1633   }
1634   n->type = JBV_NULL;
1635   jbn_add_item(parent, n);
1636 finish:
1637   return rc;
1638 }
1639 
jbn_add_item_i64(JBL_NODE parent,const char * key,int64_t val,JBL_NODE * node_out,IWPOOL * pool)1640 iwrc jbn_add_item_i64(JBL_NODE parent, const char *key, int64_t val, JBL_NODE *node_out, IWPOOL *pool) {
1641   if (!parent || !pool || (parent->type < JBV_OBJECT)) {
1642     return IW_ERROR_INVALID_ARGS;
1643   }
1644   iwrc rc = 0;
1645   JBL_NODE n = iwpool_calloc(sizeof(*n), pool);
1646   if (!n) {
1647     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1648   }
1649   if (parent->type == JBV_OBJECT) {
1650     if (!key) {
1651       return IW_ERROR_INVALID_ARGS;
1652     }
1653     n->key = iwpool_strdup(pool, key, &rc);
1654     RCGO(rc, finish);
1655     n->klidx = (int) strlen(n->key);
1656   }
1657   n->type = JBV_I64;
1658   n->vi64 = val;
1659   jbn_add_item(parent, n);
1660   if (node_out) {
1661     *node_out = n;
1662   }
1663 finish:
1664   return rc;
1665 }
1666 
jbn_add_item_f64(JBL_NODE parent,const char * key,double val,JBL_NODE * node_out,IWPOOL * pool)1667 iwrc jbn_add_item_f64(JBL_NODE parent, const char *key, double val, JBL_NODE *node_out, IWPOOL *pool) {
1668   if (!parent || !pool || (parent->type < JBV_OBJECT)) {
1669     return IW_ERROR_INVALID_ARGS;
1670   }
1671   iwrc rc = 0;
1672   JBL_NODE n = iwpool_calloc(sizeof(*n), pool);
1673   if (!n) {
1674     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1675   }
1676   if (parent->type == JBV_OBJECT) {
1677     if (!key) {
1678       return IW_ERROR_INVALID_ARGS;
1679     }
1680     n->key = iwpool_strdup(pool, key, &rc);
1681     RCGO(rc, finish);
1682     n->klidx = (int) strlen(n->key);
1683   }
1684   n->type = JBV_F64;
1685   n->vf64 = val;
1686   jbn_add_item(parent, n);
1687   if (node_out) {
1688     *node_out = n;
1689   }
1690 finish:
1691   return rc;
1692 }
1693 
jbn_add_item_bool(JBL_NODE parent,const char * key,bool val,JBL_NODE * node_out,IWPOOL * pool)1694 iwrc jbn_add_item_bool(JBL_NODE parent, const char *key, bool val, JBL_NODE *node_out, IWPOOL *pool) {
1695   if (!parent || !pool || (parent->type < JBV_OBJECT)) {
1696     return IW_ERROR_INVALID_ARGS;
1697   }
1698   iwrc rc = 0;
1699   JBL_NODE n = iwpool_calloc(sizeof(*n), pool);
1700   if (!n) {
1701     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1702   }
1703   if (parent->type == JBV_OBJECT) {
1704     if (!key) {
1705       return IW_ERROR_INVALID_ARGS;
1706     }
1707     n->key = iwpool_strdup(pool, key, &rc);
1708     RCGO(rc, finish);
1709     n->klidx = (int) strlen(n->key);
1710   }
1711   n->type = JBV_BOOL;
1712   n->vbool = val;
1713   jbn_add_item(parent, n);
1714 
1715 finish:
1716   return rc;
1717 }
1718 
jbn_add_item_obj(JBL_NODE parent,const char * key,JBL_NODE * out,IWPOOL * pool)1719 iwrc jbn_add_item_obj(JBL_NODE parent, const char *key, JBL_NODE *out, IWPOOL *pool) {
1720   if (!parent || !pool || (parent->type < JBV_OBJECT)) {
1721     return IW_ERROR_INVALID_ARGS;
1722   }
1723   iwrc rc = 0;
1724   JBL_NODE n = iwpool_calloc(sizeof(*n), pool);
1725   if (!n) {
1726     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1727   }
1728   if (parent->type == JBV_OBJECT) {
1729     if (!key) {
1730       return IW_ERROR_INVALID_ARGS;
1731     }
1732     n->key = iwpool_strdup(pool, key, &rc);
1733     RCGO(rc, finish);
1734     n->klidx = (int) strlen(n->key);
1735   }
1736   n->type = JBV_OBJECT;
1737   jbn_add_item(parent, n);
1738   if (out) {
1739     *out = n;
1740   }
1741 finish:
1742   return rc;
1743 }
1744 
jbn_add_item_arr(JBL_NODE parent,const char * key,JBL_NODE * out,IWPOOL * pool)1745 iwrc jbn_add_item_arr(JBL_NODE parent, const char *key, JBL_NODE *out, IWPOOL *pool) {
1746   if (!parent || !pool || (parent->type < JBV_OBJECT)) {
1747     return IW_ERROR_INVALID_ARGS;
1748   }
1749   iwrc rc = 0;
1750   JBL_NODE n = iwpool_calloc(sizeof(*n), pool);
1751   if (!n) {
1752     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1753   }
1754   if (parent->type == JBV_OBJECT) {
1755     if (!key) {
1756       return IW_ERROR_INVALID_ARGS;
1757     }
1758     n->key = iwpool_strdup(pool, key, &rc);
1759     RCGO(rc, finish);
1760     n->klidx = (int) strlen(n->key);
1761   }
1762   n->type = JBV_ARRAY;
1763   jbn_add_item(parent, n);
1764   if (out) {
1765     *out = n;
1766   }
1767 finish:
1768   return rc;
1769 }
1770 
jbn_copy_path(JBL_NODE src,const char * src_path,JBL_NODE target,const char * target_path,bool overwrite_on_nulls,bool no_src_clone,IWPOOL * pool)1771 iwrc jbn_copy_path(
1772   JBL_NODE    src,
1773   const char *src_path,
1774   JBL_NODE    target,
1775   const char *target_path,
1776   bool        overwrite_on_nulls,
1777   bool        no_src_clone,
1778   IWPOOL     *pool) {
1779   if (!src || !src_path || !target || !target_path || !pool) {
1780     return IW_ERROR_INVALID_ARGS;
1781   }
1782   iwrc rc = 0;
1783   JBL_NODE n1, n2;
1784   jbp_patch_t op = JBP_REPLACE;
1785 
1786   if (strcmp("/", src_path) != 0) { // -V526
1787     rc = jbn_at(src, src_path, &n1);
1788     if (rc == JBL_ERROR_PATH_NOTFOUND) {
1789       return 0;
1790     }
1791     RCRET(rc);
1792   } else {
1793     n1 = src;
1794   }
1795   if (!overwrite_on_nulls && (n1->type <= JBV_NULL)) {
1796     return 0;
1797   }
1798   if (no_src_clone) {
1799     n2 = n1;
1800   } else {
1801     rc = jbn_clone(n1, &n2, pool);
1802     RCRET(rc);
1803   }
1804 
1805   rc = jbn_at(target, target_path, &n1);
1806   if (rc == JBL_ERROR_PATH_NOTFOUND) {
1807     rc = 0;
1808     op = JBP_ADD_CREATE;
1809   }
1810   JBL_PATCH p[] = {
1811     {
1812       .op = op,
1813       .path = target_path,
1814       .vnode = n2
1815     }
1816   };
1817   return jbn_patch(target, p, sizeof(p) / sizeof(p[0]), pool);
1818 }
1819 
jbn_copy_paths(JBL_NODE src,JBL_NODE target,const char ** paths,bool overwrite_on_nulls,bool no_src_clone,IWPOOL * pool)1820 IW_EXPORT iwrc jbn_copy_paths(
1821   JBL_NODE     src,
1822   JBL_NODE     target,
1823   const char **paths,
1824   bool         overwrite_on_nulls,
1825   bool         no_src_clone,
1826   IWPOOL      *pool) {
1827   if (!target || !src || !paths || !pool) {
1828     return IW_ERROR_INVALID_ARGS;
1829   }
1830   iwrc rc = 0;
1831   for (const char **p = paths; *p; ++p) {
1832     const char *path = *p;
1833     rc = jbn_copy_path(src, path, target, path, overwrite_on_nulls, no_src_clone, pool);
1834     RCBREAK(rc);
1835   }
1836   return rc;
1837 }
1838 
_jbn_remove_item(JBL_NODE parent,JBL_NODE child)1839 IW_INLINE void _jbn_remove_item(JBL_NODE parent, JBL_NODE child) {
1840   assert(parent->child);
1841   if (parent->child == child) {                 // First element
1842     if (child->next) {
1843       parent->child = child->next;
1844       parent->child->prev = child->prev;
1845       if (child->prev) {
1846         child->prev->next = 0;
1847       }
1848     } else {
1849       parent->child = 0;
1850     }
1851   } else if (parent->child->prev == child) {    // Last element
1852     parent->child->prev = child->prev;
1853     if (child->prev) {
1854       child->prev->next = 0;
1855     }
1856   } else { // Somewhere in middle
1857     if (child->next) {
1858       child->next->prev = child->prev;
1859     }
1860     if (child->prev) {
1861       child->prev->next = child->next;
1862     }
1863   }
1864   child->next = 0;
1865   child->prev = 0;
1866   child->child = 0;
1867   child->parent = 0;
1868 }
1869 
jbn_remove_item(JBL_NODE parent,JBL_NODE child)1870 void jbn_remove_item(JBL_NODE parent, JBL_NODE child) {
1871   _jbn_remove_item(parent, child);
1872 }
1873 
_jbl_create_node(JBLDRCTX * ctx,const binn * bv,JBL_NODE parent,const char * key,int klidx,JBL_NODE * node,bool clone_strings)1874 static iwrc _jbl_create_node(
1875   JBLDRCTX   *ctx,
1876   const binn *bv,
1877   JBL_NODE    parent,
1878   const char *key,
1879   int         klidx,
1880   JBL_NODE   *node,
1881   bool        clone_strings) {
1882   iwrc rc = 0;
1883   JBL_NODE n = iwpool_alloc(sizeof(*n), ctx->pool);
1884   if (node) {
1885     *node = 0;
1886   }
1887   if (!n) {
1888     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
1889   }
1890   memset(n, 0, sizeof(*n));
1891   if (key && clone_strings) {
1892     n->key = iwpool_strndup(ctx->pool, key, klidx, &rc);
1893     RCGO(rc, finish);
1894   } else {
1895     n->key = key;
1896   }
1897   n->klidx = klidx;
1898   n->parent = parent;
1899   switch (bv->type) {
1900     case BINN_NULL:
1901       n->type = JBV_NULL;
1902       break;
1903     case BINN_STRING:
1904       n->type = JBV_STR;
1905       if (!clone_strings) {
1906         n->vptr = bv->ptr;
1907         n->vsize = bv->size;
1908       } else {
1909         n->vptr = iwpool_strndup(ctx->pool, bv->ptr, bv->size, &rc);
1910         n->vsize = bv->size;
1911         RCGO(rc, finish);
1912       }
1913       break;
1914     case BINN_OBJECT:
1915     case BINN_MAP:
1916       n->type = JBV_OBJECT;
1917       break;
1918     case BINN_LIST:
1919       n->type = JBV_ARRAY;
1920       break;
1921     case BINN_TRUE:
1922       n->type = JBV_BOOL;
1923       n->vbool = true;
1924       break;
1925     case BINN_FALSE:
1926       n->type = JBV_BOOL;
1927       n->vbool = false;
1928       break;
1929     case BINN_BOOL:
1930       n->type = JBV_BOOL;
1931       n->vbool = bv->vbool;
1932       break;
1933     case BINN_UINT8:
1934       n->vi64 = bv->vuint8;
1935       n->type = JBV_I64;
1936       break;
1937     case BINN_UINT16:
1938       n->vi64 = bv->vuint16;
1939       n->type = JBV_I64;
1940       break;
1941     case BINN_UINT32:
1942       n->vi64 = bv->vuint32;
1943       n->type = JBV_I64;
1944       break;
1945     case BINN_UINT64:
1946       n->vi64 = bv->vuint64;
1947       n->type = JBV_I64;
1948       break;
1949     case BINN_INT8:
1950       n->vi64 = bv->vint8; // NOLINT(bugprone-signed-char-misuse)
1951       n->type = JBV_I64;
1952       break;
1953     case BINN_INT16:
1954       n->vi64 = bv->vint16;
1955       n->type = JBV_I64;
1956       break;
1957     case BINN_INT32:
1958       n->vi64 = bv->vint32;
1959       n->type = JBV_I64;
1960       break;
1961     case BINN_INT64:
1962       n->vi64 = bv->vint64;
1963       n->type = JBV_I64;
1964       break;
1965     case BINN_FLOAT32:
1966     case BINN_FLOAT64:
1967       n->vf64 = bv->vdouble;
1968       n->type = JBV_F64;
1969       break;
1970     default:
1971       rc = JBL_ERROR_CREATION;
1972       goto finish;
1973   }
1974   if (parent) {
1975     _jbn_add_item(parent, n);
1976   }
1977 
1978 finish:
1979   if (rc) {
1980     free(n);
1981   } else {
1982     if (node) {
1983       *node = n;
1984     }
1985   }
1986   return rc;
1987 }
1988 
_jbl_node_from_binn_impl(JBLDRCTX * ctx,const binn * bn,JBL_NODE parent,char * key,int klidx,bool clone_strings)1989 static iwrc _jbl_node_from_binn_impl(
1990   JBLDRCTX   *ctx,
1991   const binn *bn,
1992   JBL_NODE    parent,
1993   char       *key,
1994   int         klidx,
1995   bool        clone_strings) {
1996   binn bv;
1997   binn_iter iter;
1998   iwrc rc = 0;
1999 
2000   switch (bn->type) {
2001     case BINN_OBJECT:
2002     case BINN_MAP:
2003       rc = _jbl_create_node(ctx, bn, parent, key, klidx, &parent, clone_strings);
2004       RCRET(rc);
2005       if (!ctx->root) {
2006         ctx->root = parent;
2007       }
2008       if (!binn_iter_init(&iter, (binn*) bn, bn->type)) {
2009         return JBL_ERROR_INVALID;
2010       }
2011       if (bn->type == BINN_OBJECT) {
2012         for (int i = 0; binn_object_next2(&iter, &key, &klidx, &bv); ++i) {
2013           rc = _jbl_node_from_binn_impl(ctx, &bv, parent, key, klidx, clone_strings);
2014           RCRET(rc);
2015         }
2016       } else if (bn->type == BINN_MAP) {
2017         for (int i = 0; binn_map_next(&iter, &klidx, &bv); ++i) {
2018           rc = _jbl_node_from_binn_impl(ctx, &bv, parent, 0, klidx, clone_strings);
2019           RCRET(rc);
2020         }
2021       }
2022       break;
2023     case BINN_LIST:
2024       rc = _jbl_create_node(ctx, bn, parent, key, klidx, &parent, clone_strings);
2025       RCRET(rc);
2026       if (!ctx->root) {
2027         ctx->root = parent;
2028       }
2029       if (!binn_iter_init(&iter, (binn*) bn, bn->type)) {
2030         return JBL_ERROR_INVALID;
2031       }
2032       for (int i = 0; binn_list_next(&iter, &bv); ++i) {
2033         rc = _jbl_node_from_binn_impl(ctx, &bv, parent, 0, i, clone_strings);
2034         RCRET(rc);
2035       }
2036       break;
2037     default: {
2038       rc = _jbl_create_node(ctx, bn, parent, key, klidx, 0, clone_strings);
2039       RCRET(rc);
2040       break;
2041     }
2042   }
2043   return rc;
2044 }
2045 
_jbl_node_from_binn(const binn * bn,JBL_NODE * node,bool clone_strings,IWPOOL * pool)2046 iwrc _jbl_node_from_binn(const binn *bn, JBL_NODE *node, bool clone_strings, IWPOOL *pool) {
2047   JBLDRCTX ctx = {
2048     .pool = pool
2049   };
2050   iwrc rc = _jbl_node_from_binn_impl(&ctx, bn, 0, 0, -1, clone_strings);
2051   if (rc) {
2052     *node = 0;
2053   } else {
2054     *node = ctx.root;
2055   }
2056   return rc;
2057 }
2058 
_jbl_node_find(JBL_NODE node,JBL_PTR ptr,int from,int to)2059 static JBL_NODE _jbl_node_find(JBL_NODE node, JBL_PTR ptr, int from, int to) {
2060   if (!ptr || !node) {
2061     return 0;
2062   }
2063   JBL_NODE n = node;
2064 
2065   for (int i = from; n && i < ptr->cnt && i < to; ++i) {
2066     if (n->type == JBV_OBJECT) {
2067       int ptrnlen = (int) strlen(ptr->n[i]);
2068       for (n = n->child; n; n = n->next) {
2069         if (!strncmp(n->key, ptr->n[i], n->klidx) && (ptrnlen == n->klidx)) {
2070           break;
2071         }
2072       }
2073     } else if (n->type == JBV_ARRAY) {
2074       int64_t idx = iwatoi(ptr->n[i]);
2075       for (n = n->child; n; n = n->next) {
2076         if (idx == n->klidx) {
2077           break;
2078         }
2079       }
2080     } else {
2081       return 0;
2082     }
2083   }
2084   return n;
2085 }
2086 
_jbl_node_find2(JBL_NODE node,JBL_PTR ptr)2087 IW_INLINE JBL_NODE _jbl_node_find2(JBL_NODE node, JBL_PTR ptr) {
2088   if (!node || !ptr || !ptr->cnt) {
2089     return 0;
2090   }
2091   return _jbl_node_find(node, ptr, 0, ptr->cnt - 1);
2092 }
2093 
_jbl_node_detach(JBL_NODE target,JBL_PTR path)2094 static JBL_NODE _jbl_node_detach(JBL_NODE target, JBL_PTR path) {
2095   if (!path) {
2096     return 0;
2097   }
2098   JBL_NODE parent = (path->cnt > 1) ? _jbl_node_find(target, path, 0, path->cnt - 1) : target;
2099   if (!parent) {
2100     return 0;
2101   }
2102   JBL_NODE child = _jbl_node_find(parent, path, path->cnt - 1, path->cnt);
2103   if (!child) {
2104     return 0;
2105   }
2106   _jbn_remove_item(parent, child);
2107   return child;
2108 }
2109 
jbn_detach2(JBL_NODE target,JBL_PTR path)2110 JBL_NODE jbn_detach2(JBL_NODE target, JBL_PTR path) {
2111   return _jbl_node_detach(target, path);
2112 }
2113 
jbn_detach(JBL_NODE target,const char * path)2114 JBL_NODE jbn_detach(JBL_NODE target, const char *path) {
2115   JBL_PTR jp;
2116   iwrc rc = _jbl_ptr_pool(path, &jp, 0);
2117   if (rc) {
2118     return 0;
2119   }
2120   JBL_NODE res = jbn_detach2(target, jp);
2121   free(jp);
2122   return res;
2123 }
2124 
_jbl_cmp_node_keys(const void * o1,const void * o2)2125 static int _jbl_cmp_node_keys(const void *o1, const void *o2) {
2126   JBL_NODE n1 = *((JBL_NODE*) o1);
2127   JBL_NODE n2 = *((JBL_NODE*) o2);
2128   if (!n1 && !n2) {
2129     return 0;
2130   }
2131   if (!n2 || (n1->klidx > n2->klidx)) { // -V522
2132     return 1;
2133   } else if (!n1 || (n1->klidx < n2->klidx)) { // -V522
2134     return -1;
2135   }
2136   return strncmp(n1->key, n2->key, n1->klidx);
2137 }
2138 
_jbl_node_count(JBL_NODE n)2139 static uint32_t _jbl_node_count(JBL_NODE n) {
2140   uint32_t ret = 0;
2141   n = n->child;
2142   while (n) {
2143     ret++;
2144     n = n->next;
2145   }
2146   return ret;
2147 }
2148 
_jbl_compare_objects(JBL_NODE n1,JBL_NODE n2,iwrc * rcp)2149 static int _jbl_compare_objects(JBL_NODE n1, JBL_NODE n2, iwrc *rcp) {
2150   int ret = 0;
2151   uint32_t cnt = _jbl_node_count(n1);
2152   uint32_t i = _jbl_node_count(n2);
2153   if (cnt > i) {
2154     return 1;
2155   } else if (cnt < i) {
2156     return -1;
2157   } else if (cnt == 0) {
2158     return 0;
2159   }
2160   JBL_NODE *s1 = malloc(2 * sizeof(JBL_NODE) * cnt);
2161   if (!s1) {
2162     *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
2163     return 0;
2164   }
2165   JBL_NODE *s2 = s1 + cnt;
2166 
2167   i = 0;
2168   n1 = n1->child;
2169   n2 = n2->child;
2170   while (n1 && n2) {
2171     s1[i] = n1;
2172     s2[i] = n2;
2173     n1 = n1->next;
2174     n2 = n2->next;
2175     ++i;
2176   }
2177   qsort(s1, cnt, sizeof(JBL_NODE), _jbl_cmp_node_keys);
2178   qsort(s2, cnt, sizeof(JBL_NODE), _jbl_cmp_node_keys);
2179   for (i = 0; i < cnt; ++i) {
2180     ret = _jbl_cmp_node_keys(s1 + i, s2 + i);
2181     if (ret) {
2182       goto finish;
2183     }
2184     ret = _jbl_compare_nodes(s1[i], s2[i], rcp);
2185     if (*rcp || ret) {
2186       goto finish;
2187     }
2188   }
2189 
2190 finish:
2191   free(s1);
2192   return ret;
2193 }
2194 
_jbl_compare_nodes(JBL_NODE n1,JBL_NODE n2,iwrc * rcp)2195 int _jbl_compare_nodes(JBL_NODE n1, JBL_NODE n2, iwrc *rcp) {
2196   if (!n1 && !n2) {
2197     return 0;
2198   } else if (!n1) {
2199     return -1;
2200   } else if (!n2) {
2201     return 1;
2202   } else if (n1->type != n2->type) {
2203     return (int) n1->type - (int) n2->type;
2204   }
2205   switch (n1->type) {
2206     case JBV_BOOL:
2207       return n1->vbool - n2->vbool;
2208     case JBV_I64:
2209       return n1->vi64 > n2->vi64 ? 1 : n1->vi64 < n2->vi64 ? -1 : 0;
2210     case JBV_F64: {
2211       size_t sz1, sz2;
2212       char b1[JBNUMBUF_SIZE];
2213       char b2[JBNUMBUF_SIZE];
2214       jbi_ftoa(n1->vf64, b1, &sz1);
2215       jbi_ftoa(n2->vf64, b2, &sz2);
2216       return iwafcmp(b1, sz1, b2, sz2);
2217     }
2218     case JBV_STR:
2219       if (n1->vsize != n2->vsize) {
2220         return n1->vsize - n2->vsize;
2221       }
2222       return strncmp(n1->vptr, n2->vptr, n1->vsize);
2223     case JBV_ARRAY:
2224       for (n1 = n1->child, n2 = n2->child; n1 && n2; n1 = n1->next, n2 = n2->next) {
2225         int res = _jbl_compare_nodes(n1, n2, rcp);
2226         if (res) {
2227           return res;
2228         }
2229       }
2230       if (n1) {
2231         return 1;
2232       } else if (n2) {
2233         return -1;
2234       } else {
2235         return 0;
2236       }
2237     case JBV_OBJECT:
2238       return _jbl_compare_objects(n1, n2, rcp);
2239     case JBV_NULL:
2240     case JBV_NONE:
2241       break;
2242   }
2243   return 0;
2244 }
2245 
jbn_compare_nodes(JBL_NODE n1,JBL_NODE n2,iwrc * rcp)2246 int jbn_compare_nodes(JBL_NODE n1, JBL_NODE n2, iwrc *rcp) {
2247   return _jbl_compare_nodes(n1, n2, rcp);
2248 }
2249 
_jbl_target_apply_patch(JBL_NODE target,const JBL_PATCHEXT * ex,IWPOOL * pool)2250 static iwrc _jbl_target_apply_patch(JBL_NODE target, const JBL_PATCHEXT *ex, IWPOOL *pool) {
2251 
2252   struct _JBL_NODE *ntmp;
2253   jbp_patch_t op = ex->p->op;
2254   JBL_PTR path = ex->path;
2255   JBL_NODE value = ex->p->vnode;
2256   bool oproot = ex->path->cnt == 1 && *ex->path->n[0] == '\0';
2257 
2258   if (op == JBP_TEST) {
2259     iwrc rc = 0;
2260     if (!value) {
2261       return JBL_ERROR_PATCH_NOVALUE;
2262     }
2263     if (_jbl_compare_nodes(oproot ? target : _jbl_node_find(target, path, 0, path->cnt), value, &rc)) {
2264       RCRET(rc);
2265       return JBL_ERROR_PATCH_TEST_FAILED;
2266     } else {
2267       return rc;
2268     }
2269   }
2270   if (oproot) { // Root operation
2271     if (op == JBP_REMOVE) {
2272       memset(target, 0, sizeof(*target));
2273     } else if ((op == JBP_REPLACE) || (op == JBP_ADD) || (op == JBP_ADD_CREATE)) {
2274       if (!value) {
2275         return JBL_ERROR_PATCH_NOVALUE;
2276       }
2277       memmove(target, value, sizeof(*value));
2278     }
2279   } else { // Not a root
2280     if ((op == JBP_REMOVE) || (op == JBP_REPLACE)) {
2281       _jbl_node_detach(target, ex->path);
2282     }
2283     if (op == JBP_REMOVE) {
2284       return 0;
2285     } else if ((op == JBP_MOVE) || (op == JBP_COPY) || (op == JBP_SWAP)) {
2286       if (op == JBP_MOVE) {
2287         value = _jbl_node_detach(target, ex->from);
2288       } else {
2289         value = _jbl_node_find(target, ex->from, 0, ex->from->cnt);
2290       }
2291       if (!value) {
2292         return JBL_ERROR_PATH_NOTFOUND;
2293       }
2294       if (op == JBP_SWAP) {
2295         ntmp = iwpool_calloc(sizeof(*ntmp), pool);
2296         if (!ntmp) {
2297           return iwrc_set_errno(IW_ERROR_ALLOC, errno);
2298         }
2299       }
2300     } else { // ADD/REPLACE/INCREMENT
2301       if (!value) {
2302         return JBL_ERROR_PATCH_NOVALUE;
2303       }
2304     }
2305     int lastidx = path->cnt - 1;
2306     JBL_NODE parent = (path->cnt > 1) ? _jbl_node_find(target, path, 0, lastidx) : target;
2307     if (!parent) {
2308       if (op == JBP_ADD_CREATE) {
2309         parent = target;
2310         for (int i = 0; i < lastidx; ++i) {
2311           JBL_NODE pn = _jbl_node_find(parent, path, i, i + 1);
2312           if (!pn) {
2313             pn = iwpool_calloc(sizeof(*pn), pool);
2314             if (!pn) {
2315               return iwrc_set_errno(IW_ERROR_ALLOC, errno);
2316             }
2317             pn->type = JBV_OBJECT;
2318             pn->key = path->n[i];
2319             pn->klidx = (int) strlen(pn->key);
2320             _jbn_add_item(parent, pn);
2321           } else if (pn->type != JBV_OBJECT) {
2322             return JBL_ERROR_PATCH_TARGET_INVALID;
2323           }
2324           parent = pn;
2325         }
2326       } else {
2327         return JBL_ERROR_PATCH_TARGET_INVALID;
2328       }
2329     }
2330     if (parent->type == JBV_ARRAY) {
2331       if ((path->n[lastidx][0] == '-') && (path->n[lastidx][1] == '\0')) {
2332         if (op == JBP_SWAP) {
2333           value = _jbl_node_detach(target, ex->from);
2334         }
2335         _jbn_add_item(parent, value); // Add to end of array
2336       } else {                        // Insert into the specified index
2337         int idx = iwatoi(path->n[lastidx]);
2338         int cnt = idx;
2339         JBL_NODE child = parent->child;
2340         while (child && cnt > 0) {
2341           cnt--;
2342           child = child->next;
2343         }
2344         if (cnt > 0) {
2345           return JBL_ERROR_PATCH_INVALID_ARRAY_INDEX;
2346         }
2347         value->klidx = idx;
2348         if (child) {
2349           if (op == JBP_SWAP) {
2350             _jbl_copy_node_data(ntmp, value);
2351             _jbl_copy_node_data(value, child);
2352             _jbl_copy_node_data(child, ntmp);
2353           } else {
2354             value->parent = parent;
2355             value->next = child;
2356             value->prev = child->prev;
2357             child->prev = value;
2358             if (child == parent->child) {
2359               parent->child = value;
2360             } else {
2361               value->prev->next = value;
2362             }
2363             while (child) {
2364               child->klidx++;
2365               child = child->next;
2366             }
2367           }
2368         } else {
2369           if (op == JBP_SWAP) {
2370             value = _jbl_node_detach(target, ex->from);
2371           }
2372           _jbn_add_item(parent, value);
2373         }
2374       }
2375     } else if (parent->type == JBV_OBJECT) {
2376       JBL_NODE child = _jbl_node_find(parent, path, path->cnt - 1, path->cnt);
2377       if (child) {
2378         if (op == JBP_INCREMENT) {
2379           return _jbl_increment_node_data(child, value);
2380         } else {
2381           if (op == JBP_SWAP) {
2382             _jbl_copy_node_data(ntmp, value);
2383             _jbl_copy_node_data(value, child);
2384             _jbl_copy_node_data(child, ntmp);
2385           } else {
2386             _jbl_copy_node_data(child, value);
2387           }
2388         }
2389       } else if (op != JBP_INCREMENT) {
2390         if (op == JBP_SWAP) {
2391           value = _jbl_node_detach(target, ex->from);
2392         }
2393         value->key = path->n[path->cnt - 1];
2394         value->klidx = (int) strlen(value->key);
2395         _jbn_add_item(parent, value);
2396       } else {
2397         return JBL_ERROR_PATCH_TARGET_INVALID;
2398       }
2399     } else {
2400       return JBL_ERROR_PATCH_TARGET_INVALID;
2401     }
2402   }
2403   return 0;
2404 }
2405 
_jbl_from_node_impl(binn * res,JBL_NODE node)2406 static iwrc _jbl_from_node_impl(binn *res, JBL_NODE node) {
2407   iwrc rc = 0;
2408   switch (node->type) {
2409     case JBV_OBJECT:
2410       if (!binn_create(res, BINN_OBJECT, 0, NULL)) {
2411         return JBL_ERROR_CREATION;
2412       }
2413       for (JBL_NODE n = node->child; n; n = n->next) {
2414         binn bv;
2415         rc = _jbl_from_node_impl(&bv, n);
2416         RCRET(rc);
2417         if (!binn_object_set_value2(res, n->key, n->klidx, &bv)) {
2418           rc = JBL_ERROR_CREATION;
2419         }
2420         binn_free(&bv);
2421         RCRET(rc);
2422       }
2423       break;
2424     case JBV_ARRAY:
2425       if (!binn_create(res, BINN_LIST, 0, NULL)) {
2426         return JBL_ERROR_CREATION;
2427       }
2428       for (JBL_NODE n = node->child; n; n = n->next) {
2429         binn bv;
2430         rc = _jbl_from_node_impl(&bv, n);
2431         RCRET(rc);
2432         if (!binn_list_add_value(res, &bv)) {
2433           rc = JBL_ERROR_CREATION;
2434         }
2435         binn_free(&bv);
2436         RCRET(rc);
2437       }
2438       break;
2439     case JBV_STR:
2440       binn_init_item(res);
2441       binn_set_string(res, (void*) node->vptr, 0);
2442       break;
2443     case JBV_I64:
2444       binn_init_item(res);
2445       binn_set_int64(res, node->vi64);
2446       break;
2447     case JBV_F64:
2448       binn_init_item(res);
2449       binn_set_double(res, node->vf64);
2450       break;
2451     case JBV_BOOL:
2452       binn_init_item(res);
2453       binn_set_bool(res, node->vbool);
2454       break;
2455     case JBV_NULL:
2456       binn_init_item(res);
2457       binn_set_null(res);
2458       break;
2459     case JBV_NONE:
2460       rc = JBL_ERROR_CREATION;
2461       break;
2462   }
2463   return rc;
2464 }
2465 
_jbl_binn_from_node(binn * res,JBL_NODE node)2466 iwrc _jbl_binn_from_node(binn *res, JBL_NODE node) {
2467   iwrc rc = _jbl_from_node_impl(res, node);
2468   if (!rc) {
2469     if (res->writable && res->dirty) {
2470       binn_save_header(res);
2471     }
2472   }
2473   return rc;
2474 }
2475 
_jbl_from_node(JBL jbl,JBL_NODE node)2476 iwrc _jbl_from_node(JBL jbl, JBL_NODE node) {
2477   jbl->node = node;
2478   return _jbl_binn_from_node(&jbl->bn, node);
2479 }
2480 
_jbl_patch_node(JBL_NODE root,const JBL_PATCH * p,size_t cnt,IWPOOL * pool)2481 static iwrc _jbl_patch_node(JBL_NODE root, const JBL_PATCH *p, size_t cnt, IWPOOL *pool) {
2482   if (cnt < 1) {
2483     return 0;
2484   }
2485   if (!root || !p) {
2486     return IW_ERROR_INVALID_ARGS;
2487   }
2488   iwrc rc = 0;
2489   size_t i = 0;
2490   JBL_PATCHEXT parr[cnt];
2491   memset(parr, 0, cnt * sizeof(JBL_PATCHEXT));
2492   for (i = 0; i < cnt; ++i) {
2493     JBL_PATCHEXT *ext = &parr[i];
2494     ext->p = &p[i];
2495     rc = _jbl_ptr_pool(p[i].path, &ext->path, pool);
2496     RCRET(rc);
2497     if (p[i].from) {
2498       rc = _jbl_ptr_pool(p[i].from, &ext->from, pool);
2499       RCRET(rc);
2500     }
2501   }
2502   for (i = 0; i < cnt; ++i) {
2503     rc = _jbl_target_apply_patch(root, &parr[i], pool);
2504     RCRET(rc);
2505   }
2506   return rc;
2507 }
2508 
_jbl_patch(JBL jbl,const JBL_PATCH * p,size_t cnt,IWPOOL * pool)2509 static iwrc _jbl_patch(JBL jbl, const JBL_PATCH *p, size_t cnt, IWPOOL *pool) {
2510   if (cnt < 1) {
2511     return 0;
2512   }
2513   if (!jbl || !p) {
2514     return IW_ERROR_INVALID_ARGS;
2515   }
2516   binn bv;
2517   binn *bn;
2518   JBL_NODE root;
2519   iwrc rc = _jbl_node_from_binn(&jbl->bn, &root, false, pool);
2520   RCRET(rc);
2521   rc = _jbl_patch_node(root, p, cnt, pool);
2522   RCRET(rc);
2523   if (root->type != JBV_NONE) {
2524     rc = _jbl_from_node_impl(&bv, root);
2525     RCRET(rc);
2526     bn = &bv;
2527   } else {
2528     bn = 0;
2529   }
2530   binn_free(&jbl->bn);
2531   if (bn) {
2532     if (bn->writable && bn->dirty) {
2533       binn_save_header(bn);
2534     }
2535     memcpy(&jbl->bn, bn, sizeof(jbl->bn));
2536     jbl->bn.allocated = 0;
2537   } else {
2538     memset(&jbl->bn, 0, sizeof(jbl->bn));
2539     root->type = JBV_NONE;
2540   }
2541   return rc;
2542 }
2543 
_jbl_cmp_atomic_values(JBL v1,JBL v2)2544 int _jbl_cmp_atomic_values(JBL v1, JBL v2) {
2545   jbl_type_t t1 = jbl_type(v1);
2546   jbl_type_t t2 = jbl_type(v2);
2547   if (t1 != t2) {
2548     return (int) t1 - (int) t2;
2549   }
2550   switch (t1) {
2551     case JBV_BOOL:
2552     case JBV_I64: {
2553       int64_t vv1 = jbl_get_i64(v1);
2554       int64_t vv2 = jbl_get_i64(v2);
2555       return vv1 > vv2 ? 1 : vv1 < vv2 ? -1 : 0;
2556     }
2557     case JBV_STR:
2558       return strcmp(jbl_get_str(v1), jbl_get_str(v2)); // -V575
2559     case JBV_F64: {
2560       double vv1 = jbl_get_f64(v1);
2561       double vv2 = jbl_get_f64(v2);
2562       return vv1 > vv2 ? 1 : vv1 < vv2 ? -1 : 0;
2563     }
2564     default:
2565       return 0;
2566   }
2567 }
2568 
_jbl_is_eq_atomic_values(JBL v1,JBL v2)2569 bool _jbl_is_eq_atomic_values(JBL v1, JBL v2) {
2570   jbl_type_t t1 = jbl_type(v1);
2571   jbl_type_t t2 = jbl_type(v2);
2572   if (t1 != t2) {
2573     return false;
2574   }
2575   switch (t1) {
2576     case JBV_BOOL:
2577     case JBV_I64:
2578       return jbl_get_i64(v1) == jbl_get_i64(v2);
2579     case JBV_STR:
2580       return !strcmp(jbl_get_str(v1), jbl_get_str(v2)); // -V575
2581     case JBV_F64:
2582       return jbl_get_f64(v1) == jbl_get_f64(v2); // -V550
2583     case JBV_OBJECT:
2584     case JBV_ARRAY:
2585       return false;
2586     default:
2587       return true;
2588   }
2589 }
2590 
2591 // --------------------------- Public API
2592 
jbn_apply_from(JBL_NODE target,JBL_NODE from)2593 void jbn_apply_from(JBL_NODE target, JBL_NODE from) {
2594   const int off = offsetof(struct _JBL_NODE, child);
2595   memcpy((char*) target + off,
2596          (char*) from + off,
2597          sizeof(struct _JBL_NODE) - off);
2598 }
2599 
jbl_to_node(JBL jbl,JBL_NODE * node,bool clone_strings,IWPOOL * pool)2600 iwrc jbl_to_node(JBL jbl, JBL_NODE *node, bool clone_strings, IWPOOL *pool) {
2601   if (jbl->node) {
2602     *node = jbl->node;
2603     return 0;
2604   }
2605   return _jbl_node_from_binn(&jbl->bn, node, clone_strings, pool);
2606 }
2607 
jbn_patch(JBL_NODE root,const JBL_PATCH * p,size_t cnt,IWPOOL * pool)2608 iwrc jbn_patch(JBL_NODE root, const JBL_PATCH *p, size_t cnt, IWPOOL *pool) {
2609   return _jbl_patch_node(root, p, cnt, pool);
2610 }
2611 
jbl_patch(JBL jbl,const JBL_PATCH * p,size_t cnt)2612 iwrc jbl_patch(JBL jbl, const JBL_PATCH *p, size_t cnt) {
2613   if (cnt < 1) {
2614     return 0;
2615   }
2616   if (!jbl || !p) {
2617     return IW_ERROR_INVALID_ARGS;
2618   }
2619   IWPOOL *pool = iwpool_create(jbl->bn.size);
2620   if (!pool) {
2621     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
2622   }
2623   iwrc rc = _jbl_patch(jbl, p, cnt, pool);
2624   iwpool_destroy(pool);
2625   return rc;
2626 }
2627 
_jbl_create_patch(JBL_NODE node,JBL_PATCH ** pptr,int * cntp,IWPOOL * pool)2628 static iwrc _jbl_create_patch(JBL_NODE node, JBL_PATCH **pptr, int *cntp, IWPOOL *pool) {
2629   *pptr = 0;
2630   *cntp = 0;
2631   int i = 0;
2632   for (JBL_NODE n = node->child; n; n = n->next) {
2633     if (n->type != JBV_OBJECT) {
2634       return JBL_ERROR_PATCH_INVALID;
2635     }
2636     ++i;
2637   }
2638   JBL_PATCH *p = iwpool_alloc(i * sizeof(*p), pool);
2639   if (!p) {
2640     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
2641   }
2642   memset(p, 0, i * sizeof(*p));
2643   i = 0;
2644   for (JBL_NODE n = node->child; n; n = n->next, ++i) {
2645     JBL_PATCH *pp = p + i;
2646     for (JBL_NODE n2 = n->child; n2; n2 = n2->next) {
2647       if (!strncmp("op", n2->key, n2->klidx)) {
2648         if (n2->type != JBV_STR) {
2649           return JBL_ERROR_PATCH_INVALID;
2650         }
2651         if (!strncmp("add", n2->vptr, n2->vsize)) {
2652           pp->op = JBP_ADD;
2653         } else if (!strncmp("remove", n2->vptr, n2->vsize)) {
2654           pp->op = JBP_REMOVE;
2655         } else if (!strncmp("replace", n2->vptr, n2->vsize)) {
2656           pp->op = JBP_REPLACE;
2657         } else if (!strncmp("copy", n2->vptr, n2->vsize)) {
2658           pp->op = JBP_COPY;
2659         } else if (!strncmp("move", n2->vptr, n2->vsize)) {
2660           pp->op = JBP_MOVE;
2661         } else if (!strncmp("test", n2->vptr, n2->vsize)) {
2662           pp->op = JBP_TEST;
2663         } else if (!strncmp("increment", n2->vptr, n2->vsize)) {
2664           pp->op = JBP_INCREMENT;
2665         } else if (!strncmp("add_create", n2->vptr, n2->vsize)) {
2666           pp->op = JBP_ADD_CREATE;
2667         } else if (!strncmp("swap", n2->vptr, n2->vsize)) {
2668           pp->op = JBP_SWAP;
2669         } else {
2670           return JBL_ERROR_PATCH_INVALID_OP;
2671         }
2672       } else if (!strncmp("value", n2->key, n2->klidx)) {
2673         pp->vnode = n2;
2674       } else if (!strncmp("path", n2->key, n2->klidx)) {
2675         if (n2->type != JBV_STR) {
2676           return JBL_ERROR_PATCH_INVALID;
2677         }
2678         pp->path = n2->vptr;
2679       } else if (!strncmp("from", n2->key, n2->klidx)) {
2680         if (n2->type != JBV_STR) {
2681           return JBL_ERROR_PATCH_INVALID;
2682         }
2683         pp->from = n2->vptr;
2684       }
2685     }
2686   }
2687   *cntp = i;
2688   *pptr = p;
2689   return 0;
2690 }
2691 
jbl_patch_from_json(JBL jbl,const char * patchjson)2692 iwrc jbl_patch_from_json(JBL jbl, const char *patchjson) {
2693   if (!jbl || !patchjson) {
2694     return IW_ERROR_INVALID_ARGS;
2695   }
2696   JBL_PATCH *p;
2697   JBL_NODE patch;
2698   int cnt = (int) strlen(patchjson);
2699   IWPOOL *pool = iwpool_create(MAX(cnt, 1024U));
2700   if (!pool) {
2701     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
2702   }
2703   iwrc rc = jbn_from_json(patchjson, &patch, pool);
2704   RCGO(rc, finish);
2705   if (patch->type == JBV_ARRAY) {
2706     rc = _jbl_create_patch(patch, &p, &cnt, pool);
2707     RCGO(rc, finish);
2708     rc = _jbl_patch(jbl, p, cnt, pool);
2709   } else if (patch->type == JBV_OBJECT) {
2710     // FIXME: Merge patch not implemented
2711     //_jbl_merge_patch_node()
2712     rc = IW_ERROR_NOT_IMPLEMENTED;
2713   } else {
2714     rc = JBL_ERROR_PATCH_INVALID;
2715   }
2716 
2717 finish:
2718   iwpool_destroy(pool);
2719   return rc;
2720 }
2721 
jbl_fill_from_node(JBL jbl,JBL_NODE node)2722 iwrc jbl_fill_from_node(JBL jbl, JBL_NODE node) {
2723   if (!jbl || !node) {
2724     return IW_ERROR_INVALID_ARGS;
2725   }
2726   if (node->type == JBV_NONE) {
2727     memset(jbl, 0, sizeof(*jbl));
2728     return 0;
2729   }
2730   binn bv = { 0 };
2731   iwrc rc = _jbl_binn_from_node(&bv, node);
2732   RCRET(rc);
2733   binn_free(&jbl->bn);
2734   memcpy(&jbl->bn, &bv, sizeof(jbl->bn));
2735   jbl->bn.allocated = 0;
2736   return rc;
2737 }
2738 
jbl_from_node(JBL * jblp,JBL_NODE node)2739 iwrc jbl_from_node(JBL *jblp, JBL_NODE node) {
2740   if (!jblp || !node) {
2741     return IW_ERROR_INVALID_ARGS;
2742   }
2743   iwrc rc = 0;
2744   if (node->type == JBV_OBJECT) {
2745     rc = jbl_create_empty_object(jblp);
2746   } else if (node->type == JBV_ARRAY) {
2747     rc = jbl_create_empty_array(jblp);
2748   } else {
2749     rc = IW_ERROR_INVALID_ARGS;
2750   }
2751   RCRET(rc);
2752   return jbl_fill_from_node(*jblp, node);
2753 }
2754 
_jbl_merge_patch_node(JBL_NODE target,JBL_NODE patch,IWPOOL * pool,iwrc * rcp)2755 static JBL_NODE _jbl_merge_patch_node(JBL_NODE target, JBL_NODE patch, IWPOOL *pool, iwrc *rcp) {
2756   *rcp = 0;
2757   if (!patch) {
2758     return 0;
2759   }
2760   if (patch->type == JBV_OBJECT) {
2761     if (!target) {
2762       target = iwpool_alloc(sizeof(*target), pool);
2763       if (!target) {
2764         *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
2765         return 0;
2766       }
2767       memset(target, 0, sizeof(*target));
2768       target->type = JBV_OBJECT;
2769       target->key = patch->key;
2770       target->klidx = patch->klidx;
2771     } else if (target->type != JBV_OBJECT) {
2772       _jbl_node_reset_data(target);
2773       target->type = JBV_OBJECT;
2774     }
2775     patch = patch->child;
2776     while (patch) {
2777       JBL_NODE patch_next = patch->next;
2778       if (patch->type == JBV_NULL) {
2779         JBL_NODE node = target->child;
2780         while (node) {
2781           if ((node->klidx == patch->klidx) && !strncmp(node->key, patch->key, node->klidx)) {
2782             _jbn_remove_item(target, node);
2783             break;
2784           }
2785           node = node->next;
2786         }
2787       } else {
2788         JBL_NODE node = target->child;
2789         while (node) {
2790           if ((node->klidx == patch->klidx) && !strncmp(node->key, patch->key, node->klidx)) {
2791             _jbl_copy_node_data(node, _jbl_merge_patch_node(node, patch, pool, rcp));
2792             break;
2793           }
2794           node = node->next;
2795         }
2796         if (!node) {
2797           _jbn_add_item(target, _jbl_merge_patch_node(0, patch, pool, rcp));
2798         }
2799       }
2800       patch = patch_next;
2801     }
2802     return target;
2803   } else {
2804     return patch;
2805   }
2806 }
2807 
jbn_merge_patch_from_json(JBL_NODE root,const char * patchjson,IWPOOL * pool)2808 iwrc jbn_merge_patch_from_json(JBL_NODE root, const char *patchjson, IWPOOL *pool) {
2809   if (!root || !patchjson || !pool) {
2810     return IW_ERROR_INVALID_ARGS;
2811   }
2812   JBL_NODE patch, res;
2813   iwrc rc = jbn_from_json(patchjson, &patch, pool);
2814   RCRET(rc);
2815   res = _jbl_merge_patch_node(root, patch, pool, &rc);
2816   RCGO(rc, finish);
2817   if (res != root) {
2818     memcpy(root, res, sizeof(*root)); // -V575
2819   }
2820 
2821 finish:
2822   return rc;
2823 }
2824 
jbl_merge_patch(JBL jbl,const char * patchjson)2825 iwrc jbl_merge_patch(JBL jbl, const char *patchjson) {
2826   if (!jbl || !patchjson) {
2827     return IW_ERROR_INVALID_ARGS;
2828   }
2829   binn bv;
2830   JBL_NODE target;
2831   IWPOOL *pool = iwpool_create(jbl->bn.size * 2);
2832   if (!pool) {
2833     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
2834   }
2835   iwrc rc = _jbl_node_from_binn(&jbl->bn, &target, false, pool);
2836   RCGO(rc, finish);
2837   rc = jbn_merge_patch_from_json(target, patchjson, pool);
2838   RCGO(rc, finish);
2839 
2840   rc = _jbl_binn_from_node(&bv, target);
2841   RCGO(rc, finish);
2842 
2843   binn_free(&jbl->bn);
2844   memcpy(&jbl->bn, &bv, sizeof(jbl->bn));
2845   jbl->bn.allocated = 0;
2846 
2847 finish:
2848   iwpool_destroy(pool);
2849   return 0;
2850 }
2851 
jbl_merge_patch_jbl(JBL jbl,JBL patch)2852 iwrc jbl_merge_patch_jbl(JBL jbl, JBL patch) {
2853 
2854   IWXSTR *xstr = iwxstr_new();
2855   if (!xstr) {
2856     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
2857   }
2858   iwrc rc = jbl_as_json(patch, jbl_xstr_json_printer, xstr, 0);
2859   RCGO(rc, finish);
2860   rc = jbl_merge_patch(jbl, iwxstr_ptr(xstr));
2861 finish:
2862   iwxstr_destroy(xstr);
2863   return rc;
2864 }
2865 
jbn_patch_auto(JBL_NODE root,JBL_NODE patch,IWPOOL * pool)2866 iwrc jbn_patch_auto(JBL_NODE root, JBL_NODE patch, IWPOOL *pool) {
2867   if (!root || !patch || !pool) {
2868     return IW_ERROR_INVALID_ARGS;
2869   }
2870   iwrc rc = 0;
2871   if (patch->type == JBV_OBJECT) {
2872     _jbl_merge_patch_node(root, patch, pool, &rc);
2873   } else if (patch->type == JBV_ARRAY) {
2874     int cnt;
2875     JBL_PATCH *p;
2876     rc = _jbl_create_patch(patch, &p, &cnt, pool);
2877     RCRET(rc);
2878     rc = _jbl_patch_node(root, p, cnt, pool);
2879   } else {
2880     return IW_ERROR_INVALID_ARGS;
2881   }
2882   return rc;
2883 }
2884 
jbn_merge_patch(JBL_NODE root,JBL_NODE patch,IWPOOL * pool)2885 iwrc jbn_merge_patch(JBL_NODE root, JBL_NODE patch, IWPOOL *pool) {
2886   if (!root || !patch || pool || (root->type != JBV_OBJECT)) {
2887     return IW_ERROR_INVALID_ARGS;
2888   }
2889   iwrc rc = 0;
2890   _jbl_merge_patch_node(root, patch, pool, &rc);
2891   return rc;
2892 }
2893 
_jbl_ecodefn(locale_t locale,uint32_t ecode)2894 static const char *_jbl_ecodefn(locale_t locale, uint32_t ecode) {
2895   if (!((ecode > _JBL_ERROR_START) && (ecode < _JBL_ERROR_END))) {
2896     return 0;
2897   }
2898   switch (ecode) {
2899     case JBL_ERROR_INVALID_BUFFER:
2900       return "Invalid JBL buffer (JBL_ERROR_INVALID_BUFFER)";
2901     case JBL_ERROR_CREATION:
2902       return "Cannot create JBL object (JBL_ERROR_CREATION)";
2903     case JBL_ERROR_INVALID:
2904       return "Invalid JBL object (JBL_ERROR_INVALID)";
2905     case JBL_ERROR_PARSE_JSON:
2906       return "Failed to parse JSON string (JBL_ERROR_PARSE_JSON)";
2907     case JBL_ERROR_PARSE_UNQUOTED_STRING:
2908       return "Unquoted JSON string (JBL_ERROR_PARSE_UNQUOTED_STRING)";
2909     case JBL_ERROR_PARSE_INVALID_CODEPOINT:
2910       return "Invalid unicode codepoint/escape sequence (JBL_ERROR_PARSE_INVALID_CODEPOINT)";
2911     case JBL_ERROR_PARSE_INVALID_UTF8:
2912       return "Invalid utf8 string (JBL_ERROR_PARSE_INVALID_UTF8)";
2913     case JBL_ERROR_JSON_POINTER:
2914       return "Invalid JSON pointer (rfc6901) path (JBL_ERROR_JSON_POINTER)";
2915     case JBL_ERROR_PATH_NOTFOUND:
2916       return "JSON object not matched the path specified (JBL_ERROR_PATH_NOTFOUND)";
2917     case JBL_ERROR_PATCH_INVALID:
2918       return "Invalid JSON patch specified (JBL_ERROR_PATCH_INVALID)";
2919     case JBL_ERROR_PATCH_INVALID_OP:
2920       return "Invalid JSON patch operation specified (JBL_ERROR_PATCH_INVALID_OP)";
2921     case JBL_ERROR_PATCH_NOVALUE:
2922       return "No value specified in JSON patch (JBL_ERROR_PATCH_NOVALUE)";
2923     case JBL_ERROR_PATCH_TARGET_INVALID:
2924       return "Could not find target object to set value (JBL_ERROR_PATCH_TARGET_INVALID)";
2925     case JBL_ERROR_PATCH_INVALID_VALUE:
2926       return "Invalid value specified by patch (JBL_ERROR_PATCH_INVALID_VALUE)";
2927     case JBL_ERROR_PATCH_INVALID_ARRAY_INDEX:
2928       return "Invalid array index in JSON patch path (JBL_ERROR_PATCH_INVALID_ARRAY_INDEX)";
2929     case JBL_ERROR_PATCH_TEST_FAILED:
2930       return "JSON patch test operation failed (JBL_ERROR_PATCH_TEST_FAILED)";
2931     case JBL_ERROR_NOT_AN_OBJECT:
2932       return "JBL is not an object (JBL_ERROR_NOT_AN_OBJECT)";
2933     case JBL_ERROR_TYPE_MISMATCHED:
2934       return "Type of JBL object mismatched user type constraints (JBL_ERROR_TYPE_MISMATCHED)";
2935     case JBL_ERROR_MAX_NESTING_LEVEL_EXCEEDED:
2936       return "Exceeded the maximal object nesting level: " _STR(JBL_MAX_NESTING_LEVEL)
2937              " (JBL_ERROR_MAX_NESTING_LEVEL_EXCEEDED)";
2938   }
2939   return 0;
2940 }
2941 
jbl_init()2942 iwrc jbl_init() {
2943   static int _jbl_initialized = 0;
2944   if (!__sync_bool_compare_and_swap(&_jbl_initialized, 0, 1)) {
2945     return 0;
2946   }
2947   return iwlog_register_ecodefn(_jbl_ecodefn);
2948 }
2949