json-parser.c revision 2eccb2637d0153bb7f9ad39a70f254cece74342c
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainenstatic int json_parser_read_more(struct json_parser *parser)
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen uoff_t cur_highwater = parser->input->v_offset +
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(parser->highwater_offset <= cur_highwater);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (parser->highwater_offset == cur_highwater) {
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen i_assert(parser->highwater_offset < cur_highwater);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen parser->start = parser->data = i_stream_get_data(parser->input, &size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic void json_parser_update_input_pos(struct json_parser *parser)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen i_stream_skip(parser->input, parser->data - parser->start);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen parser->start = parser->data = i_stream_get_data(parser->input, &size);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen /* we skipped over some data and there's still data left.
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen no need to read() the next time. */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen parser->highwater_offset = parser->input->v_offset;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstruct json_parser *json_parser_init(struct istream *input)
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainenint json_parser_deinit(struct json_parser **_parser, const char **error_r)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* actual parser error */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen } else if (parser->input->stream_errno != 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *error_r = t_strdup_printf("read(%s) failed: %m",
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenstatic bool json_parse_whitespace(struct json_parser *parser)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen for (; parser->data != parser->end; parser->data++) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstatic int json_skip_string(struct json_parser *parser)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen for (; parser->data != parser->end; parser->data++) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenstatic int json_parse_string(struct json_parser *parser, bool allow_skip,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen const char **value_r)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen for (; parser->data != parser->end; parser->data++) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* wait for more data */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (*parser->data < '0' || *parser->data > '9')
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int json_parse_int(struct json_parser *parser)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int json_parse_number(struct json_parser *parser, const char **value_r)
871c7b8969e8627dc4c8b3e56fd126f948e6bce6Timo Sirainen if (parser->data != parser->end && *parser->data == '.') {
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen (*parser->data == 'e' || *parser->data == 'E')) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (*parser->data == '+' || *parser->data == '-')
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (parser->data == parser->end && !parser->input->eof)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int json_parse_atom(struct json_parser *parser, const char *atom)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* everything matches so far, but we need more data */
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainenjson_parse_object_close(struct json_parser *parser, enum json_type *type_r)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* closing a nested object */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenjson_try_parse_next(struct json_parser *parser, enum json_type *type_r,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen const char **value_r)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->error = "Object doesn't begin with '{'";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = json_parse_string(parser, TRUE, value_r)) >= 0) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen } else if ((ret = json_parse_number(parser, value_r)) >= 0) {
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen } else if ((ret = json_parse_atom(parser, "true")) >= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if ((ret = json_parse_atom(parser, "false")) >= 0) {
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen } else if ((ret = json_parse_atom(parser, "null")) >= 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (parser->skipping && *type_r == JSON_TYPE_STRING) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* a large string that we want to skip over. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->state = parser->state == JSON_STATE_ROOT ?
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen return json_parse_object_close(parser, type_r);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* fall through */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (json_parse_string(parser, FALSE, value_r) <= 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->error = "Expected string as object key";
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (parser->skipping && parser->nested_skip_count == 0) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen /* we skipped over the previous value */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return json_parse_object_close(parser, type_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->error = "Expected ',' or '}' after object value";
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainenint json_parse_next(struct json_parser *parser, enum json_type *type_r,
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen const char **value_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((ret = json_parser_read_more(parser)) > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((ret = json_try_parse_next(parser, type_r, value_r)) == 0)
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen /* parsing probably failed because there wasn't enough input.
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen reset the error and try reading more. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid json_parse_skip_next(struct json_parser *parser)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void json_strinput_destroyed(struct json_parser *parser)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenjson_try_parse_stream_start(struct json_parser *parser,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (parser->state == JSON_STATE_OBJECT_COLON) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->strinput = i_stream_create_jsonstr(parser->input);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_stream_set_destroy_callback(parser->strinput,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint json_parse_next_stream(struct json_parser *parser,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen while ((ret = json_parser_read_more(parser)) > 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (json_try_parse_stream_start(parser, input_r) == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* parsing probably failed because there wasn't enough input.
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen reset the error and try reading more. */