json-parser.c revision c3393007354b7ab607449fea0c3d7088193ab208
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int json_parser_read_more(struct json_parser *parser)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher uoff_t cur_highwater = parser->input->v_offset +
f775337a7d4ca1c0be8eab683d0d753cbaee49e2Lukas Slebodnik i_assert(parser->highwater_offset <= cur_highwater);
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek /* call it once more to finish any pending number */
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek } else if (ret <= 0) {
48130eef6c5c64a07094b9e8582ba358b2048f24Jakub Hrozek i_assert(parser->highwater_offset < cur_highwater);
faa16fc9f0c9a02b26497e7cf148a92586144c08David Disseldorp parser->start = parser->data = i_stream_get_data(parser->input, &size);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void json_parser_update_input_pos(struct json_parser *parser)
d921c1eba437662437847279f251a0a5d8f70127Maxim i_stream_skip(parser->input, parser->data - parser->start);
d921c1eba437662437847279f251a0a5d8f70127Maxim parser->start = parser->data = i_stream_get_data(parser->input, &size);
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer /* we skipped over some data and there's still data left.
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer no need to read() the next time. */
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer parser->highwater_offset = parser->input->v_offset;
327127bb7fcc07f882209f029e14026de1b23c94Maximstruct json_parser *json_parser_init(struct istream *input)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct json_parser *json_parser_init_flags(struct istream *input,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher parser->value = str_new(default_pool, 128);
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher if ((flags & JSON_PARSER_NO_ROOT_OBJECT) != 0)
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzkeint json_parser_deinit(struct json_parser **_parser, const char **error_r)
068dbee9ca7bf5b37330eff91c94ae10f288d09fJakub Hrozek /* actual parser error */
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek *error_r = t_strdup_printf("read(%s) failed: %s",
e07a94a66985b674c5df11ca466792902164c4e2George McCollister !i_stream_have_bytes_left(parser->input) &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool json_parse_whitespace(struct json_parser *parser)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (; parser->data != parser->end; parser->data++) {
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozekstatic int json_skip_string(struct json_parser *parser)
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke for (; parser->data != parser->end; parser->data++) {
574a1c20f114851071ae74112b34488c3d1aeeb3Ondrej Kosstatic int json_parse_unicode_escape(struct json_parser *parser)
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek /* wait for more data */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher parser->error = "Invalid unicode escape seen";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* possible surrogate pair */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* wait for more data */
6b01dae732eedee808f32a9cdd4b5656a9f839c4Jakub Hrozek /* wait for more data */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* wait for more data */
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek if (parser->data[0] != '\\' || parser->data[1] != 'u' ||
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek "but not followed by low surrogate",
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnik t_strdup_printf("Invalid unicode character U+%04x", chr);
827dd342494de18099dddd0272c1a85f10703556Lukas Slebodnikstatic int json_parse_string(struct json_parser *parser, bool allow_skip,
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik for (; parser->data != parser->end; parser->data++) {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik if ((ret=json_parse_unicode_escape(parser)) <= 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherjson_parse_digits(struct json_parser *parser)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*parser->data < '0' || *parser->data > '9')
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozekstatic int json_parse_int(struct json_parser *parser)
e07a94a66985b674c5df11ca466792902164c4e2George McCollister str_append_c(parser->value, *parser->data++);
336879aabae137f9a81304f147fb0d43001654b0Simo Sorcestatic int json_parse_number(struct json_parser *parser, const char **value_r)
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce if (parser->data != parser->end && *parser->data == '.') {
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik str_append_c(parser->value, *parser->data++);
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik (*parser->data == 'e' || *parser->data == 'E')) {
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik str_append_c(parser->value, *parser->data++);
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik if (*parser->data == '+' || *parser->data == '-')
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik str_append_c(parser->value, *parser->data++);
aac071824f6c98003f30d49ab440c15b4b53692cLukas Slebodnik if (parser->data == parser->end && !parser->input->eof)
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnikstatic int json_parse_atom(struct json_parser *parser, const char *atom)
356eef72675cde4dc5627c1e2f1a01846ec6eb1dLukas Slebodnik /* everything matches so far, but we need more data */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int json_parse_denest(struct json_parser *parser)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher nested_states = array_get(&parser->nesting, &count);
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher /* closing root */
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek if ((parser->flags & JSON_PARSER_NO_ROOT_OBJECT) == 0)
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek /* we want to return the ending "]" or "}" to caller */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* closing a nested object */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ?
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bosejson_parse_close_object(struct json_parser *parser, enum json_type *type_r)
const char **value_r)
int ret;
case JSON_STATE_ROOT:
case JSON_STATE_OBJECT_VALUE:
case JSON_STATE_ARRAY_VALUE:
case JSON_STATE_VALUE:
if (ret == 0) {
case JSON_STATE_OBJECT_VALUE:
case JSON_STATE_ARRAY_VALUE:
case JSON_STATE_VALUE:
i_unreached();
case JSON_STATE_OBJECT_OPEN:
case JSON_STATE_OBJECT_KEY:
case JSON_STATE_OBJECT_COLON:
case JSON_STATE_OBJECT_NEXT:
case JSON_STATE_ARRAY_OPEN:
case JSON_STATE_ARRAY_NEXT:
case JSON_STATE_DONE:
const char **value_r)
int ret;
if (ret > 0)
return ret;
int ret;
return ret;
switch (src) {
size_t i;
int bytes = 0;
for (i = 0; i < size;) {
i += bytes;