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