json-parser.c revision 2eccb2637d0153bb7f9ad39a70f254cece74342c
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "str.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hex-dec.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "unichar.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-jsonstr.h"
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#include "json-parser.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenenum json_state {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen JSON_STATE_ROOT = 0,
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen JSON_STATE_OBJECT_OPEN,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen JSON_STATE_OBJECT_KEY,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen JSON_STATE_OBJECT_COLON,
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen JSON_STATE_OBJECT_VALUE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen JSON_STATE_OBJECT_VALUE_NEXT,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen JSON_STATE_SKIP_STRING,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen JSON_STATE_DONE
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenstruct json_parser {
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen struct istream *input;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen uoff_t highwater_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *start, *end, *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *error;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen string_t *value;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream *strinput;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum json_state state;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int nested_object_count;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen unsigned int nested_skip_count;
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen bool skipping;
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen};
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainenstatic int json_parser_read_more(struct json_parser *parser)
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen{
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen uoff_t cur_highwater = parser->input->v_offset +
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen i_stream_get_data_size(parser->input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ssize_t ret;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(parser->highwater_offset <= cur_highwater);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen if (parser->error != NULL)
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen return -1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (parser->highwater_offset == cur_highwater) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ret = i_stream_read(parser->input);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret == -2) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->error = "Token too large";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ret <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen cur_highwater = parser->input->v_offset +
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_stream_get_data_size(parser->input);
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen i_assert(parser->highwater_offset < cur_highwater);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen parser->highwater_offset = cur_highwater;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen parser->start = parser->data = i_stream_get_data(parser->input, &size);
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen parser->end = parser->start + size;
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen i_assert(size > 0);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return 1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic void json_parser_update_input_pos(struct json_parser *parser)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (parser->data == parser->start)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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 parser->end = parser->start + size;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (size > 0) {
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen /* we skipped over some data and there's still data left.
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen no need to read() the next time. */
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen parser->highwater_offset = 0;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen } else {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen parser->highwater_offset = parser->input->v_offset;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstruct json_parser *json_parser_init(struct istream *input)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen struct json_parser *parser;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen parser = i_new(struct json_parser, 1);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen parser->input = input;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen parser->value = str_new(default_pool, 128);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_stream_ref(input);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return parser;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen}
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainenint json_parser_deinit(struct json_parser **_parser, const char **error_r)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen struct json_parser *parser = *_parser;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen *_parser = NULL;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (parser->error != NULL) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* actual parser error */
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen *error_r = parser->error;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen } else if (parser->input->stream_errno != 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *error_r = t_strdup_printf("read(%s) failed: %m",
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_stream_get_name(parser->input));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen } else if (parser->data == parser->end &&
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen !i_stream_have_bytes_left(parser->input) &&
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen parser->state != JSON_STATE_ROOT &&
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen parser->state != JSON_STATE_DONE) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen *error_r = "Missing '}'";
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen } else {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen *error_r = NULL;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen }
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_stream_unref(&parser->input);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen str_free(&parser->value);
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen i_free(parser);
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen return *error_r != NULL ? -1 : 0;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenstatic bool json_parse_whitespace(struct json_parser *parser)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen for (; parser->data != parser->end; parser->data++) {
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen switch (*parser->data) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen case ' ':
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen case '\t':
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen case '\r':
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen case '\n':
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen default:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen json_parser_update_input_pos(parser);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return TRUE;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen }
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen json_parser_update_input_pos(parser);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return FALSE;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstatic int json_skip_string(struct json_parser *parser)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen for (; parser->data != parser->end; parser->data++) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (*parser->data == '"') {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen parser->data++;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen json_parser_update_input_pos(parser);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return 1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (*parser->data == '\\') {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen switch (*++parser->data) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen case '"':
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen case '\\':
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen case '/':
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen case 'b':
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen case 'f':
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen case 'n':
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen case 'r':
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen case 't':
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen break;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen case 'u':
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen if (parser->end - parser->data < 4)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return -1;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen parser->data += 3;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen break;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen default:
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen json_parser_update_input_pos(parser);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return 0;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenstatic int json_parse_string(struct json_parser *parser, bool allow_skip,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen const char **value_r)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (*parser->data != '"')
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen parser->data++;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (parser->skipping && allow_skip) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen *value_r = NULL;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return json_skip_string(parser);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_truncate(parser->value, 0);
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen for (; parser->data != parser->end; parser->data++) {
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen if (*parser->data == '"') {
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen parser->data++;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *value_r = str_c(parser->value);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (*parser->data != '\\')
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, *parser->data);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen switch (*++parser->data) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case '"':
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case '\\':
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case '/':
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, *parser->data);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case 'b':
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, '\b');
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case 'f':
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, '\f');
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen case 'n':
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen str_append_c(parser->value, '\n');
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen break;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen case 'r':
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen str_append_c(parser->value, '\r');
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case 't':
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen str_append_c(parser->value, '\t');
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen break;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen case 'u':
190237ce467d2389dfb809874b0fec86d3c7968dTimo Sirainen parser->data++;
190237ce467d2389dfb809874b0fec86d3c7968dTimo Sirainen if (parser->end - parser->data < 4) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* wait for more data */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen parser->data = parser->end;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uni_ucs4_to_utf8_c(hex2dec(parser->data, 4),
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen parser->value);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen parser->data += 3;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen break;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen default:
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return -1;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen }
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen }
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen }
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return 0;
b4931fc08faa0079f32f29286f4c3abd0d8788bcTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenjson_parse_digits(struct json_parser *parser)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (parser->data == parser->end)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (*parser->data < '0' || *parser->data > '9')
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return -1;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen while (parser->data != parser->end &&
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *parser->data >= '0' && *parser->data <= '9')
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, *parser->data++);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int json_parse_int(struct json_parser *parser)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen int ret;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (*parser->data == '-') {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, *parser->data++);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (parser->data == parser->end)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 0;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (*parser->data == '0')
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen str_append_c(parser->value, *parser->data++);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen else {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((ret = json_parse_digits(parser)) <= 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return ret;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int json_parse_number(struct json_parser *parser, const char **value_r)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen int ret;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen str_truncate(parser->value, 0);
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen if ((ret = json_parse_int(parser)) <= 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return ret;
871c7b8969e8627dc4c8b3e56fd126f948e6bce6Timo Sirainen if (parser->data != parser->end && *parser->data == '.') {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* frac */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen str_append_c(parser->value, *parser->data++);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((ret = json_parse_digits(parser)) <= 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return ret;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen if (parser->data != parser->end &&
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen (*parser->data == 'e' || *parser->data == 'E')) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* exp */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, *parser->data++);
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen if (parser->data == parser->end)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (*parser->data == '+' || *parser->data == '-')
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen str_append_c(parser->value, *parser->data++);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if ((ret = json_parse_digits(parser)) <= 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return ret;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (parser->data == parser->end && !parser->input->eof)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *value_r = str_c(parser->value);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int json_parse_atom(struct json_parser *parser, const char *atom)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int avail, len = strlen(atom);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen avail = parser->end - parser->data;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (avail < len) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (memcmp(parser->data, atom, avail) != 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return -1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* everything matches so far, but we need more data */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen parser->data += avail;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (memcmp(parser->data, atom, len) != 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen parser->data += len;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainenstatic int
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainenjson_parse_object_close(struct json_parser *parser, enum json_type *type_r)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen parser->data++;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen json_parser_update_input_pos(parser);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (parser->nested_object_count > 0) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* closing a nested object */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->nested_object_count--;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen parser->state = JSON_STATE_OBJECT_VALUE_NEXT;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (parser->nested_skip_count > 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->nested_skip_count--;
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen return 0;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen *type_r = JSON_TYPE_OBJECT_END;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return 1;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen parser->state = JSON_STATE_DONE;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return 0;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenstatic int
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenjson_try_parse_next(struct json_parser *parser, enum json_type *type_r,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen const char **value_r)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen bool skipping = parser->skipping;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen int ret;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (!json_parse_whitespace(parser))
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return -1;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen switch (parser->state) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen case JSON_STATE_ROOT:
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (*parser->data != '{') {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->error = "Object doesn't begin with '{'";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return -1;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->data++;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen parser->state = JSON_STATE_OBJECT_OPEN;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen json_parser_update_input_pos(parser);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen case JSON_STATE_OBJECT_VALUE:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (*parser->data == '[') {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->error = "Arrays not supported";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return -1;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen } else if (*parser->data == '{') {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->data++;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->state = JSON_STATE_OBJECT_OPEN;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->nested_object_count++;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen json_parser_update_input_pos(parser);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (parser->skipping) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->nested_skip_count++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen *type_r = JSON_TYPE_OBJECT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = json_parse_string(parser, TRUE, value_r)) >= 0) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen *type_r = JSON_TYPE_STRING;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen } else if ((ret = json_parse_number(parser, value_r)) >= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *type_r = JSON_TYPE_NUMBER;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen } else if ((ret = json_parse_atom(parser, "true")) >= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *type_r = JSON_TYPE_TRUE;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen *value_r = "true";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if ((ret = json_parse_atom(parser, "false")) >= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *type_r = JSON_TYPE_FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *value_r = "false";
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen } else if ((ret = json_parse_atom(parser, "null")) >= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *type_r = JSON_TYPE_NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *value_r = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->error = "Invalid data as value";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(parser->data == parser->end);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (parser->skipping && *type_r == JSON_TYPE_STRING) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* a large string that we want to skip over. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen json_parser_update_input_pos(parser);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->state = JSON_STATE_SKIP_STRING;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->state = parser->state == JSON_STATE_ROOT ?
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen JSON_STATE_DONE :
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen JSON_STATE_OBJECT_VALUE_NEXT;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen break;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen case JSON_STATE_OBJECT_OPEN:
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (*parser->data == '}')
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen return json_parse_object_close(parser, type_r);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen parser->state = JSON_STATE_OBJECT_KEY;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* fall through */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen case JSON_STATE_OBJECT_KEY:
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (json_parse_string(parser, FALSE, value_r) <= 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->error = "Expected string as object key";
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *type_r = JSON_TYPE_OBJECT_KEY;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen parser->state = JSON_STATE_OBJECT_COLON;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen break;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen case JSON_STATE_OBJECT_COLON:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (*parser->data != ':') {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen parser->error = "Expected ':' after key";
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->data++;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->state = JSON_STATE_OBJECT_VALUE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen json_parser_update_input_pos(parser);
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen case JSON_STATE_OBJECT_VALUE_NEXT:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (parser->skipping && parser->nested_skip_count == 0) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen /* we skipped over the previous value */
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen parser->skipping = FALSE;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen }
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen if (*parser->data == '}')
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return json_parse_object_close(parser, type_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*parser->data != ',') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->error = "Expected ',' or '}' after object value";
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen return -1;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->state = JSON_STATE_OBJECT_KEY;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->data++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen json_parser_update_input_pos(parser);
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen return 0;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen case JSON_STATE_SKIP_STRING:
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen if (json_skip_string(parser) <= 0)
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen return -1;
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen parser->state = JSON_STATE_OBJECT_VALUE_NEXT;
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen return 0;
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen case JSON_STATE_DONE:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->error = "Unexpected data at the end";
99e8698f598d2b83da7c581584a538c0713fd11dTimo Sirainen return -1;
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen }
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen json_parser_update_input_pos(parser);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return skipping ? 0 : 1;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen}
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainenint json_parse_next(struct json_parser *parser, enum json_type *type_r,
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen const char **value_r)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(parser->strinput == NULL);
ec1e30ecc38f0deddaf655413cf02d5972ddbc70Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *value_r = NULL;
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((ret = json_parser_read_more(parser)) > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((ret = json_try_parse_next(parser, type_r, value_r)) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (ret > 0)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen break;
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen if (parser->data != parser->end)
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen return -1;
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen /* parsing probably failed because there wasn't enough input.
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen reset the error and try reading more. */
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen parser->error = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return ret;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid json_parse_skip_next(struct json_parser *parser)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(!parser->skipping);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(parser->strinput == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->state == JSON_STATE_OBJECT_VALUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->skipping = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void json_strinput_destroyed(struct json_parser *parser)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(parser->strinput != NULL);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->strinput = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenjson_try_parse_stream_start(struct json_parser *parser,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen struct istream **input_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!json_parse_whitespace(parser))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (parser->state == JSON_STATE_OBJECT_COLON) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*parser->data != ':') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->error = "Expected ':' after key";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->data++;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen parser->state = JSON_STATE_OBJECT_VALUE;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen if (!json_parse_whitespace(parser))
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*parser->data != '"')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parser->data++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen json_parser_update_input_pos(parser);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->state = JSON_STATE_SKIP_STRING;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen parser->strinput = i_stream_create_jsonstr(parser->input);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_stream_set_destroy_callback(parser->strinput,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen json_strinput_destroyed, parser);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *input_r = parser->strinput;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint json_parse_next_stream(struct json_parser *parser,
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct istream **input_r)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen int ret;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(!parser->skipping);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_assert(parser->strinput == NULL);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->state == JSON_STATE_OBJECT_VALUE);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen *input_r = NULL;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen while ((ret = json_parser_read_more(parser)) > 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (json_try_parse_stream_start(parser, input_r) == 0)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen break;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (parser->data != parser->end)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* parsing probably failed because there wasn't enough input.
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen reset the error and try reading more. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen parser->error = NULL;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return ret;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen