json-parser.c revision 4e8e7a93628b4ed60aaaa47c6f72c1433f21e81d
a4544a5a0e622ef69e38641f87ab1b5685e05911Phill Cunnington/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "lib.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "str.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "istream.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "hex-dec.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "unichar.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "json-parser.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterenum json_state {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster JSON_STATE_ROOT = 0,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster JSON_STATE_OBJECT_OPEN,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster JSON_STATE_OBJECT_KEY,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster JSON_STATE_OBJECT_COLON,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster JSON_STATE_OBJECT_VALUE,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster JSON_STATE_OBJECT_VALUE_NEXT,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster JSON_STATE_DONE
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster};
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstruct json_parser {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster struct istream *input;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster uoff_t highwater_offset;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster const unsigned char *start, *end, *data;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster const char *error;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster string_t *value;
a4544a5a0e622ef69e38641f87ab1b5685e05911Phill Cunnington
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster enum json_state state;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster unsigned int nested_object_count;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster};
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic int
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterjson_try_parse_next(struct json_parser *parser, enum json_type *type_r,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster const char **value_r);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic int json_parser_read_more(struct json_parser *parser)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster uoff_t cur_highwater = parser->input->v_offset +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_stream_get_data_size(parser->input);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster size_t size;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ssize_t ret;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_assert(parser->highwater_offset <= cur_highwater);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (parser->error != NULL)
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings return -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (parser->highwater_offset == cur_highwater) {
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna ret = i_stream_read(parser->input);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (ret == -2) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->error = "Token too large";
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (ret <= 0)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return ret;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster cur_highwater = parser->input->v_offset +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_stream_get_data_size(parser->input);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_assert(parser->highwater_offset < cur_highwater);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->highwater_offset = cur_highwater;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->start = parser->data = i_stream_get_data(parser->input, &size);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->end = parser->start + size;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_assert(size > 0);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic void json_parser_update_input_pos(struct json_parser *parser)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster size_t size;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (parser->data == parser->start)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_stream_skip(parser->input, parser->data - parser->start);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->start = parser->data = i_stream_get_data(parser->input, &size);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->end = parser->start + size;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (size > 0) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* we skipped over some data and there's still data left.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster no need to read() the next time. */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->highwater_offset = 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } else {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->highwater_offset = parser->input->v_offset;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstruct json_parser *json_parser_init(struct istream *input)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster struct json_parser *parser;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser = i_new(struct json_parser, 1);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->input = input;
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee parser->value = str_new(default_pool, 128);
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee i_stream_ref(input);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return parser;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterint json_parser_deinit(struct json_parser **_parser, const char **error_r)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster struct json_parser *parser = *_parser;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *_parser = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (parser->error != NULL) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* actual parser error */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *error_r = parser->error;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } else if (parser->input->stream_errno != 0) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *error_r = t_strdup_printf("read(%s) failed: %m",
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_stream_get_name(parser->input));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } else if (parser->data == parser->end &&
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster !i_stream_have_bytes_left(parser->input) &&
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->state != JSON_STATE_ROOT &&
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->state != JSON_STATE_DONE) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *error_r = "Missing '}'";
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } else {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *error_r = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_stream_unref(&parser->input);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_free(&parser->value);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster i_free(parser);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return *error_r != NULL ? -1 : 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic bool json_parse_whitespace(struct json_parser *parser)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (; parser->data != parser->end; parser->data++) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster switch (*parser->data) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case ' ':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case '\t':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case '\r':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case '\n':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster default:
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster json_parser_update_input_pos(parser);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return TRUE;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster json_parser_update_input_pos(parser);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return FALSE;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic int json_parse_string(struct json_parser *parser, const char **value_r)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (*parser->data != '"')
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->data++;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_truncate(parser->value, 0);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (; parser->data != parser->end; parser->data++) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (*parser->data == '"') {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->data++;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *value_r = str_c(parser->value);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (*parser->data != '\\')
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, *parser->data);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster else {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster switch (*++parser->data) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case '"':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case '\\':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case '/':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, *parser->data);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case 'b':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, '\b');
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case 'f':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, '\f');
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case 'n':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, '\n');
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case 'r':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, '\r');
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case 't':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, '\t');
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster case 'u':
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->data++;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (parser->end - parser->data < 4) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* wait for more data */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->data = parser->end;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster uni_ucs4_to_utf8_c(hex2dec(parser->data, 4),
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->value);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster parser->data += 3;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster break;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster default:
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic int
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterjson_parse_digits(struct json_parser *parser)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee if (parser->data == parser->end)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (*parser->data < '0' || *parser->data > '9')
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee return -1;
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (parser->data != parser->end &&
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *parser->data >= '0' && *parser->data <= '9')
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, *parser->data++);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 1;
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna}
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Lunastatic int json_parse_int(struct json_parser *parser)
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna{
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna int ret;
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna if (*parser->data == '-') {
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna str_append_c(parser->value, *parser->data++);
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna if (parser->data == parser->end)
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna return 0;
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna }
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna if (*parser->data == '0')
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna str_append_c(parser->value, *parser->data++);
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna else {
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna if ((ret = json_parse_digits(parser)) <= 0)
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna return ret;
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna }
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna return 1;
61b4091b1d49fc8b736ee1e150a1b76c14f05c91David Luna}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Leestatic int json_parse_number(struct json_parser *parser, const char **value_r)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int ret;
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_truncate(parser->value, 0);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((ret = json_parse_int(parser)) <= 0)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return ret;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (parser->data != parser->end && *parser->data == '.') {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* frac */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster str_append_c(parser->value, *parser->data++);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((ret = json_parse_digits(parser)) <= 0)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster 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 0;
if (*parser->data == '+' || *parser->data == '-')
str_append_c(parser->value, *parser->data++);
if ((ret = json_parse_digits(parser)) <= 0)
return ret;
}
if (parser->data == parser->end && !parser->input->eof)
return 0;
*value_r = str_c(parser->value);
return 1;
}
static int json_parse_atom(struct json_parser *parser, const char *atom)
{
unsigned int avail, len = strlen(atom);
avail = parser->end - parser->data;
if (avail < len) {
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 1;
}
static int
json_parse_object_close(struct json_parser *parser, enum json_type *type_r,
const char **value_r)
{
parser->data++;
json_parser_update_input_pos(parser);
if (parser->nested_object_count > 0) {
/* closing a nested object */
parser->nested_object_count--;
parser->state = JSON_STATE_OBJECT_VALUE_NEXT;
*type_r = JSON_TYPE_OBJECT_END;
return 0;
}
parser->state = JSON_STATE_DONE;
return json_try_parse_next(parser, type_r, value_r);
}
static int
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;
switch (parser->state) {
case JSON_STATE_ROOT:
if (*parser->data != '{') {
parser->error = "Object doesn't begin with '{'";
return -1;
}
parser->data++;
parser->state = JSON_STATE_OBJECT_OPEN;
json_parser_update_input_pos(parser);
return json_try_parse_next(parser, type_r, value_r);
case JSON_STATE_OBJECT_VALUE:
if (*parser->data == '[') {
parser->error = "Arrays not supported";
return -1;
} else if (*parser->data == '{') {
parser->data++;
parser->state = JSON_STATE_OBJECT_OPEN;
parser->nested_object_count++;
json_parser_update_input_pos(parser);
*type_r = JSON_TYPE_OBJECT;
return 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 ((ret = json_parse_atom(parser, "false")) >= 0) {
*type_r = JSON_TYPE_FALSE;
*value_r = "false";
} 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;
break;
case JSON_STATE_OBJECT_OPEN:
if (*parser->data == '}')
return json_parse_object_close(parser, type_r, value_r);
parser->state = JSON_STATE_OBJECT_KEY;
/* fall through */
case JSON_STATE_OBJECT_KEY:
if (json_parse_string(parser, value_r) <= 0) {
parser->error = "Expected string as object key";
return -1;
}
*type_r = JSON_TYPE_OBJECT_KEY;
parser->state = JSON_STATE_OBJECT_COLON;
break;
case JSON_STATE_OBJECT_COLON:
if (*parser->data != ':') {
parser->error = "Expected ':' after key";
return -1;
}
parser->data++;
parser->state = JSON_STATE_OBJECT_VALUE;
json_parser_update_input_pos(parser);
return json_try_parse_next(parser, type_r, value_r);
case JSON_STATE_OBJECT_VALUE_NEXT:
if (*parser->data == '}')
return json_parse_object_close(parser, type_r, value_r);
if (*parser->data != ',') {
parser->error = "Expected ',' or '}' after object value";
return -1;
}
parser->state = JSON_STATE_OBJECT_KEY;
parser->data++;
json_parser_update_input_pos(parser);
return json_try_parse_next(parser, type_r, value_r);
case JSON_STATE_DONE:
parser->error = "Unexpected data at the end";
return -1;
}
json_parser_update_input_pos(parser);
return 0;
}
int json_parse_next(struct json_parser *parser, enum json_type *type_r,
const char **value_r)
{
int ret;
*value_r = NULL;
while ((ret = json_parser_read_more(parser)) > 0) {
if (json_try_parse_next(parser, type_r, value_r) == 0)
break;
if (parser->data != parser->end)
return -1;
/* parsing probably failed because there wasn't enough input.
reset the error and try reading more. */
parser->error = NULL;
}
return ret;
}