Mercurial > dovecot > core-2.2
changeset 15436:9a31c44c1184
JSON parser fixes
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 29 Nov 2012 07:30:23 +0200 |
parents | 86572582647e |
children | 014be18f7130 |
files | src/lib/json-parser.c src/lib/test-json-parser.c |
diffstat | 2 files changed, 59 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/json-parser.c Thu Nov 29 06:26:29 2012 +0200 +++ b/src/lib/json-parser.c Thu Nov 29 07:30:23 2012 +0200 @@ -148,11 +148,11 @@ parser->data++; str_truncate(parser->value, 0); - for (; parser->data != parser->end; parser->data++) { + for (; parser->data != parser->end; parser->data++) { if (*parser->data == '"') { parser->data++; *value_r = str_c(parser->value); - return 0; + return 1; } if (*parser->data != '\\') str_append_c(parser->value, *parser->data); @@ -179,8 +179,12 @@ str_append_c(parser->value, '\t'); break; case 'u': - if (parser->end - parser->data < 4) - return -1; + parser->data++; + if (parser->end - parser->data < 4) { + /* wait for more data */ + parser->data = parser->end; + return 0; + } uni_ucs4_to_utf8_c(hex2dec(parser->data, 4), parser->value); parser->data += 3; @@ -190,64 +194,69 @@ } } } - return -1; + return 0; } static int json_parse_digits(struct json_parser *parser) { - if (parser->data == parser->end || - *parser->data < '0' || *parser->data > '9') + if (parser->data == parser->end) + return 0; + if (*parser->data < '0' || *parser->data > '9') return -1; while (parser->data != parser->end && *parser->data >= '0' && *parser->data <= '9') str_append_c(parser->value, *parser->data++); - return 0; + return 1; } static int json_parse_int(struct json_parser *parser) { + int ret; + if (*parser->data == '-') { str_append_c(parser->value, *parser->data++); if (parser->data == parser->end) - return -1; + return 0; } if (*parser->data == '0') str_append_c(parser->value, *parser->data++); else { - if (json_parse_digits(parser) < 0) - return -1; + if ((ret = json_parse_digits(parser)) <= 0) + return ret; } - return 0; + return 1; } static int json_parse_number(struct json_parser *parser, const char **value_r) { + int ret; + str_truncate(parser->value, 0); - if (json_parse_int(parser) < 0) - return -1; + if ((ret = json_parse_int(parser)) <= 0) + return ret; if (parser->data != parser->end && *parser->data == '.') { /* frac */ str_append_c(parser->value, *parser->data++); - if (json_parse_digits(parser) < 0) - return -1; + if ((ret = json_parse_digits(parser)) <= 0) + return ret; } if (parser->data != parser->end && (*parser->data == 'e' || *parser->data == 'E')) { /* exp */ str_append_c(parser->value, *parser->data++); if (parser->data == parser->end) - return -1; + return 0; if (*parser->data == '+' || *parser->data == '-') str_append_c(parser->value, *parser->data++); - if (json_parse_digits(parser) < 0) - return -1; + if ((ret = json_parse_digits(parser)) <= 0) + return ret; } if (parser->data == parser->end && !parser->input->eof) - return -1; + return 0; *value_r = str_c(parser->value); - return 0; + return 1; } static int json_parse_atom(struct json_parser *parser, const char *atom) @@ -256,16 +265,17 @@ avail = parser->end - parser->data; if (avail < len) { - if (memcmp(parser->data, atom, avail) == 0) { - /* everything matches so far, but we need more data */ - parser->data += avail; - } - return -1; + if (memcmp(parser->data, atom, avail) != 0) + return -1; + + /* everything matches so far, but we need more data */ + parser->data += avail; + return 0; } if (memcmp(parser->data, atom, len) != 0) return -1; parser->data += len; - return 0; + return 1; } static int @@ -290,6 +300,8 @@ json_try_parse_next(struct json_parser *parser, enum json_type *type_r, const char **value_r) { + int ret; + if (!json_parse_whitespace(parser)) return -1; @@ -304,11 +316,7 @@ json_parser_update_input_pos(parser); return json_try_parse_next(parser, type_r, value_r); case JSON_STATE_OBJECT_VALUE: - if (json_parse_string(parser, value_r) == 0) - *type_r = JSON_TYPE_STRING; - else if (json_parse_number(parser, value_r) == 0) - *type_r = JSON_TYPE_NUMBER; - else if (*parser->data == '[') { + if (*parser->data == '[') { parser->error = "Arrays not supported"; return -1; } else if (*parser->data == '{') { @@ -318,19 +326,28 @@ json_parser_update_input_pos(parser); *type_r = JSON_TYPE_OBJECT; return 0; - } else if (json_parse_atom(parser, "true") == 0) { + } + if ((ret = json_parse_string(parser, value_r)) >= 0) { + *type_r = JSON_TYPE_STRING; + } else if ((ret = json_parse_number(parser, value_r)) >= 0) { + *type_r = JSON_TYPE_NUMBER; + } else if ((ret = json_parse_atom(parser, "true")) >= 0) { *type_r = JSON_TYPE_TRUE; *value_r = "true"; - } else if (json_parse_atom(parser, "false") == 0) { + } else if ((ret = json_parse_atom(parser, "false")) >= 0) { *type_r = JSON_TYPE_FALSE; *value_r = "false"; - } else if (json_parse_atom(parser, "null") == 0) { + } else if ((ret = json_parse_atom(parser, "null")) >= 0) { *type_r = JSON_TYPE_NULL; *value_r = NULL; } else { parser->error = "Invalid data as value"; return -1; } + if (ret == 0) { + i_assert(parser->data == parser->end); + return -1; + } parser->state = parser->state == JSON_STATE_ROOT ? JSON_STATE_DONE : JSON_STATE_OBJECT_VALUE_NEXT; @@ -341,7 +358,7 @@ parser->state = JSON_STATE_OBJECT_KEY; /* fall through */ case JSON_STATE_OBJECT_KEY: - if (json_parse_string(parser, value_r) < 0) { + if (json_parse_string(parser, value_r) <= 0) { parser->error = "Expected string as object key"; return -1; }
--- a/src/lib/test-json-parser.c Thu Nov 29 06:26:29 2012 +0200 +++ b/src/lib/test-json-parser.c Thu Nov 29 07:30:23 2012 +0200 @@ -20,7 +20,8 @@ " \"sub2\":-12.456,\n" " \"sub3\":12.456e9,\n" " \"sub4\":0.456e-789" - "}" + "}," + "\"key9\": \"\\\\\\\"\\b\\f\\n\\r\\t\\u0001\uffff\"" "}\n"; static struct { @@ -53,7 +54,9 @@ { JSON_TYPE_NUMBER, "12.456e9" }, { JSON_TYPE_OBJECT_KEY, "sub4" }, { JSON_TYPE_NUMBER, "0.456e-789" }, - { JSON_TYPE_OBJECT_END, NULL } + { JSON_TYPE_OBJECT_END, NULL }, + { JSON_TYPE_OBJECT_KEY, "key9" }, + { JSON_TYPE_STRING, "\\\"\b\f\n\r\t\001\xef\xbf\xbf" } }; static void test_json_parser_success(bool full_size) @@ -93,6 +96,6 @@ void test_json_parser(void) { + test_json_parser_success(FALSE); test_json_parser_success(TRUE); - test_json_parser_success(FALSE); }