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