json-parser.c revision f784d5bb8edbec88829524135cfa100129f5384d
429N/A/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
429N/A
429N/A#include "lib.h"
429N/A#include "array.h"
429N/A#include "str.h"
429N/A#include "istream.h"
429N/A#include "hex-dec.h"
429N/A#include "unichar.h"
429N/A#include "istream-jsonstr.h"
429N/A#include "json-parser.h"
429N/A
429N/Aenum json_state {
429N/A JSON_STATE_ROOT = 0,
429N/A JSON_STATE_OBJECT_OPEN,
429N/A JSON_STATE_OBJECT_KEY,
429N/A JSON_STATE_OBJECT_COLON,
429N/A JSON_STATE_OBJECT_VALUE,
429N/A JSON_STATE_OBJECT_SKIP_STRING,
429N/A JSON_STATE_OBJECT_NEXT,
429N/A JSON_STATE_ARRAY_OPEN,
429N/A JSON_STATE_ARRAY_VALUE,
941N/A JSON_STATE_ARRAY_SKIP_STRING,
941N/A JSON_STATE_ARRAY_NEXT,
3158N/A JSON_STATE_ARRAY_NEXT_SKIP,
941N/A JSON_STATE_VALUE,
429N/A JSON_STATE_DONE
429N/A};
429N/A
429N/Astruct json_parser {
1516N/A struct istream *input;
3234N/A uoff_t highwater_offset;
429N/A enum json_parser_flags flags;
429N/A
429N/A const unsigned char *start, *end, *data;
429N/A const char *error;
1026N/A string_t *value;
429N/A struct istream *strinput;
941N/A
941N/A enum json_state state;
941N/A ARRAY(enum json_state) nesting;
546N/A unsigned int nested_skip_count;
941N/A bool skipping;
546N/A bool seen_eof;
546N/A};
1054N/A
546N/Astatic int json_parser_read_more(struct json_parser *parser)
516N/A{
429N/A uoff_t cur_highwater = parser->input->v_offset +
429N/A i_stream_get_data_size(parser->input);
429N/A size_t size;
429N/A ssize_t ret;
429N/A
429N/A i_assert(parser->highwater_offset <= cur_highwater);
1100N/A
429N/A if (parser->error != NULL)
429N/A return -1;
429N/A
429N/A if (parser->highwater_offset == cur_highwater) {
429N/A ret = i_stream_read(parser->input);
429N/A if (ret == -2) {
429N/A parser->error = "Token too large";
441N/A return -1;
441N/A }
441N/A if (ret < 0 && !parser->seen_eof &&
441N/A i_stream_get_data_size(parser->input) > 0 &&
441N/A parser->input->stream_errno == 0) {
429N/A /* call it once more to finish any pending number */
429N/A parser->seen_eof = TRUE;
429N/A } else if (ret <= 0) {
429N/A return ret;
429N/A } else {
429N/A cur_highwater = parser->input->v_offset +
429N/A i_stream_get_data_size(parser->input);
429N/A i_assert(parser->highwater_offset < cur_highwater);
429N/A parser->highwater_offset = cur_highwater;
429N/A }
429N/A }
429N/A
429N/A parser->start = parser->data = i_stream_get_data(parser->input, &size);
429N/A parser->end = parser->start + size;
429N/A i_assert(size > 0);
429N/A return 1;
429N/A}
429N/A
429N/Astatic void json_parser_update_input_pos(struct json_parser *parser)
429N/A{
429N/A size_t size;
441N/A
429N/A if (parser->data == parser->start)
546N/A return;
429N/A
429N/A i_stream_skip(parser->input, parser->data - parser->start);
429N/A parser->start = parser->data = i_stream_get_data(parser->input, &size);
429N/A parser->end = parser->start + size;
429N/A if (size > 0) {
429N/A /* we skipped over some data and there's still data left.
429N/A no need to read() the next time. */
429N/A parser->highwater_offset = 0;
429N/A } else {
429N/A parser->highwater_offset = parser->input->v_offset;
429N/A }
429N/A}
429N/A
429N/Astruct json_parser *json_parser_init(struct istream *input)
441N/A{
3171N/A return json_parser_init_flags(input, 0);
429N/A}
429N/A
429N/Astruct json_parser *json_parser_init_flags(struct istream *input,
429N/A enum json_parser_flags flags)
429N/A{
429N/A struct json_parser *parser;
429N/A
429N/A parser = i_new(struct json_parser, 1);
429N/A parser->input = input;
441N/A parser->flags = flags;
429N/A parser->value = str_new(default_pool, 128);
429N/A i_array_init(&parser->nesting, 8);
429N/A i_stream_ref(input);
429N/A
429N/A if ((flags & JSON_PARSER_NO_ROOT_OBJECT) != 0)
429N/A parser->state = JSON_STATE_VALUE;
429N/A return parser;
429N/A}
429N/A
429N/Aint json_parser_deinit(struct json_parser **_parser, const char **error_r)
429N/A{
429N/A struct json_parser *parser = *_parser;
429N/A
429N/A *_parser = NULL;
429N/A
429N/A if (parser->error != NULL) {
429N/A /* actual parser error */
429N/A *error_r = parser->error;
429N/A } else if (parser->input->stream_errno != 0) {
429N/A *error_r = t_strdup_printf("read(%s) failed: %s",
429N/A i_stream_get_name(parser->input),
429N/A i_stream_get_error(parser->input));
429N/A } else if (parser->data == parser->end &&
429N/A !i_stream_have_bytes_left(parser->input) &&
429N/A parser->state != JSON_STATE_DONE) {
429N/A *error_r = "Missing '}'";
429N/A } else {
1230N/A *error_r = NULL;
1230N/A }
429N/A
429N/A i_stream_unref(&parser->input);
429N/A array_free(&parser->nesting);
429N/A str_free(&parser->value);
429N/A i_free(parser);
429N/A return *error_r != NULL ? -1 : 0;
429N/A}
429N/A
429N/Astatic bool json_parse_whitespace(struct json_parser *parser)
429N/A{
429N/A for (; parser->data != parser->end; parser->data++) {
3234N/A switch (*parser->data) {
1230N/A case ' ':
1230N/A case '\t':
1230N/A case '\r':
1230N/A case '\n':
429N/A break;
429N/A default:
429N/A json_parser_update_input_pos(parser);
429N/A return TRUE;
941N/A }
941N/A }
941N/A json_parser_update_input_pos(parser);
429N/A return FALSE;
429N/A}
429N/A
429N/Astatic int json_skip_string(struct json_parser *parser)
1230N/A{
429N/A for (; parser->data != parser->end; parser->data++) {
429N/A if (*parser->data == '"') {
429N/A parser->data++;
429N/A json_parser_update_input_pos(parser);
429N/A return 1;
429N/A }
429N/A if (*parser->data == '\\') {
429N/A switch (*++parser->data) {
429N/A case '"':
429N/A case '\\':
429N/A case '/':
429N/A case 'b':
429N/A case 'f':
429N/A case 'n':
429N/A case 'r':
429N/A case 't':
429N/A break;
429N/A case 'u':
429N/A if (parser->end - parser->data < 4)
429N/A return -1;
429N/A parser->data += 3;
1230N/A break;
1230N/A default:
429N/A return -1;
429N/A }
1230N/A }
1230N/A }
1230N/A json_parser_update_input_pos(parser);
1230N/A return 0;
429N/A}
429N/A
429N/Astatic int json_parse_string(struct json_parser *parser, bool allow_skip,
429N/A const char **value_r)
429N/A{
429N/A if (*parser->data != '"')
429N/A return -1;
429N/A parser->data++;
429N/A
429N/A if (parser->skipping && allow_skip) {
429N/A *value_r = NULL;
429N/A return json_skip_string(parser);
429N/A }
429N/A
1100N/A str_truncate(parser->value, 0);
429N/A for (; parser->data != parser->end; parser->data++) {
1100N/A if (*parser->data == '"') {
1100N/A parser->data++;
1100N/A *value_r = str_c(parser->value);
1100N/A return 1;
1100N/A }
1100N/A if (*parser->data != '\\')
1100N/A str_append_c(parser->value, *parser->data);
1100N/A else {
1100N/A if (++parser->data == parser->end)
429N/A return 0;
1751N/A switch (*parser->data) {
1751N/A case '"':
429N/A case '\\':
429N/A case '/':
429N/A str_append_c(parser->value, *parser->data);
429N/A break;
429N/A case 'b':
429N/A str_append_c(parser->value, '\b');
429N/A break;
429N/A case 'f':
429N/A str_append_c(parser->value, '\f');
429N/A break;
429N/A case 'n':
429N/A str_append_c(parser->value, '\n');
429N/A break;
429N/A case 'r':
429N/A str_append_c(parser->value, '\r');
429N/A break;
429N/A case 't':
429N/A str_append_c(parser->value, '\t');
429N/A break;
429N/A case 'u':
429N/A parser->data++;
429N/A if (parser->end - parser->data < 4) {
429N/A /* wait for more data */
429N/A parser->data = parser->end;
429N/A return 0;
429N/A }
1751N/A uni_ucs4_to_utf8_c(hex2dec(parser->data, 4),
1751N/A parser->value);
1751N/A parser->data += 3;
1751N/A break;
429N/A default:
941N/A return -1;
1751N/A }
429N/A }
1751N/A }
3234N/A return 0;
1751N/A}
1751N/A
1751N/Astatic int
1751N/Ajson_parse_digits(struct json_parser *parser)
1751N/A{
1751N/A if (parser->data == parser->end)
1751N/A return 0;
1751N/A if (*parser->data < '0' || *parser->data > '9')
1751N/A return -1;
1751N/A
1751N/A while (parser->data != parser->end &&
1751N/A *parser->data >= '0' && *parser->data <= '9')
1751N/A str_append_c(parser->value, *parser->data++);
1751N/A return 1;
3234N/A}
1751N/A
1751N/Astatic int json_parse_int(struct json_parser *parser)
1751N/A{
1751N/A int ret;
1751N/A
1751N/A if (*parser->data == '-') {
1751N/A str_append_c(parser->value, *parser->data++);
1751N/A if (parser->data == parser->end)
1751N/A return 0;
1751N/A }
1751N/A if (*parser->data == '0')
1751N/A str_append_c(parser->value, *parser->data++);
1751N/A else {
1751N/A if ((ret = json_parse_digits(parser)) <= 0)
429N/A return ret;
429N/A }
1026N/A return 1;
1026N/A}
1026N/A
1026N/Astatic int json_parse_number(struct json_parser *parser, const char **value_r)
1026N/A{
1026N/A int ret;
1026N/A
1026N/A str_truncate(parser->value, 0);
3234N/A if ((ret = json_parse_int(parser)) <= 0)
1026N/A return ret;
1026N/A if (parser->data != parser->end && *parser->data == '.') {
1751N/A /* frac */
1751N/A str_append_c(parser->value, *parser->data++);
1751N/A if ((ret = json_parse_digits(parser)) <= 0)
1751N/A return ret;
1100N/A }
1751N/A if (parser->data != parser->end &&
1751N/A (*parser->data == 'e' || *parser->data == 'E')) {
1100N/A /* exp */
1100N/A str_append_c(parser->value, *parser->data++);
1751N/A if (parser->data == parser->end)
1751N/A return 0;
1751N/A if (*parser->data == '+' || *parser->data == '-')
1751N/A str_append_c(parser->value, *parser->data++);
1751N/A if ((ret = json_parse_digits(parser)) <= 0)
1100N/A return ret;
1751N/A }
3234N/A if (parser->data == parser->end && !parser->input->eof)
1751N/A return 0;
1751N/A *value_r = str_c(parser->value);
3158N/A return 1;
1751N/A}
1751N/A
3158N/Astatic int json_parse_atom(struct json_parser *parser, const char *atom)
1751N/A{
1751N/A size_t avail, len = strlen(atom);
3158N/A
3234N/A avail = parser->end - parser->data;
1751N/A if (avail < len) {
1751N/A if (memcmp(parser->data, atom, avail) != 0)
3158N/A return -1;
1751N/A
1751N/A /* everything matches so far, but we need more data */
3158N/A parser->data += avail;
3158N/A return 0;
1751N/A }
1751N/A if (memcmp(parser->data, atom, len) != 0)
1100N/A return -1;
429N/A parser->data += len;
429N/A return 1;
429N/A}
429N/A
429N/Astatic int json_parse_denest(struct json_parser *parser)
429N/A{
429N/A const enum json_state *nested_states;
429N/A unsigned count;
429N/A
429N/A parser->data++;
429N/A json_parser_update_input_pos(parser);
429N/A
429N/A nested_states = array_get(&parser->nesting, &count);
429N/A i_assert(count > 0);
429N/A if (count == 1) {
429N/A /* closing root */
429N/A parser->state = JSON_STATE_DONE;
429N/A if ((parser->flags & JSON_PARSER_NO_ROOT_OBJECT) == 0)
429N/A return 0;
429N/A /* we want to return the ending "]" or "}" to caller */
429N/A return 1;
429N/A }
429N/A
429N/A /* closing a nested object */
429N/A parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ?
429N/A JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
429N/A array_delete(&parser->nesting, count-1, 1);
429N/A
429N/A if (parser->nested_skip_count > 0) {
429N/A parser->nested_skip_count--;
429N/A return 0;
429N/A }
429N/A return 1;
429N/A}
429N/A
429N/Astatic int
429N/Ajson_parse_close_object(struct json_parser *parser, enum json_type *type_r)
1054N/A{
1054N/A if (json_parse_denest(parser) == 0)
429N/A return 0;
429N/A *type_r = JSON_TYPE_OBJECT_END;
429N/A return 1;
429N/A}
429N/A
1054N/Astatic int
429N/Ajson_parse_close_array(struct json_parser *parser, enum json_type *type_r)
429N/A{
429N/A if (json_parse_denest(parser) == 0)
429N/A return 0;
429N/A *type_r = JSON_TYPE_ARRAY_END;
429N/A return 1;
429N/A}
429N/A
429N/Astatic void json_parser_object_open(struct json_parser *parser)
429N/A{
429N/A parser->data++;
429N/A parser->state = JSON_STATE_OBJECT_OPEN;
429N/A array_append(&parser->nesting, &parser->state, 1);
429N/A json_parser_update_input_pos(parser);
429N/A}
429N/A
429N/Astatic int
429N/Ajson_try_parse_next(struct json_parser *parser, enum json_type *type_r,
429N/A const char **value_r)
429N/A{
429N/A bool skipping = parser->skipping;
429N/A int ret;
429N/A
429N/A if (!json_parse_whitespace(parser))
429N/A return -1;
429N/A
429N/A switch (parser->state) {
429N/A case JSON_STATE_ROOT:
429N/A if (*parser->data != '{') {
429N/A parser->error = "Object doesn't begin with '{'";
429N/A return -1;
429N/A }
429N/A json_parser_object_open(parser);
429N/A return 0;
429N/A case JSON_STATE_OBJECT_VALUE:
429N/A case JSON_STATE_ARRAY_VALUE:
429N/A case JSON_STATE_VALUE:
429N/A if (*parser->data == '{') {
429N/A json_parser_object_open(parser);
429N/A
429N/A if (parser->skipping) {
429N/A parser->nested_skip_count++;
429N/A return 0;
3234N/A }
429N/A *type_r = JSON_TYPE_OBJECT;
429N/A return 1;
429N/A } else if (*parser->data == '[') {
429N/A parser->data++;
429N/A parser->state = JSON_STATE_ARRAY_OPEN;
429N/A array_append(&parser->nesting, &parser->state, 1);
429N/A json_parser_update_input_pos(parser);
3194N/A
429N/A if (parser->skipping) {
429N/A parser->nested_skip_count++;
429N/A return 0;
429N/A }
429N/A *type_r = JSON_TYPE_ARRAY;
429N/A return 1;
429N/A }
429N/A
429N/A if ((ret = json_parse_string(parser, TRUE, value_r)) >= 0) {
429N/A *type_r = JSON_TYPE_STRING;
429N/A } else if ((ret = json_parse_number(parser, value_r)) >= 0) {
429N/A *type_r = JSON_TYPE_NUMBER;
429N/A } else if ((ret = json_parse_atom(parser, "true")) >= 0) {
429N/A *type_r = JSON_TYPE_TRUE;
429N/A *value_r = "true";
429N/A } else if ((ret = json_parse_atom(parser, "false")) >= 0) {
429N/A *type_r = JSON_TYPE_FALSE;
429N/A *value_r = "false";
429N/A } else if ((ret = json_parse_atom(parser, "null")) >= 0) {
429N/A *type_r = JSON_TYPE_NULL;
429N/A *value_r = NULL;
429N/A } else {
429N/A parser->error = "Invalid data as value";
3194N/A return -1;
429N/A }
429N/A if (ret == 0) {
429N/A i_assert(parser->data == parser->end);
429N/A if (parser->skipping && *type_r == JSON_TYPE_STRING) {
429N/A /* a large string that we want to skip over. */
429N/A json_parser_update_input_pos(parser);
429N/A parser->state = parser->state == JSON_STATE_OBJECT_VALUE ?
429N/A JSON_STATE_OBJECT_SKIP_STRING :
429N/A JSON_STATE_ARRAY_SKIP_STRING;
429N/A return 0;
429N/A }
429N/A return -1;
429N/A }
429N/A switch (parser->state) {
429N/A case JSON_STATE_OBJECT_VALUE:
1054N/A parser->state = JSON_STATE_OBJECT_NEXT;
429N/A break;
429N/A case JSON_STATE_ARRAY_VALUE:
429N/A parser->state = JSON_STATE_ARRAY_NEXT;
429N/A break;
429N/A case JSON_STATE_VALUE:
1230N/A parser->state = JSON_STATE_DONE;
1230N/A break;
1230N/A default:
1230N/A i_unreached();
1230N/A }
1230N/A break;
1230N/A case JSON_STATE_OBJECT_OPEN:
1230N/A if (*parser->data == '}')
1230N/A return json_parse_close_object(parser, type_r);
1230N/A parser->state = JSON_STATE_OBJECT_KEY;
1230N/A /* fall through */
1230N/A case JSON_STATE_OBJECT_KEY:
1230N/A if (json_parse_string(parser, FALSE, value_r) <= 0) {
429N/A parser->error = "Expected string as object key";
429N/A return -1;
429N/A }
429N/A *type_r = JSON_TYPE_OBJECT_KEY;
429N/A parser->state = JSON_STATE_OBJECT_COLON;
429N/A break;
429N/A case JSON_STATE_OBJECT_COLON:
429N/A if (*parser->data != ':') {
429N/A parser->error = "Expected ':' after key";
429N/A return -1;
429N/A }
429N/A parser->data++;
429N/A parser->state = JSON_STATE_OBJECT_VALUE;
429N/A json_parser_update_input_pos(parser);
429N/A return 0;
429N/A case JSON_STATE_OBJECT_NEXT:
429N/A if (parser->skipping && parser->nested_skip_count == 0) {
429N/A /* we skipped over the previous value */
429N/A parser->skipping = FALSE;
429N/A }
429N/A if (*parser->data == '}')
429N/A return json_parse_close_object(parser, type_r);
429N/A if (*parser->data != ',') {
429N/A parser->error = "Expected ',' or '}' after object value";
3194N/A return -1;
429N/A }
429N/A parser->state = JSON_STATE_OBJECT_KEY;
429N/A parser->data++;
429N/A json_parser_update_input_pos(parser);
429N/A return 0;
1230N/A case JSON_STATE_ARRAY_OPEN:
1230N/A if (*parser->data == ']')
1230N/A return json_parse_close_array(parser, type_r);
1230N/A parser->state = JSON_STATE_ARRAY_VALUE;
1230N/A return 0;
429N/A case JSON_STATE_ARRAY_NEXT:
429N/A if (parser->skipping && parser->nested_skip_count == 0) {
429N/A /* we skipped over the previous value */
429N/A parser->skipping = FALSE;
429N/A }
429N/A /* fall through */
429N/A case JSON_STATE_ARRAY_NEXT_SKIP:
429N/A if (*parser->data == ']')
429N/A return json_parse_close_array(parser, type_r);
429N/A if (*parser->data != ',') {
429N/A parser->error = "Expected ',' or '}' after array value";
429N/A return -1;
429N/A }
429N/A parser->state = JSON_STATE_ARRAY_VALUE;
429N/A parser->data++;
429N/A json_parser_update_input_pos(parser);
429N/A return 0;
429N/A case JSON_STATE_OBJECT_SKIP_STRING:
429N/A case JSON_STATE_ARRAY_SKIP_STRING:
3194N/A if (json_skip_string(parser) <= 0)
429N/A return -1;
429N/A parser->state = parser->state == JSON_STATE_OBJECT_SKIP_STRING ?
429N/A JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
429N/A return 0;
499N/A case JSON_STATE_DONE:
3234N/A parser->error = "Unexpected data at the end";
499N/A return -1;
546N/A }
546N/A json_parser_update_input_pos(parser);
546N/A return skipping ? 0 : 1;
3234N/A}
546N/A
546N/Aint json_parse_next(struct json_parser *parser, enum json_type *type_r,
546N/A const char **value_r)
429N/A{
429N/A int ret;
429N/A
429N/A i_assert(parser->strinput == NULL);
1230N/A
1230N/A *value_r = NULL;
1653N/A
1653N/A while ((ret = json_parser_read_more(parser)) > 0) {
3234N/A while ((ret = json_try_parse_next(parser, type_r, value_r)) == 0)
1653N/A ;
1653N/A if (ret > 0)
1653N/A break;
1230N/A if (parser->data != parser->end)
1230N/A return -1;
429N/A /* parsing probably failed because there wasn't enough input.
429N/A reset the error and try reading more. */
429N/A parser->error = NULL;
429N/A parser->highwater_offset = parser->input->v_offset +
429N/A i_stream_get_data_size(parser->input);
546N/A }
429N/A return ret;
1026N/A}
429N/A
429N/Avoid json_parse_skip_next(struct json_parser *parser)
429N/A{
429N/A i_assert(!parser->skipping);
941N/A i_assert(parser->strinput == NULL);
941N/A i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
429N/A parser->state == JSON_STATE_OBJECT_VALUE ||
429N/A parser->state == JSON_STATE_ARRAY_VALUE ||
429N/A parser->state == JSON_STATE_ARRAY_NEXT);
429N/A
429N/A parser->skipping = TRUE;
429N/A if (parser->state == JSON_STATE_ARRAY_NEXT)
429N/A parser->state = JSON_STATE_ARRAY_NEXT_SKIP;
429N/A}
429N/A
429N/Astatic void json_strinput_destroyed(struct json_parser *parser)
429N/A{
429N/A i_assert(parser->strinput != NULL);
429N/A
429N/A parser->strinput = NULL;
429N/A}
516N/A
516N/Astatic int
516N/Ajson_try_parse_stream_start(struct json_parser *parser,
2962N/A struct istream **input_r)
2962N/A{
1516N/A if (!json_parse_whitespace(parser))
1230N/A return -1;
516N/A
516N/A if (parser->state == JSON_STATE_OBJECT_COLON) {
2962N/A if (*parser->data != ':') {
516N/A parser->error = "Expected ':' after key";
516N/A return -1;
516N/A }
516N/A parser->data++;
516N/A parser->state = JSON_STATE_OBJECT_VALUE;
2962N/A if (!json_parse_whitespace(parser))
2962N/A return -1;
1516N/A }
516N/A
516N/A if (*parser->data != '"')
516N/A return -1;
2962N/A parser->data++;
516N/A json_parser_update_input_pos(parser);
516N/A
516N/A parser->state = parser->state == JSON_STATE_OBJECT_VALUE ?
516N/A JSON_STATE_OBJECT_SKIP_STRING : JSON_STATE_ARRAY_SKIP_STRING;
516N/A parser->strinput = i_stream_create_jsonstr(parser->input);
516N/A i_stream_add_destroy_callback(parser->strinput,
516N/A json_strinput_destroyed, parser);
516N/A
1230N/A *input_r = parser->strinput;
1230N/A return 0;
1230N/A}
1230N/A
1230N/Aint json_parse_next_stream(struct json_parser *parser,
1230N/A struct istream **input_r)
1230N/A{
1230N/A int ret;
941N/A
516N/A i_assert(!parser->skipping);
516N/A i_assert(parser->strinput == NULL);
516N/A i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
1230N/A parser->state == JSON_STATE_OBJECT_VALUE ||
1230N/A parser->state == JSON_STATE_ARRAY_VALUE);
516N/A
941N/A *input_r = NULL;
941N/A
941N/A while ((ret = json_parser_read_more(parser)) > 0) {
516N/A if (json_try_parse_stream_start(parser, input_r) == 0)
516N/A break;
516N/A if (parser->data != parser->end)
516N/A return -1;
516N/A /* parsing probably failed because there wasn't enough input.
3234N/A reset the error and try reading more. */
429N/A parser->error = NULL;
429N/A parser->highwater_offset = parser->input->v_offset +
429N/A i_stream_get_data_size(parser->input);
429N/A }
429N/A return ret;
429N/A}
429N/A
429N/Astatic void json_append_escaped_char(string_t *dest, unsigned char src)
429N/A{
429N/A switch (src) {
429N/A case '\b':
429N/A str_append(dest, "\\b");
429N/A break;
429N/A case '\f':
1354N/A str_append(dest, "\\f");
1354N/A break;
1354N/A case '\n':
429N/A str_append(dest, "\\n");
429N/A break;
429N/A case '\r':
429N/A str_append(dest, "\\r");
429N/A break;
429N/A case '\t':
429N/A str_append(dest, "\\t");
429N/A break;
429N/A case '"':
429N/A str_append(dest, "\\\"");
429N/A break;
429N/A case '\\':
429N/A str_append(dest, "\\\\");
429N/A break;
429N/A default:
429N/A if (src < 32)
429N/A str_printfa(dest, "\\u%04x", src);
429N/A else
429N/A str_append_c(dest, src);
429N/A break;
429N/A }
429N/A}
429N/A
1230N/Avoid ostream_escaped_json_format(string_t *dest, unsigned char src)
1230N/A{
1230N/A json_append_escaped_char(dest, src);
1230N/A}
1230N/A
1230N/Avoid json_append_escaped(string_t *dest, const char *src)
1230N/A{
429N/A for (; *src != '\0'; src++)
429N/A json_append_escaped_char(dest, *src);
429N/A}
429N/A
429N/Avoid json_append_escaped_data(string_t *dest, const unsigned char *src, size_t size)
429N/A{
429N/A size_t i;
429N/A
429N/A for (i = 0; i < size; i++)
429N/A json_append_escaped_char(dest, src[i]);
429N/A}
429N/A