Merge pull request #644 from ekaitz-zarraga/master

Support multiple \u sequences and add error checking
This commit is contained in:
Alex Shinn 2020-05-22 10:11:10 +08:00 committed by GitHub
commit 278657eea4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 4 deletions

View file

@ -8,6 +8,9 @@
(test 1 (parse-json "1")) (test 1 (parse-json "1"))
(test 1.5 (parse-json "1.5")) (test 1.5 (parse-json "1.5"))
(test 1000.0 (parse-json "1e3")) (test 1000.0 (parse-json "1e3"))
(test "á" (parse-json "\"\\u00e1\""))
(test "𐐷" (parse-json "\"\\uD801\\uDC37\""))
(test "😐" (parse-json "\"\\uD83D\\uDE10\""))
(test '((glossary (test '((glossary
(title . "example glossary") (title . "example glossary")
(GlossDiv (GlossDiv

View file

@ -54,11 +54,24 @@ sexp parse_json_literal (sexp ctx, sexp self, sexp str, const char* s, int* i, c
return res; return res;
} }
#define USEQ_LEN 4
long decode_useq(const char* s) {
char utf_tmp[USEQ_LEN+1];
for (int iter=0; iter!=USEQ_LEN; iter++) {
if (!isxdigit(s[iter])) {
return -1;
}
}
strncpy(utf_tmp, s, USEQ_LEN);
return strtol(utf_tmp, NULL, 16);
}
sexp parse_json_string (sexp ctx, sexp self, sexp str, const char* s, int* i, const int len) { sexp parse_json_string (sexp ctx, sexp self, sexp str, const char* s, int* i, const int len) {
sexp_gc_var2(res, tmp); sexp_gc_var2(res, tmp);
sexp_gc_preserve2(ctx, res, tmp); sexp_gc_preserve2(ctx, res, tmp);
char utf_tmp[5];
int from = *i, to = *i; int from = *i, to = *i;
long utfchar, utfchar2;
res = SEXP_NULL; res = SEXP_NULL;
for ( ; s[to] != '"'; ++to) { for ( ; s[to] != '"'; ++to) {
if (to+1 >= len) { if (to+1 >= len) {
@ -80,10 +93,29 @@ sexp parse_json_string (sexp ctx, sexp self, sexp str, const char* s, int* i, co
from = to+1; from = to+1;
break; break;
case 'u': case 'u':
strncpy(utf_tmp, s+to+1, 5); utfchar = decode_useq(s+to+1);
tmp = sexp_make_string(ctx, sexp_make_fixnum(1), sexp_make_character(strtoll(utf_tmp, NULL, 16))); if (utfchar == -1) {
res = sexp_json_exception(ctx, self, "invalid \\u sequence at", str, *i);
goto except;
}
to = to+USEQ_LEN;
if ( 0xd800 <= utfchar && utfchar <= 0xdbff && s[to+2] == 'u') {
utfchar2 = decode_useq(s+to+3);
if (utfchar2 == -1) {
res = sexp_json_exception(ctx, self, "invalid \\u sequence at", str, *i);
goto except;
}
if ( 0xdc00 <= utfchar2 && utfchar <=0xdfff ) {
utfchar = 0x10000 + (((utfchar - 0xd800) << 10) | (utfchar2 - 0xdc00));
to = to + USEQ_LEN +2;
}
}
tmp = sexp_make_string(ctx, sexp_make_fixnum(1), sexp_make_character(utfchar));
res = sexp_cons(ctx, tmp, res); res = sexp_cons(ctx, tmp, res);
from = to+5; from = to + 1;
break; break;
default: default:
from = to; from = to;
@ -91,6 +123,7 @@ sexp parse_json_string (sexp ctx, sexp self, sexp str, const char* s, int* i, co
} }
} }
} }
except:
if (!sexp_exceptionp(res)) { if (!sexp_exceptionp(res)) {
tmp = sexp_c_string(ctx, s+from, to-from); tmp = sexp_c_string(ctx, s+from, to-from);
if (res == SEXP_NULL) { if (res == SEXP_NULL) {

View file

@ -40,6 +40,7 @@
(rename (chibi generic-test) (run-tests run-generic-tests)) (rename (chibi generic-test) (run-tests run-generic-tests))
(rename (chibi io-test) (run-tests run-io-tests)) (rename (chibi io-test) (run-tests run-io-tests))
(rename (chibi iset-test) (run-tests run-iset-tests)) (rename (chibi iset-test) (run-tests run-iset-tests))
(rename (chibi json-test) (run-tests run-json-tests))
(rename (chibi log-test) (run-tests run-log-tests)) (rename (chibi log-test) (run-tests run-log-tests))
(rename (chibi loop-test) (run-tests run-loop-tests)) (rename (chibi loop-test) (run-tests run-loop-tests))
(rename (chibi match-test) (run-tests run-match-tests)) (rename (chibi match-test) (run-tests run-match-tests))
@ -100,6 +101,7 @@
(run-generic-tests) (run-generic-tests)
(run-io-tests) (run-io-tests)
(run-iset-tests) (run-iset-tests)
(run-json-tests)
(run-log-tests) (run-log-tests)
(run-loop-tests) (run-loop-tests)
(run-match-tests) (run-match-tests)