1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3 * Copyright (C) 2021-2024 Cyril Hrubis <metan@ucw.cz>
4 */
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <stdint.h>
14
15 #include "ujson_utf.h"
16 #include "ujson_reader.h"
17
18 static const struct ujson_obj empty = {};
19 const struct ujson_obj *ujson_empty_obj = ∅
20
buf_empty(ujson_reader * buf)21 static inline int buf_empty(ujson_reader *buf)
22 {
23 return buf->off >= buf->len;
24 }
25
eatws(ujson_reader * buf)26 static int eatws(ujson_reader *buf)
27 {
28 while (!buf_empty(buf)) {
29 switch (buf->json[buf->off]) {
30 case ' ':
31 case '\t':
32 case '\n':
33 case '\r':
34 break;
35 default:
36 goto ret;
37 }
38
39 buf->off += 1;
40 }
41 ret:
42 return buf_empty(buf);
43 }
44
getb(ujson_reader * buf)45 static char getb(ujson_reader *buf)
46 {
47 if (buf_empty(buf))
48 return 0;
49
50 return buf->json[buf->off++];
51 }
52
peekb_off(ujson_reader * buf,size_t off)53 static char peekb_off(ujson_reader *buf, size_t off)
54 {
55 if (buf->off + off >= buf->len)
56 return 0;
57
58 return buf->json[buf->off + off];
59 }
60
peekb(ujson_reader * buf)61 static char peekb(ujson_reader *buf)
62 {
63 if (buf_empty(buf))
64 return 0;
65
66 return buf->json[buf->off];
67 }
68
eatb(ujson_reader * buf,char ch)69 static int eatb(ujson_reader *buf, char ch)
70 {
71 if (peekb(buf) != ch)
72 return 0;
73
74 getb(buf);
75 return 1;
76 }
77
eatb2(ujson_reader * buf,char ch1,char ch2)78 static int eatb2(ujson_reader *buf, char ch1, char ch2)
79 {
80 if (peekb(buf) != ch1 && peekb(buf) != ch2)
81 return 0;
82
83 getb(buf);
84 return 1;
85 }
86
eatstr(ujson_reader * buf,const char * str)87 static int eatstr(ujson_reader *buf, const char *str)
88 {
89 while (*str) {
90 if (!eatb(buf, *str))
91 return 0;
92 str++;
93 }
94
95 return 1;
96 }
97
hex2val(unsigned char b)98 static int hex2val(unsigned char b)
99 {
100 switch (b) {
101 case '0' ... '9':
102 return b - '0';
103 case 'a' ... 'f':
104 return b - 'a' + 10;
105 case 'A' ... 'F':
106 return b - 'A' + 10;
107 default:
108 return -1;
109 }
110 }
111
parse_ucode_cp(ujson_reader * buf)112 static int32_t parse_ucode_cp(ujson_reader *buf)
113 {
114 int ret = 0, v, i;
115
116 for (i = 0; i < 4; i++) {
117 if ((v = hex2val(getb(buf))) < 0)
118 goto err;
119 ret *= 16;
120 ret += v;
121 }
122
123 return ret;
124 err:
125 ujson_err(buf, "Expected four hexadecimal digits");
126 return -1;
127 }
128
parse_ucode_esc(ujson_reader * buf,char * str,size_t off,size_t len)129 static unsigned int parse_ucode_esc(ujson_reader *buf, char *str,
130 size_t off, size_t len)
131 {
132 int32_t ucode = parse_ucode_cp(buf);
133
134 if (ucode < 0)
135 return 0;
136
137 if (!str)
138 return ucode;
139
140 if (ujson_utf8_bytes(ucode) + 1 >= len - off) {
141 ujson_err(buf, "String buffer too short!");
142 return 0;
143 }
144
145 return ujson_to_utf8(ucode, str+off);
146 }
147
copy_str(ujson_reader * buf,char * str,size_t len)148 static int copy_str(ujson_reader *buf, char *str, size_t len)
149 {
150 size_t pos = 0;
151 int esc = 0;
152 unsigned int l;
153
154 eatb(buf, '"');
155
156 for (;;) {
157 if (buf_empty(buf)) {
158 ujson_err(buf, "Unterminated string");
159 return 1;
160 }
161
162 if (!esc && eatb(buf, '"')) {
163 if (str)
164 str[pos] = 0;
165 return 0;
166 }
167
168 unsigned char b = getb(buf);
169
170 if (b < 0x20) {
171 if (!peekb(buf))
172 ujson_err(buf, "Unterminated string");
173 else
174 ujson_err(buf, "Invalid string character 0x%02x", b);
175 return 1;
176 }
177
178 if (!esc && b == '\\') {
179 esc = 1;
180 continue;
181 }
182
183 if (esc) {
184 switch (b) {
185 case '"':
186 case '\\':
187 case '/':
188 break;
189 case 'b':
190 b = '\b';
191 break;
192 case 'f':
193 b = '\f';
194 break;
195 case 'n':
196 b = '\n';
197 break;
198 case 'r':
199 b = '\r';
200 break;
201 case 't':
202 b = '\t';
203 break;
204 case 'u':
205 if (!(l = parse_ucode_esc(buf, str, pos, len)))
206 return 1;
207 pos += l;
208 b = 0;
209 break;
210 default:
211 ujson_err(buf, "Invalid escape \\%c", b);
212 return 1;
213 }
214 esc = 0;
215 }
216
217 if (str && b) {
218 if (pos + 1 >= len) {
219 ujson_err(buf, "String buffer too short!");
220 return 1;
221 }
222
223 str[pos++] = b;
224 }
225 }
226
227 return 1;
228 }
229
copy_id_str(ujson_reader * buf,char * str,size_t len)230 static int copy_id_str(ujson_reader *buf, char *str, size_t len)
231 {
232 size_t pos = 0;
233
234 if (eatws(buf))
235 goto err0;
236
237 if (!eatb(buf, '"'))
238 goto err0;
239
240 for (;;) {
241 if (buf_empty(buf)) {
242 ujson_err(buf, "Unterminated ID string");
243 return 1;
244 }
245
246 if (eatb(buf, '"')) {
247 str[pos] = 0;
248 break;
249 }
250
251 if (pos >= len-1) {
252 ujson_err(buf, "ID string too long");
253 return 1;
254 }
255
256 str[pos++] = getb(buf);
257 }
258
259 if (eatws(buf))
260 goto err1;
261
262 if (!eatb(buf, ':'))
263 goto err1;
264
265 return 0;
266 err0:
267 ujson_err(buf, "Expected ID string");
268 return 1;
269 err1:
270 ujson_err(buf, "Expected ':' after ID string");
271 return 1;
272 }
273
is_digit(char b)274 static int is_digit(char b)
275 {
276 switch (b) {
277 case '0' ... '9':
278 return 1;
279 default:
280 return 0;
281 }
282 }
283
get_int(ujson_reader * buf,struct ujson_val * res)284 static int get_int(ujson_reader *buf, struct ujson_val *res)
285 {
286 long val = 0;
287 int sign = 1;
288
289 if (eatb(buf, '-')) {
290 sign = -1;
291 if (!is_digit(peekb(buf))) {
292 ujson_err(buf, "Expected digit(s)");
293 return 1;
294 }
295 }
296
297 if (peekb(buf) == '0' && is_digit(peekb_off(buf, 1))) {
298 ujson_err(buf, "Leading zero in number!");
299 return 1;
300 }
301
302 while (is_digit(peekb(buf))) {
303 val *= 10;
304 val += getb(buf) - '0';
305 //TODO: overflow?
306 }
307
308 if (sign < 0)
309 val = -val;
310
311 res->val_int = val;
312 res->val_float = val;
313
314 return 0;
315 }
316
eat_digits(ujson_reader * buf)317 static int eat_digits(ujson_reader *buf)
318 {
319 if (!is_digit(peekb(buf))) {
320 ujson_err(buf, "Expected digit(s)");
321 return 1;
322 }
323
324 while (is_digit(peekb(buf)))
325 getb(buf);
326
327 return 0;
328 }
329
get_float(ujson_reader * buf,struct ujson_val * res)330 static int get_float(ujson_reader *buf, struct ujson_val *res)
331 {
332 off_t start = buf->off;
333
334 eatb(buf, '-');
335
336 if (peekb(buf) == '0' && is_digit(peekb_off(buf, 1))) {
337 ujson_err(buf, "Leading zero in float");
338 return 1;
339 }
340
341 if (eat_digits(buf))
342 return 1;
343
344 switch (getb(buf)) {
345 case '.':
346 if (eat_digits(buf))
347 return 1;
348
349 if (!eatb2(buf, 'e', 'E'))
350 break;
351
352 /* fallthrough */
353 case 'e':
354 case 'E':
355 eatb2(buf, '+', '-');
356
357 if (eat_digits(buf))
358 return 1;
359 break;
360 }
361
362 size_t len = buf->off - start;
363 char tmp[len+1];
364
365 memcpy(tmp, buf->json + start, len);
366
367 tmp[len] = 0;
368
369 res->val_float = strtod(tmp, NULL);
370
371 return 0;
372 }
373
get_bool(ujson_reader * buf,struct ujson_val * res)374 static int get_bool(ujson_reader *buf, struct ujson_val *res)
375 {
376 switch (peekb(buf)) {
377 case 'f':
378 if (!eatstr(buf, "false")) {
379 ujson_err(buf, "Expected 'false'");
380 return 1;
381 }
382
383 res->val_bool = 0;
384 break;
385 case 't':
386 if (!eatstr(buf, "true")) {
387 ujson_err(buf, "Expected 'true'");
388 return 1;
389 }
390
391 res->val_bool = 1;
392 break;
393 }
394
395 return 0;
396 }
397
get_null(ujson_reader * buf)398 static int get_null(ujson_reader *buf)
399 {
400 if (!eatstr(buf, "null")) {
401 ujson_err(buf, "Expected 'null'");
402 return 1;
403 }
404
405 return 0;
406 }
407
ujson_obj_skip(ujson_reader * buf)408 int ujson_obj_skip(ujson_reader *buf)
409 {
410 struct ujson_val res = {};
411
412 UJSON_OBJ_FOREACH(buf, &res) {
413 switch (res.type) {
414 case UJSON_OBJ:
415 if (ujson_obj_skip(buf))
416 return 1;
417 break;
418 case UJSON_ARR:
419 if (ujson_arr_skip(buf))
420 return 1;
421 break;
422 default:
423 break;
424 }
425 }
426
427 return 0;
428 }
429
ujson_arr_skip(ujson_reader * buf)430 int ujson_arr_skip(ujson_reader *buf)
431 {
432 struct ujson_val res = {};
433
434 UJSON_ARR_FOREACH(buf, &res) {
435 switch (res.type) {
436 case UJSON_OBJ:
437 if (ujson_obj_skip(buf))
438 return 1;
439 break;
440 case UJSON_ARR:
441 if (ujson_arr_skip(buf))
442 return 1;
443 break;
444 default:
445 break;
446 }
447 }
448
449 return 0;
450 }
451
next_num_type(ujson_reader * buf)452 static enum ujson_type next_num_type(ujson_reader *buf)
453 {
454 size_t off = 0;
455
456 for (;;) {
457 char b = peekb_off(buf, off++);
458
459 switch (b) {
460 case 0:
461 case ',':
462 return UJSON_INT;
463 case '.':
464 case 'e':
465 case 'E':
466 return UJSON_FLOAT;
467 }
468 }
469
470 return UJSON_VOID;
471 }
472
ujson_next_type(ujson_reader * buf)473 enum ujson_type ujson_next_type(ujson_reader *buf)
474 {
475 if (eatws(buf)) {
476 ujson_err(buf, "Unexpected end");
477 return UJSON_VOID;
478 }
479
480 char b = peekb(buf);
481
482 switch (b) {
483 case '{':
484 return UJSON_OBJ;
485 case '[':
486 return UJSON_ARR;
487 case '"':
488 return UJSON_STR;
489 case '-':
490 case '0' ... '9':
491 return next_num_type(buf);
492 case 'f':
493 case 't':
494 return UJSON_BOOL;
495 break;
496 case 'n':
497 return UJSON_NULL;
498 break;
499 default:
500 ujson_err(buf, "Expected object, array, number or string");
501 return UJSON_VOID;
502 }
503 }
504
ujson_reader_start(ujson_reader * buf)505 enum ujson_type ujson_reader_start(ujson_reader *buf)
506 {
507 enum ujson_type type = ujson_next_type(buf);
508
509 switch (type) {
510 case UJSON_ARR:
511 case UJSON_OBJ:
512 case UJSON_VOID:
513 break;
514 default:
515 ujson_err(buf, "JSON can start only with array or object");
516 type = UJSON_VOID;
517 break;
518 }
519
520 return type;
521 }
522
get_value(ujson_reader * buf,struct ujson_val * res)523 static int get_value(ujson_reader *buf, struct ujson_val *res)
524 {
525 int ret = 0;
526
527 res->type = ujson_next_type(buf);
528
529 switch (res->type) {
530 case UJSON_STR:
531 if (copy_str(buf, res->buf, res->buf_size)) {
532 res->type = UJSON_VOID;
533 return 0;
534 }
535 res->val_str = res->buf;
536 return 1;
537 case UJSON_INT:
538 ret = get_int(buf, res);
539 break;
540 case UJSON_FLOAT:
541 ret = get_float(buf, res);
542 break;
543 case UJSON_BOOL:
544 ret = get_bool(buf, res);
545 break;
546 case UJSON_NULL:
547 ret = get_null(buf);
548 break;
549 case UJSON_VOID:
550 return 0;
551 case UJSON_ARR:
552 case UJSON_OBJ:
553 buf->sub_off = buf->off;
554 return 1;
555 }
556
557 if (ret) {
558 res->type = UJSON_VOID;
559 return 0;
560 }
561
562 return 1;
563 }
564
pre_next(ujson_reader * buf,struct ujson_val * res)565 static int pre_next(ujson_reader *buf, struct ujson_val *res)
566 {
567 if (!eatb(buf, ',')) {
568 ujson_err(buf, "Expected ','");
569 res->type = UJSON_VOID;
570 return 1;
571 }
572
573 if (eatws(buf)) {
574 ujson_err(buf, "Unexpected end");
575 res->type = UJSON_VOID;
576 return 1;
577 }
578
579 return 0;
580 }
581
check_end(ujson_reader * buf,struct ujson_val * res,char b)582 static int check_end(ujson_reader *buf, struct ujson_val *res, char b)
583 {
584 if (eatws(buf)) {
585 ujson_err(buf, "Unexpected end");
586 return 1;
587 }
588
589 if (eatb(buf, b)) {
590 res->type = UJSON_VOID;
591 eatws(buf);
592 eatb(buf, 0);
593 buf->depth--;
594 return 1;
595 }
596
597 return 0;
598 }
599
600 /*
601 * This is supposed to return a pointer to a string stored as a first member of
602 * a structure given an array.
603 *
604 * e.g.
605 *
606 * struct foo {
607 * const char *key;
608 * ...
609 * };
610 *
611 * const struct foo bar[10] = {...};
612 *
613 * // Returns a pointer to the key string in a second structure in bar[].
614 * const char *key = list_elem(bar, sizeof(struct foo), 1);
615 */
list_elem(const void * arr,size_t memb_size,size_t idx)616 static inline const char *list_elem(const void *arr, size_t memb_size, size_t idx)
617 {
618 return *(const char**)(arr + idx * memb_size);
619 }
620
ujson_lookup(const void * arr,size_t memb_size,size_t list_len,const char * key)621 size_t ujson_lookup(const void *arr, size_t memb_size, size_t list_len,
622 const char *key)
623 {
624 size_t l = 0;
625 size_t r = list_len-1;
626 size_t mid = -1;
627
628 if (!list_len)
629 return (size_t)-1;
630
631 while (r - l > 1) {
632 mid = (l+r)/2;
633
634 int ret = strcmp(list_elem(arr, memb_size, mid), key);
635 if (!ret)
636 return mid;
637
638 if (ret < 0)
639 l = mid;
640 else
641 r = mid;
642 }
643
644 if (r != mid && !strcmp(list_elem(arr, memb_size, r), key))
645 return r;
646
647 if (l != mid && !strcmp(list_elem(arr, memb_size, l), key))
648 return l;
649
650 return -1;
651 }
652
skip_obj_val(ujson_reader * buf)653 static int skip_obj_val(ujson_reader *buf)
654 {
655 struct ujson_val dummy = {};
656
657 if (!get_value(buf, &dummy))
658 return 0;
659
660 switch (dummy.type) {
661 case UJSON_OBJ:
662 return !ujson_obj_skip(buf);
663 case UJSON_ARR:
664 return !ujson_arr_skip(buf);
665 default:
666 return 1;
667 }
668 }
669
obj_next(ujson_reader * buf,struct ujson_val * res)670 static int obj_next(ujson_reader *buf, struct ujson_val *res)
671 {
672 if (copy_id_str(buf, res->id, sizeof(res->id)))
673 return 0;
674
675 return get_value(buf, res);
676 }
677
obj_pre_next(ujson_reader * buf,struct ujson_val * res)678 static int obj_pre_next(ujson_reader *buf, struct ujson_val *res)
679 {
680 if (ujson_reader_err(buf))
681 return 1;
682
683 if (check_end(buf, res, '}'))
684 return 1;
685
686 if (pre_next(buf, res))
687 return 1;
688
689 return 0;
690 }
691
obj_next_filter(ujson_reader * buf,struct ujson_val * res,const struct ujson_obj * obj,const struct ujson_obj * ign)692 static int obj_next_filter(ujson_reader *buf, struct ujson_val *res,
693 const struct ujson_obj *obj, const struct ujson_obj *ign)
694 {
695 const struct ujson_obj_attr *attr;
696
697 for (;;) {
698 if (copy_id_str(buf, res->id, sizeof(res->id)))
699 return 0;
700
701 res->idx = obj ? ujson_obj_lookup(obj, res->id) : (size_t)-1;
702
703 if (res->idx != (size_t)-1) {
704 if (!get_value(buf, res))
705 return 0;
706
707 attr = &obj->attrs[res->idx];
708
709 if (attr->type == UJSON_VOID)
710 return 1;
711
712 if (attr->type == res->type)
713 return 1;
714
715 if (attr->type == UJSON_FLOAT &&
716 res->type == UJSON_INT)
717 return 1;
718
719 ujson_warn(buf, "Wrong '%s' type expected %s",
720 attr->key, ujson_type_name(attr->type));
721 } else {
722 if (!skip_obj_val(buf))
723 return 0;
724
725 if (ign && ujson_obj_lookup(ign, res->id) == (size_t)-1)
726 ujson_warn(buf, "Unexpected key '%s'", res->id);
727 }
728
729 if (obj_pre_next(buf, res))
730 return 0;
731 }
732 }
733
check_err(ujson_reader * buf,struct ujson_val * res)734 static int check_err(ujson_reader *buf, struct ujson_val *res)
735 {
736 if (ujson_reader_err(buf)) {
737 res->type = UJSON_VOID;
738 return 1;
739 }
740
741 return 0;
742 }
743
ujson_obj_next_filter(ujson_reader * buf,struct ujson_val * res,const struct ujson_obj * obj,const struct ujson_obj * ign)744 int ujson_obj_next_filter(ujson_reader *buf, struct ujson_val *res,
745 const struct ujson_obj *obj, const struct ujson_obj *ign)
746 {
747 if (check_err(buf, res))
748 return 0;
749
750 if (obj_pre_next(buf, res))
751 return 0;
752
753 return obj_next_filter(buf, res, obj, ign);
754 }
755
ujson_obj_next(ujson_reader * buf,struct ujson_val * res)756 int ujson_obj_next(ujson_reader *buf, struct ujson_val *res)
757 {
758 if (check_err(buf, res))
759 return 0;
760
761 if (obj_pre_next(buf, res))
762 return 0;
763
764 return obj_next(buf, res);
765 }
766
any_first(ujson_reader * buf,char b)767 static int any_first(ujson_reader *buf, char b)
768 {
769 if (eatws(buf)) {
770 ujson_err(buf, "Unexpected end");
771 return 1;
772 }
773
774 if (!eatb(buf, b)) {
775 ujson_err(buf, "Expected '%c'", b);
776 return 1;
777 }
778
779 buf->depth++;
780
781 if (buf->depth > buf->max_depth) {
782 ujson_err(buf, "Recursion too deep");
783 return 1;
784 }
785
786 return 0;
787 }
788
ujson_obj_first_filter(ujson_reader * buf,struct ujson_val * res,const struct ujson_obj * obj,const struct ujson_obj * ign)789 int ujson_obj_first_filter(ujson_reader *buf, struct ujson_val *res,
790 const struct ujson_obj *obj, const struct ujson_obj *ign)
791 {
792 if (check_err(buf, res))
793 return 0;
794
795 if (any_first(buf, '{'))
796 return 0;
797
798 if (check_end(buf, res, '}'))
799 return 0;
800
801 return obj_next_filter(buf, res, obj, ign);
802 }
803
ujson_obj_first(ujson_reader * buf,struct ujson_val * res)804 int ujson_obj_first(ujson_reader *buf, struct ujson_val *res)
805 {
806 if (check_err(buf, res))
807 return 0;
808
809 if (any_first(buf, '{'))
810 return 0;
811
812 if (check_end(buf, res, '}'))
813 return 0;
814
815 return obj_next(buf, res);
816 }
817
arr_next(ujson_reader * buf,struct ujson_val * res)818 static int arr_next(ujson_reader *buf, struct ujson_val *res)
819 {
820 return get_value(buf, res);
821 }
822
ujson_arr_first(ujson_reader * buf,struct ujson_val * res)823 int ujson_arr_first(ujson_reader *buf, struct ujson_val *res)
824 {
825 if (check_err(buf, res))
826 return 0;
827
828 if (any_first(buf, '['))
829 return 0;
830
831 if (check_end(buf, res, ']'))
832 return 0;
833
834 return arr_next(buf, res);
835 }
836
ujson_arr_next(ujson_reader * buf,struct ujson_val * res)837 int ujson_arr_next(ujson_reader *buf, struct ujson_val *res)
838 {
839 if (check_err(buf, res))
840 return 0;
841
842 if (check_end(buf, res, ']'))
843 return 0;
844
845 if (pre_next(buf, res))
846 return 0;
847
848 return arr_next(buf, res);
849 }
850
ujson_err_va(ujson_reader * buf,const char * fmt,va_list va)851 static void ujson_err_va(ujson_reader *buf, const char *fmt, va_list va)
852 {
853 vsnprintf(buf->err, UJSON_ERR_MAX, fmt, va);
854 }
855
ujson_err(ujson_reader * buf,const char * fmt,...)856 void ujson_err(ujson_reader *buf, const char *fmt, ...)
857 {
858 va_list va;
859
860 va_start(va, fmt);
861 ujson_err_va(buf, fmt, va);
862 va_end(va);
863 }
864
vprintf_line(ujson_reader * buf,const char * fmt,va_list va)865 static void vprintf_line(ujson_reader *buf, const char *fmt, va_list va)
866 {
867 char line[UJSON_ERR_MAX+1];
868
869 vsnprintf(line, sizeof(line), fmt, va);
870
871 line[UJSON_ERR_MAX] = 0;
872
873 buf->err_print(buf->err_print_priv, line);
874 }
875
printf_line(ujson_reader * buf,const char * fmt,...)876 static void printf_line(ujson_reader *buf, const char *fmt, ...)
877 {
878 va_list va;
879
880 va_start(va, fmt);
881 vprintf_line(buf, fmt, va);
882 va_end(va);
883 }
884
printf_json_line(ujson_reader * buf,size_t line_nr,const char * buf_pos)885 static void printf_json_line(ujson_reader *buf, size_t line_nr, const char *buf_pos)
886 {
887 char line[UJSON_ERR_MAX+1];
888 size_t plen, i;
889
890 plen = sprintf(line, "%03zu: ", line_nr);
891
892 for (i = 0; i < UJSON_ERR_MAX-plen && buf_pos[i] && buf_pos[i] != '\n'; i++)
893 line[i+plen] = buf_pos[i];
894
895 line[i+plen] = 0;
896
897 buf->err_print(buf->err_print_priv, line);
898 }
899
print_arrow(ujson_reader * buf,const char * buf_pos,size_t count)900 static void print_arrow(ujson_reader *buf, const char *buf_pos, size_t count)
901 {
902 char line[count + 7];
903 size_t i;
904
905 /* The '000: ' prefix */
906 for (i = 0; i <= 5; i++)
907 line[i] = ' ';
908
909 for (i = 0; i < count; i++)
910 line[i+5] = buf_pos[i] == '\t' ? '\t' : ' ';
911
912 line[count+5] = '^';
913 line[count+6] = 0;
914
915 buf->err_print(buf->err_print_priv, line);
916 }
917
918 #define ERR_LINES 10
919
920 #define MIN(A, B) ((A < B) ? (A) : (B))
921
print_snippet(ujson_reader * buf,const char * type)922 static void print_snippet(ujson_reader *buf, const char *type)
923 {
924 ssize_t i;
925 const char *lines[ERR_LINES] = {};
926 size_t cur_line = 0;
927 size_t cur_off = 0;
928 size_t last_off = buf->off;
929
930 for (;;) {
931 lines[(cur_line++) % ERR_LINES] = buf->json + cur_off;
932
933 while (cur_off < buf->len && buf->json[cur_off] != '\n')
934 cur_off++;
935
936 if (cur_off >= buf->off)
937 break;
938
939 cur_off++;
940 last_off = buf->off - cur_off;
941 }
942
943 printf_line(buf, "%s at line %03zu", type, cur_line);
944 buf->err_print(buf->err_print_priv, "");
945
946 size_t idx = 0;
947
948 for (i = MIN(ERR_LINES, cur_line); i > 0; i--) {
949 idx = (cur_line - i) % ERR_LINES;
950 printf_json_line(buf, cur_line - i + 1, lines[idx]);
951 }
952
953 print_arrow(buf, lines[idx], last_off);
954 }
955
ujson_err_print(ujson_reader * buf)956 void ujson_err_print(ujson_reader *buf)
957 {
958 if (!buf->err_print)
959 return;
960
961 print_snippet(buf, "Parse error");
962 buf->err_print(buf->err_print_priv, buf->err);
963 }
964
ujson_warn(ujson_reader * buf,const char * fmt,...)965 void ujson_warn(ujson_reader *buf, const char *fmt, ...)
966 {
967 va_list va;
968
969 if (buf->flags & UJSON_READER_STRICT) {
970 va_start(va, fmt);
971 ujson_err_va(buf, fmt, va);
972 va_end(va);
973 return;
974 }
975
976 if (!buf->err_print)
977 return;
978
979 print_snippet(buf, "Warning");
980
981 va_start(va, fmt);
982 vprintf_line(buf, fmt, va);
983 va_end(va);
984 }
985
ujson_print(void * err_print_priv,const char * line)986 void ujson_print(void *err_print_priv, const char *line)
987 {
988 fputs(line, err_print_priv);
989 putc('\n', err_print_priv);
990 }
991
ujson_reader_load(const char * path)992 ujson_reader *ujson_reader_load(const char *path)
993 {
994 int fd = open(path, O_RDONLY);
995 ujson_reader *ret;
996 ssize_t res;
997 off_t len, off = 0;
998
999 if (fd < 0)
1000 return NULL;
1001
1002 len = lseek(fd, 0, SEEK_END);
1003 if (len == (off_t)-1) {
1004 fprintf(stderr, "lseek() failed\n");
1005 goto err0;
1006 }
1007
1008 if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
1009 fprintf(stderr, "lseek() failed\n");
1010 goto err0;
1011 }
1012
1013 ret = malloc(sizeof(ujson_reader) + len + 1);
1014 if (!ret) {
1015 fprintf(stderr, "malloc() failed\n");
1016 goto err0;
1017 }
1018
1019 memset(ret, 0, sizeof(*ret));
1020
1021 ret->buf[len] = 0;
1022 ret->len = len;
1023 ret->max_depth = UJSON_RECURSION_MAX;
1024 ret->json = ret->buf;
1025 ret->err_print = UJSON_ERR_PRINT;
1026 ret->err_print_priv = UJSON_ERR_PRINT_PRIV;
1027
1028 while (off < len) {
1029 res = read(fd, ret->buf + off, len - off);
1030 if (res < 0) {
1031 fprintf(stderr, "read() failed\n");
1032 goto err1;
1033 }
1034
1035 off += res;
1036 }
1037
1038 close(fd);
1039
1040 return ret;
1041 err1:
1042 free(ret);
1043 err0:
1044 close(fd);
1045 return NULL;
1046 }
1047
ujson_reader_finish(ujson_reader * self)1048 void ujson_reader_finish(ujson_reader *self)
1049 {
1050 if (ujson_reader_err(self))
1051 ujson_err_print(self);
1052 else if (!ujson_reader_consumed(self)) {
1053 ujson_warn(self, "Garbage after JSON string!");
1054
1055 if (ujson_reader_err(self))
1056 ujson_err_print(self);
1057 }
1058 }
1059
ujson_reader_free(ujson_reader * buf)1060 void ujson_reader_free(ujson_reader *buf)
1061 {
1062 free(buf);
1063 }
1064
ujson_val_alloc(size_t buf_size)1065 ujson_val *ujson_val_alloc(size_t buf_size)
1066 {
1067 buf_size = buf_size == 0 ? 4096 : buf_size;
1068 ujson_val *ret;
1069
1070 ret = malloc(sizeof(ujson_val) + buf_size);
1071 if (!ret)
1072 return NULL;
1073
1074 memset(ret, 0, sizeof(ujson_val) + buf_size);
1075
1076 ret->buf = ret->buf__;
1077 ret->buf_size = buf_size;
1078
1079 return ret;
1080 }
1081
ujson_val_free(ujson_val * self)1082 void ujson_val_free(ujson_val *self)
1083 {
1084 free(self);
1085 }
1086