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