json-parser.c revision 32bd32dcc845cd0c00d5617aea1ffbe45522b413
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenstatic int json_parser_read_more(struct json_parser *parser)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen uoff_t cur_highwater = parser->input->v_offset +
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen i_assert(parser->highwater_offset <= cur_highwater);
c991d8c2c0d5d6c025e24fc00cb06dd61c42456dTimo Sirainen if (parser->highwater_offset == cur_highwater) {
c991d8c2c0d5d6c025e24fc00cb06dd61c42456dTimo Sirainen /* call it once more to finish any pending number */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen } else if (ret <= 0) {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen i_assert(parser->highwater_offset < cur_highwater);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen parser->start = parser->data = i_stream_get_data(parser->input, &size);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenstatic void json_parser_update_input_pos(struct json_parser *parser)
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen i_stream_skip(parser->input, parser->data - parser->start);
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen parser->start = parser->data = i_stream_get_data(parser->input, &size);
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen /* we skipped over some data and there's still data left.
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen no need to read() the next time. */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen parser->highwater_offset = parser->input->v_offset;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainenstruct json_parser *json_parser_init(struct istream *input)
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainenstruct json_parser *json_parser_init_flags(struct istream *input,
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen if ((flags & JSON_PARSER_NO_ROOT_OBJECT) != 0)
ba66ac5557ca97d8a6fe5d524056264a9f92243cPhil Carmodyint json_parser_deinit(struct json_parser **_parser, const char **error_r)
ba66ac5557ca97d8a6fe5d524056264a9f92243cPhil Carmody /* actual parser error */
ba66ac5557ca97d8a6fe5d524056264a9f92243cPhil Carmody *error_r = t_strdup_printf("read(%s) failed: %s",
ba66ac5557ca97d8a6fe5d524056264a9f92243cPhil Carmodystatic bool json_parse_whitespace(struct json_parser *parser)
ba66ac5557ca97d8a6fe5d524056264a9f92243cPhil Carmody for (; parser->data != parser->end; parser->data++) {
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainenstatic int json_skip_string(struct json_parser *parser)
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen for (; parser->data != parser->end; parser->data++) {
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainenstatic int json_parse_unicode_escape(struct json_parser *parser)
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen /* wait for more data */
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen /* possible surrogate pair */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* wait for more data */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* wait for more data */
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen /* wait for more data */
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen if (parser->data[0] != '\\' || parser->data[1] != 'u' ||
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen t_strdup_printf("High surrogate 0x%04x seen, "
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen "but not followed by low surrogate",
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen t_strdup_printf("Invalid unicode character U+%04x", chr);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenstatic int json_parse_string(struct json_parser *parser, bool allow_skip,
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen const char **value_r)
4c9a72e0988d462df49810984dc93b3fd4a24c23Timo Sirainen for (; parser->data != parser->end; parser->data++) {
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen if ((ret=json_parse_unicode_escape(parser)) <= 0)
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen if (*parser->data < '0' || *parser->data > '9')
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainenstatic int json_parse_int(struct json_parser *parser)
199566f5a171b2c43b9a5254634f6bf47b8baca8Timo Sirainenstatic int json_parse_number(struct json_parser *parser, const char **value_r)
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen if (parser->data != parser->end && *parser->data == '.') {
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen (*parser->data == 'e' || *parser->data == 'E')) {
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen if (*parser->data == '+' || *parser->data == '-')
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen if (parser->data == parser->end && !parser->input->eof)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenstatic int json_parse_atom(struct json_parser *parser, const char *atom)
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen /* everything matches so far, but we need more data */
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainenstatic int json_parse_denest(struct json_parser *parser)
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen nested_states = array_get(&parser->nesting, &count);
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen /* closing root */
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if ((parser->flags & JSON_PARSER_NO_ROOT_OBJECT) == 0)
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen /* we want to return the ending "]" or "}" to caller */
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen /* closing a nested object */
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ?
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenjson_parse_close_object(struct json_parser *parser, enum json_type *type_r)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenjson_parse_close_array(struct json_parser *parser, enum json_type *type_r)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenstatic void json_parser_object_open(struct json_parser *parser)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen array_append(&parser->nesting, &parser->state, 1);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenjson_try_parse_next(struct json_parser *parser, enum json_type *type_r,
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen const char **value_r)
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen parser->error = "Object doesn't begin with '{'";
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen array_append(&parser->nesting, &parser->state, 1);
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;) {
if (bytes > 0) {
i += bytes;