From: Stephan Bosch Date: Tue, 8 Oct 2019 18:15:14 +0000 (+0200) Subject: lib: Drop original JSON parser implementation X-Git-Tag: 2.4.0~2358 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43ae376fecee723b74b01091a668db66f38f9b14;p=thirdparty%2Fdovecot%2Fcore.git lib: Drop original JSON parser implementation --- diff --git a/src/lib-json/Makefile.am b/src/lib-json/Makefile.am index 661a88e74f..d0c1ce6437 100644 --- a/src/lib-json/Makefile.am +++ b/src/lib-json/Makefile.am @@ -7,9 +7,9 @@ AM_CPPFLAGS = \ libjson_la_SOURCES = \ json-syntax.c \ json-types.c \ - json-tree.new.c \ + json-tree.c \ json-tree-io.c \ - json-parser.new.c \ + json-parser.c \ json-generator.c \ json-istream.c \ json-ostream.c \ @@ -19,9 +19,9 @@ libjson_la_LIBADD = -lm headers = \ json-syntax.h \ json-types.h \ - json-tree.new.h \ + json-tree.h \ json-tree-io.h \ - json-parser.new.h \ + json-parser.h \ json-generator.h \ json-istream.h \ json-ostream.h \ diff --git a/src/lib-json/json-generator.h b/src/lib-json/json-generator.h index 7a833d99d6..58db575e42 100644 --- a/src/lib-json/json-generator.h +++ b/src/lib-json/json-generator.h @@ -3,9 +3,6 @@ #include "json-types.h" -#define json_append_escaped json_append_escaped_new -#define json_append_escaped_data json_append_escaped_data_new - // FIXME: add settings for formatting/indenting the output struct json_generator; diff --git a/src/lib-json/json-istream.h b/src/lib-json/json-istream.h index cf260f6818..51463df860 100644 --- a/src/lib-json/json-istream.h +++ b/src/lib-json/json-istream.h @@ -1,8 +1,8 @@ #ifndef JSON_ISTREAM_H #define JSON_ISTREAM_H -#include "json-tree.new.h" -#include "json-parser.new.h" +#include "json-tree.h" +#include "json-parser.h" // FIXME: don't bother recording values if we're only validating/skipping diff --git a/src/lib-json/json-ostream.h b/src/lib-json/json-ostream.h index da9d48df18..8f475f1bc4 100644 --- a/src/lib-json/json-ostream.h +++ b/src/lib-json/json-ostream.h @@ -4,7 +4,7 @@ #include "lib.h" #include "json-types.h" -#include "json-tree.new.h" +#include "json-tree.h" #include "json-generator.h" struct json_ostream; diff --git a/src/lib-json/json-parser.new.c b/src/lib-json/json-parser.c similarity index 99% rename from src/lib-json/json-parser.new.c rename to src/lib-json/json-parser.c index f0f734f937..5e248132bc 100644 --- a/src/lib-json/json-parser.new.c +++ b/src/lib-json/json-parser.c @@ -8,7 +8,7 @@ #include "istream-private.h" #include "json-syntax.h" -#include "json-parser.new.h" +#include "json-parser.h" #include #include diff --git a/src/lib-json/json-parser.new.h b/src/lib-json/json-parser.h similarity index 97% rename from src/lib-json/json-parser.new.h rename to src/lib-json/json-parser.h index 0b5a15c3bc..92a8aa1ad9 100644 --- a/src/lib-json/json-parser.new.h +++ b/src/lib-json/json-parser.h @@ -3,9 +3,6 @@ #include "json-types.h" -#define json_parser_init json_parser_new_init -#define json_parser_deinit json_parser_new_deinit - // FIXME: don't bother recording values if we're only validating. /* diff --git a/src/lib-json/json-text.h b/src/lib-json/json-text.h index 644cc1ae16..754c5957c6 100644 --- a/src/lib-json/json-text.h +++ b/src/lib-json/json-text.h @@ -1,7 +1,7 @@ #ifndef JSON_TEXT_H #define JSON_TEXT_H -#include "json-parser.new.h" +#include "json-parser.h" #include "json-generator.h" int json_text_format_data(const void *data, size_t size, diff --git a/src/lib-json/json-tree-io.h b/src/lib-json/json-tree-io.h index dad89915f5..7909baa9c3 100644 --- a/src/lib-json/json-tree-io.h +++ b/src/lib-json/json-tree-io.h @@ -1,8 +1,8 @@ #ifndef JSON_TREE_IO_H #define JSON_TREE_IO_H -#include "json-tree.new.h" -#include "json-parser.new.h" +#include "json-tree.h" +#include "json-parser.h" #include "json-generator.h" /* diff --git a/src/lib-json/json-tree.new.c b/src/lib-json/json-tree.c similarity index 99% rename from src/lib-json/json-tree.new.c rename to src/lib-json/json-tree.c index 2728232a54..4d4689a82c 100644 --- a/src/lib-json/json-tree.new.c +++ b/src/lib-json/json-tree.c @@ -5,7 +5,7 @@ #include "array.h" #include "istream.h" -#include "json-tree.new.h" +#include "json-tree.h" struct json_tree_node_list { struct json_tree_node *head, *tail; diff --git a/src/lib-json/json-tree.new.h b/src/lib-json/json-tree.h similarity index 100% rename from src/lib-json/json-tree.new.h rename to src/lib-json/json-tree.h diff --git a/src/lib-json/test-json-io.c b/src/lib-json/test-json-io.c index ccbefc94e9..b98fca80f5 100644 --- a/src/lib-json/test-json-io.c +++ b/src/lib-json/test-json-io.c @@ -9,7 +9,7 @@ #include "iostream-pump.h" #include "test-common.h" -#include "json-parser.new.h" +#include "json-parser.h" #include "json-generator.h" #include "json-istream.h" #include "json-ostream.h" diff --git a/src/lib-json/test-json-parser.c b/src/lib-json/test-json-parser.c index fdbd7ca3a4..5cb8c1e74d 100644 --- a/src/lib-json/test-json-parser.c +++ b/src/lib-json/test-json-parser.c @@ -7,7 +7,7 @@ #include "istream-base64.h" #include "test-common.h" -#include "json-parser.new.h" +#include "json-parser.h" #include diff --git a/src/lib-json/test-json-tree.c b/src/lib-json/test-json-tree.c index 63c6ccd358..b5fa84bbbb 100644 --- a/src/lib-json/test-json-tree.c +++ b/src/lib-json/test-json-tree.c @@ -6,7 +6,7 @@ #include "ostream.h" #include "test-common.h" -#include "json-tree.new.h" +#include "json-tree.h" #include diff --git a/src/lib-oauth2/oauth2-jwt.c b/src/lib-oauth2/oauth2-jwt.c index 21c807a90c..73df41fcf0 100644 --- a/src/lib-oauth2/oauth2-jwt.c +++ b/src/lib-oauth2/oauth2-jwt.c @@ -9,7 +9,7 @@ #include "hash-method.h" #include "istream.h" #include "iso8601-date.h" -#include "json-tree.new.h" +#include "json-tree.h" #include "array.h" #include "base64.h" #include "str-sanitize.h" diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 6b7996b3d1..94f751288f 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -101,7 +101,6 @@ liblib_la_SOURCES = \ istream-failure-at.c \ istream-file.c \ istream-hash.c \ - istream-jsonstr.c \ istream-limit.c \ istream-multiplex.c \ istream-nonuls.c \ @@ -123,8 +122,6 @@ liblib_la_SOURCES = \ ioloop-select.c \ ioloop-epoll.c \ ioloop-kqueue.c \ - json-parser.c \ - json-tree.c \ lib.c \ lib-event.c \ lib-signals.c \ @@ -270,7 +267,6 @@ headers = \ istream-failure-at.h \ istream-file-private.h \ istream-hash.h \ - istream-jsonstr.h \ istream-multiplex.h \ istream-nonuls.h \ istream-private.h \ @@ -285,8 +281,6 @@ headers = \ ioloop-iolist.h \ ioloop-private.h \ ioloop-notify-fd.h \ - json-parser.h \ - json-tree.h \ lib.h \ lib-event.h \ lib-event-private.h \ @@ -419,7 +413,6 @@ test_lib_SOURCES = \ test-istream-concat.c \ test-istream-crlf.c \ test-istream-failure-at.c \ - test-istream-jsonstr.c \ test-istream-multiplex.c \ test-istream-noop.c \ test-istream-seekable.c \ @@ -427,8 +420,6 @@ test_lib_SOURCES = \ test-istream-tee.c \ test-istream-try.c \ test-istream-unix.c \ - test-json-parser.c \ - test-json-tree.c \ test-lib-event.c \ test-lib-signals.c \ test-llist.c \ diff --git a/src/lib/istream-jsonstr.c b/src/lib/istream-jsonstr.c deleted file mode 100644 index 727f21c3bf..0000000000 --- a/src/lib/istream-jsonstr.c +++ /dev/null @@ -1,217 +0,0 @@ -/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "buffer.h" -#include "hex-dec.h" -#include "unichar.h" -#include "istream-private.h" -#include "istream-jsonstr.h" - -#define MAX_UTF8_LEN 6 - -struct jsonstr_istream { - struct istream_private istream; - - /* The end '"' was found */ - bool str_end:1; -}; - -static int -i_stream_jsonstr_read_parent(struct jsonstr_istream *jstream, - unsigned int min_bytes) -{ - struct istream_private *stream = &jstream->istream; - size_t size, avail; - ssize_t ret; - - size = i_stream_get_data_size(stream->parent); - while (size < min_bytes) { - ret = i_stream_read_memarea(stream->parent); - if (ret <= 0) { - if (ret == -2) { - /* tiny parent buffer size - shouldn't happen */ - return -2; - } - stream->istream.stream_errno = - stream->parent->stream_errno; - stream->istream.eof = stream->parent->eof; - if (ret == -1 && stream->istream.stream_errno == 0) { - io_stream_set_error(&stream->iostream, - "EOF before trailing <\"> was seen"); - stream->istream.stream_errno = EPIPE; - } - return ret; - } - size = i_stream_get_data_size(stream->parent); - } - - if (!i_stream_try_alloc(stream, size, &avail)) - return -2; - return 1; -} - -static int -i_stream_json_unescape(const unsigned char *src, size_t len, - unsigned char *dest, - unsigned int *src_size_r, unsigned int *dest_size_r) -{ - switch (*src) { - case '"': - case '\\': - case '/': - *dest = *src; - break; - case 'b': - *dest = '\b'; - break; - case 'f': - *dest = '\f'; - break; - case 'n': - *dest = '\n'; - break; - case 'r': - *dest = '\r'; - break; - case 't': - *dest = '\t'; - break; - case 'u': { - char chbuf[5] = {0}; - unichar_t chr,chr2 = 0; - buffer_t buf; - if (len < 5) - return 5; - buffer_create_from_data(&buf, dest, MAX_UTF8_LEN); - memcpy(chbuf, src+1, 4); - if (str_to_uint32_hex(chbuf, &chr)<0) - return -1; - if (UTF16_VALID_LOW_SURROGATE(chr)) - return -1; - /* if we encounter surrogate, we need another \\uxxxx */ - if (UTF16_VALID_HIGH_SURROGATE(chr)) { - if (len < 5+2+4) - return 5+2+4; - if (src[5] != '\\' && src[6] != 'u') - return -1; - memcpy(chbuf, src+7, 4); - if (str_to_uint32_hex(chbuf, &chr2)<0) - return -1; - if (!UTF16_VALID_LOW_SURROGATE(chr2)) - return -1; - chr = uni_join_surrogate(chr, chr2); - } - if (!uni_is_valid_ucs4(chr)) - return -1; - uni_ucs4_to_utf8_c(chr, &buf); - *src_size_r = 5 + (chr2>0?6:0); - *dest_size_r = buf.used; - return 0; - } - default: - return -1; - } - *src_size_r = 1; - *dest_size_r = 1; - return 0; -} - -static ssize_t i_stream_jsonstr_read(struct istream_private *stream) -{ - struct jsonstr_istream *jstream = - container_of(stream, struct jsonstr_istream, istream); - const unsigned char *data; - unsigned int srcskip, destskip, extra; - size_t i, dest, size; - ssize_t ret, ret2; - - if (jstream->str_end) { - stream->istream.eof = TRUE; - return -1; - } - - ret = i_stream_jsonstr_read_parent(jstream, 1); - if (ret <= 0) - return ret; - - /* @UNSAFE */ - dest = stream->pos; - extra = 0; - - data = i_stream_get_data(stream->parent, &size); - for (i = 0; i < size && dest < stream->buffer_size; ) { - if (data[i] == '"') { - jstream->str_end = TRUE; - if (dest == stream->pos) { - stream->istream.eof = TRUE; - return -1; - } - break; - } else if (data[i] == '\\') { - if (i+1 == size) { - /* not enough input for \x */ - extra = 1; - break; - } - if (data[i+1] == 'u' && stream->buffer_size - dest < MAX_UTF8_LEN) { - /* UTF8 output is max. 6 chars */ - if (dest == stream->pos) - return -2; - break; - } - i++; - if ((ret2 = i_stream_json_unescape(data + i, size - i, - stream->w_buffer + dest, - &srcskip, &destskip)) < 0) { - /* invalid string */ - io_stream_set_error(&stream->iostream, - "Invalid JSON string"); - stream->istream.stream_errno = EINVAL; - return -1; - } else if (ret2 > 0) { - /* we need to get more bytes, do not consume - escape slash */ - i--; - extra = ret2; - break; - } - i += srcskip; - i_assert(i <= size); - dest += destskip; - i_assert(dest <= stream->buffer_size); - } else { - stream->w_buffer[dest++] = data[i]; - i++; - } - } - i_stream_skip(stream->parent, i); - - ret = dest - stream->pos; - if (ret == 0) { - /* not enough input */ - i_assert(i == 0); - i_assert(extra > 0); - ret = i_stream_jsonstr_read_parent(jstream, extra+1); - if (ret <= 0) - return ret; - return i_stream_jsonstr_read(stream); - } - i_assert(ret > 0); - stream->pos = dest; - return ret; -} - -struct istream *i_stream_create_jsonstr(struct istream *input) -{ - struct jsonstr_istream *dstream; - - dstream = i_new(struct jsonstr_istream, 1); - dstream->istream.max_buffer_size = input->real_stream->max_buffer_size; - dstream->istream.read = i_stream_jsonstr_read; - - dstream->istream.istream.readable_fd = FALSE; - dstream->istream.istream.blocking = input->blocking; - dstream->istream.istream.seekable = FALSE; - return i_stream_create(&dstream->istream, input, - i_stream_get_fd(input), 0); -} diff --git a/src/lib/istream-jsonstr.h b/src/lib/istream-jsonstr.h deleted file mode 100644 index 255eccd89e..0000000000 --- a/src/lib/istream-jsonstr.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ISTREAM_JSONSTR_H -#define ISTREAM_JSONSTR_H - -/* Parse input until '"' is reached. Unescape JSON \x codes. */ -struct istream *i_stream_create_jsonstr(struct istream *input); - -#endif diff --git a/src/lib/json-parser.c b/src/lib/json-parser.c deleted file mode 100644 index 459833c98d..0000000000 --- a/src/lib/json-parser.c +++ /dev/null @@ -1,849 +0,0 @@ -/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "str.h" -#include "istream.h" -#include "hex-dec.h" -#include "unichar.h" -#include "istream-jsonstr.h" -#include "json-parser.h" - -enum json_state { - JSON_STATE_ROOT = 0, - JSON_STATE_OBJECT_OPEN, - JSON_STATE_OBJECT_KEY, - JSON_STATE_OBJECT_COLON, - JSON_STATE_OBJECT_VALUE, - JSON_STATE_OBJECT_SKIP_STRING, - JSON_STATE_OBJECT_NEXT, - JSON_STATE_ARRAY_OPEN, - JSON_STATE_ARRAY_VALUE, - JSON_STATE_ARRAY_SKIP_STRING, - JSON_STATE_ARRAY_NEXT, - JSON_STATE_ARRAY_NEXT_SKIP, - JSON_STATE_VALUE, - JSON_STATE_DONE -}; - -struct json_parser { - pool_t pool; - struct istream *input; - uoff_t highwater_offset; - enum json_parser_flags flags; - - const unsigned char *start, *end, *data; - const char *error; - string_t *value; - struct istream *strinput; - - enum json_state state; - ARRAY(enum json_state) nesting; - unsigned int nested_skip_count; - - bool skipping; - bool seen_eof; -}; - -static int json_parser_read_more(struct json_parser *parser) -{ - uoff_t cur_highwater = parser->input->v_offset + - i_stream_get_data_size(parser->input); - size_t size; - ssize_t ret; - - i_assert(parser->highwater_offset <= cur_highwater); - - if (parser->error != NULL) - return -1; - - if (parser->highwater_offset == cur_highwater) { - ret = i_stream_read(parser->input); - if (ret == -2) { - parser->error = "Token too large"; - return -1; - } - if (ret < 0 && !parser->seen_eof && - i_stream_get_data_size(parser->input) > 0 && - parser->input->stream_errno == 0) { - /* call it once more to finish any pending number */ - parser->seen_eof = TRUE; - } else if (ret <= 0) { - return ret; - } else { - cur_highwater = parser->input->v_offset + - i_stream_get_data_size(parser->input); - i_assert(parser->highwater_offset < cur_highwater); - parser->highwater_offset = cur_highwater; - } - } - - parser->start = parser->data = i_stream_get_data(parser->input, &size); - parser->end = parser->start + size; - i_assert(size > 0); - return 1; -} - -static void json_parser_update_input_pos(struct json_parser *parser) -{ - size_t size; - - if (parser->data == parser->start) - return; - - i_stream_skip(parser->input, parser->data - parser->start); - parser->start = parser->data = i_stream_get_data(parser->input, &size); - parser->end = parser->start + size; - if (size > 0) { - /* we skipped over some data and there's still data left. - no need to read() the next time. */ - parser->highwater_offset = 0; - } else { - parser->highwater_offset = parser->input->v_offset; - } -} - -struct json_parser *json_parser_init(struct istream *input) -{ - return json_parser_init_flags(input, 0); -} - -struct json_parser *json_parser_init_flags(struct istream *input, - enum json_parser_flags flags) -{ - struct json_parser *parser; - pool_t pool = pool_alloconly_create("json parser", - sizeof(struct json_parser)+64); - - parser = p_new(pool, struct json_parser, 1); - parser->pool = pool; - parser->input = input; - parser->flags = flags; - parser->value = str_new(default_pool, 128); - i_array_init(&parser->nesting, 8); - i_stream_ref(input); - - if ((flags & JSON_PARSER_NO_ROOT_OBJECT) != 0) - parser->state = JSON_STATE_VALUE; - return parser; -} - -int json_parser_deinit(struct json_parser **_parser, const char **error_r) -{ - struct json_parser *parser = *_parser; - - *_parser = NULL; - - if (parser->error != NULL) { - /* actual parser error */ - *error_r = t_strdup(parser->error); - } else if (parser->input->stream_errno != 0) { - *error_r = t_strdup_printf("read(%s) failed: %s", - i_stream_get_name(parser->input), - i_stream_get_error(parser->input)); - } else if (parser->data == parser->end && - parser->state != JSON_STATE_DONE) { - *error_r = "Missing '}'"; - } else { - *error_r = NULL; - } - - i_stream_unref(&parser->input); - array_free(&parser->nesting); - str_free(&parser->value); - pool_unref(&parser->pool); - return *error_r != NULL ? -1 : 0; -} - -static bool json_parse_whitespace(struct json_parser *parser) -{ - for (; parser->data != parser->end; parser->data++) { - switch (*parser->data) { - case ' ': - case '\t': - case '\r': - case '\n': - break; - default: - json_parser_update_input_pos(parser); - return TRUE; - } - } - json_parser_update_input_pos(parser); - return FALSE; -} - -static int json_skip_string(struct json_parser *parser) -{ - for (; parser->data != parser->end; parser->data++) { - if (*parser->data == '"') { - parser->data++; - json_parser_update_input_pos(parser); - return 1; - } - if (*parser->data == '\\') { - parser->data++; - if (parser->data == parser->end) - break; - switch (*parser->data) { - case '"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - break; - case 'u': - if (parser->end - parser->data < 4) { - parser->data = parser->end; - return -1; - } - parser->data += 3; - break; - default: - parser->error = "Invalid escape string"; - return -1; - } - } - } - json_parser_update_input_pos(parser); - return 0; -} - -static int json_parse_unicode_escape(struct json_parser *parser) -{ - char chbuf[5] = {0}; - unichar_t chr, hi_surg; - - parser->data++; - if (parser->end - parser->data < 4) { - /* wait for more data */ - parser->data = parser->end; - return 0; - } - memcpy(chbuf, parser->data, 4); - if (str_to_uint32_hex(chbuf, &chr) < 0) { - parser->error = "Invalid unicode escape seen"; - return -1; - } - if (UTF16_VALID_HIGH_SURROGATE(chr)) { - /* possible surrogate pair */ - hi_surg = chr; - chr = 0; - parser->data += 4; - if (parser->data >= parser->end) { - /* wait for more data */ - parser->data = parser->end; - return 0; - } - if ((parser->end - parser->data) < 2) { - if (parser->data[0] == '\\') { - /* wait for more data */ - parser->data = parser->end; - return 0; - } - /* error */ - } - if ((parser->end - parser->data) < 6) { - if (parser->data[0] == '\\' && - parser->data[1] == 'u') { - /* wait for more data */ - parser->data = parser->end; - return 0; - } - /* error */ - } else { - memcpy(chbuf, &parser->data[2], 4); - if (str_to_uint32_hex(chbuf, &chr) < 0) { - parser->error = "Invalid unicode escape seen"; - return -1; - } - } - if (parser->data[0] != '\\' || parser->data[1] != 'u' || - !UTF16_VALID_LOW_SURROGATE(chr)) { - parser->error = p_strdup_printf(parser->pool, - "High surrogate 0x%04x seen, " - "but not followed by low surrogate", hi_surg); - return -1; - } - chr = uni_join_surrogate(hi_surg, chr); - parser->data += 2; - } - - if (!uni_is_valid_ucs4(chr)) { - parser->error = p_strdup_printf(parser->pool, - "Invalid unicode character U+%04x", chr); - return -1; - } - if (chr == 0) { - parser->error = "\\u0000 not supported in strings"; - return -1; - } - uni_ucs4_to_utf8_c(chr, parser->value); - parser->data += 3; - return 1; -} - -static int json_parse_string(struct json_parser *parser, bool allow_skip, - const char **value_r) -{ - int ret; - - if (*parser->data != '"') - return -1; - parser->data++; - - if (parser->skipping && allow_skip) { - *value_r = NULL; - return json_skip_string(parser); - } - - str_truncate(parser->value, 0); - for (; parser->data != parser->end; parser->data++) { - if (*parser->data == '"') { - parser->data++; - *value_r = str_c(parser->value); - return 1; - } - switch (*parser->data) { - case '\\': - if (++parser->data == parser->end) - return 0; - switch (*parser->data) { - case '"': - case '\\': - case '/': - str_append_c(parser->value, *parser->data); - break; - case 'b': - str_append_c(parser->value, '\b'); - break; - case 'f': - str_append_c(parser->value, '\f'); - break; - case 'n': - str_append_c(parser->value, '\n'); - break; - case 'r': - str_append_c(parser->value, '\r'); - break; - case 't': - str_append_c(parser->value, '\t'); - break; - case 'u': - if ((ret=json_parse_unicode_escape(parser)) <= 0) - return ret; - break; - default: - parser->error = "Invalid escape string"; - return -1; - } - break; - case '\0': - parser->error = "NULs not supported in strings"; - return -1; - default: - str_append_c(parser->value, *parser->data); - break; - } - } - return 0; -} - -static int -json_parse_digits(struct json_parser *parser) -{ - if (parser->data == parser->end) - return 0; - if (*parser->data < '0' || *parser->data > '9') - return -1; - - while (parser->data != parser->end && - *parser->data >= '0' && *parser->data <= '9') - str_append_c(parser->value, *parser->data++); - return 1; -} - -static int json_parse_int(struct json_parser *parser) -{ - int ret; - - if (*parser->data == '-') { - str_append_c(parser->value, *parser->data++); - if (parser->data == parser->end) - return 0; - } - if (*parser->data == '0') - str_append_c(parser->value, *parser->data++); - else { - if ((ret = json_parse_digits(parser)) <= 0) - return ret; - } - return 1; -} - -static int json_parse_number(struct json_parser *parser, const char **value_r) -{ - int ret; - - str_truncate(parser->value, 0); - if ((ret = json_parse_int(parser)) <= 0) - return ret; - if (parser->data != parser->end && *parser->data == '.') { - /* frac */ - str_append_c(parser->value, *parser->data++); - if ((ret = json_parse_digits(parser)) <= 0) - 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) -{ - size_t 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_denest(struct json_parser *parser) -{ - const enum json_state *nested_states; - unsigned int count; - - parser->data++; - json_parser_update_input_pos(parser); - - nested_states = array_get(&parser->nesting, &count); - i_assert(count > 0); - if (count == 1) { - /* closing root */ - parser->state = JSON_STATE_DONE; - if ((parser->flags & JSON_PARSER_NO_ROOT_OBJECT) == 0) - return 0; - /* we want to return the ending "]" or "}" to caller */ - return 1; - } - - /* closing a nested object */ - parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ? - JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT; - array_delete(&parser->nesting, count-1, 1); - - if (parser->nested_skip_count > 0) { - parser->nested_skip_count--; - return 0; - } - return 1; -} - -static int -json_parse_close_object(struct json_parser *parser, enum json_type *type_r) -{ - if (json_parse_denest(parser) == 0) - return 0; - *type_r = JSON_TYPE_OBJECT_END; - return 1; -} - -static int -json_parse_close_array(struct json_parser *parser, enum json_type *type_r) -{ - if (json_parse_denest(parser) == 0) - return 0; - *type_r = JSON_TYPE_ARRAY_END; - return 1; -} - -static void json_parser_object_open(struct json_parser *parser) -{ - parser->data++; - parser->state = JSON_STATE_OBJECT_OPEN; - array_push_back(&parser->nesting, &parser->state); - json_parser_update_input_pos(parser); -} - -static int -json_try_parse_next(struct json_parser *parser, enum json_type *type_r, - const char **value_r) -{ - bool skipping = parser->skipping; - 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; - } - json_parser_object_open(parser); - return 0; - case JSON_STATE_OBJECT_VALUE: - case JSON_STATE_ARRAY_VALUE: - case JSON_STATE_VALUE: - if (*parser->data == '{') { - json_parser_object_open(parser); - - if (parser->skipping) { - parser->nested_skip_count++; - return 0; - } - *type_r = JSON_TYPE_OBJECT; - return 1; - } else if (*parser->data == '[') { - parser->data++; - parser->state = JSON_STATE_ARRAY_OPEN; - array_push_back(&parser->nesting, &parser->state); - json_parser_update_input_pos(parser); - - if (parser->skipping) { - parser->nested_skip_count++; - return 0; - } - *type_r = JSON_TYPE_ARRAY; - return 1; - } - - if ((ret = json_parse_string(parser, TRUE, 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 { - if (parser->error == NULL) - parser->error = "Invalid data as value"; - return -1; - } - if (ret == 0) { - i_assert(parser->data == parser->end); - if (parser->skipping && *type_r == JSON_TYPE_STRING) { - /* a large string that we want to skip over. */ - json_parser_update_input_pos(parser); - parser->state = parser->state == JSON_STATE_OBJECT_VALUE ? - JSON_STATE_OBJECT_SKIP_STRING : - JSON_STATE_ARRAY_SKIP_STRING; - return 0; - } - return -1; - } - switch (parser->state) { - case JSON_STATE_OBJECT_VALUE: - parser->state = JSON_STATE_OBJECT_NEXT; - break; - case JSON_STATE_ARRAY_VALUE: - parser->state = JSON_STATE_ARRAY_NEXT; - break; - case JSON_STATE_VALUE: - parser->state = JSON_STATE_DONE; - break; - default: - i_unreached(); - } - break; - case JSON_STATE_OBJECT_OPEN: - if (*parser->data == '}') - return json_parse_close_object(parser, type_r); - parser->state = JSON_STATE_OBJECT_KEY; - /* fall through */ - case JSON_STATE_OBJECT_KEY: - if (json_parse_string(parser, FALSE, 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 0; - case JSON_STATE_OBJECT_NEXT: - if (parser->skipping && parser->nested_skip_count == 0) { - /* we skipped over the previous value */ - parser->skipping = FALSE; - } - if (*parser->data == '}') - return json_parse_close_object(parser, type_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 0; - case JSON_STATE_ARRAY_OPEN: - if (*parser->data == ']') - return json_parse_close_array(parser, type_r); - parser->state = JSON_STATE_ARRAY_VALUE; - return 0; - case JSON_STATE_ARRAY_NEXT: - if (parser->skipping && parser->nested_skip_count == 0) { - /* we skipped over the previous value */ - parser->skipping = FALSE; - } - /* fall through */ - case JSON_STATE_ARRAY_NEXT_SKIP: - if (*parser->data == ']') - return json_parse_close_array(parser, type_r); - if (*parser->data != ',') { - parser->error = "Expected ',' or '}' after array value"; - return -1; - } - parser->state = JSON_STATE_ARRAY_VALUE; - parser->data++; - json_parser_update_input_pos(parser); - return 0; - case JSON_STATE_OBJECT_SKIP_STRING: - case JSON_STATE_ARRAY_SKIP_STRING: - if (json_skip_string(parser) <= 0) - return -1; - parser->state = parser->state == JSON_STATE_OBJECT_SKIP_STRING ? - JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT; - return 0; - case JSON_STATE_DONE: - parser->error = "Unexpected data at the end"; - return -1; - } - json_parser_update_input_pos(parser); - return skipping ? 0 : 1; -} - -int json_parse_next(struct json_parser *parser, enum json_type *type_r, - const char **value_r) -{ - int ret; - - i_assert(parser->strinput == NULL); - - *value_r = NULL; - - while ((ret = json_parser_read_more(parser)) > 0) { - while ((ret = json_try_parse_next(parser, type_r, value_r)) == 0) - ; - if (ret > 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; - parser->highwater_offset = parser->input->v_offset + - i_stream_get_data_size(parser->input); - } - return ret; -} - -void json_parse_skip_next(struct json_parser *parser) -{ - i_assert(!parser->skipping); - i_assert(parser->strinput == NULL); - i_assert(parser->state == JSON_STATE_OBJECT_COLON || - parser->state == JSON_STATE_OBJECT_VALUE || - parser->state == JSON_STATE_ARRAY_VALUE || - parser->state == JSON_STATE_ARRAY_NEXT); - - parser->skipping = TRUE; - if (parser->state == JSON_STATE_ARRAY_NEXT) - parser->state = JSON_STATE_ARRAY_NEXT_SKIP; -} - -void json_parse_skip(struct json_parser *parser) -{ - i_assert(!parser->skipping); - i_assert(parser->strinput == NULL); - i_assert(parser->state == JSON_STATE_OBJECT_NEXT || - parser->state == JSON_STATE_OBJECT_OPEN || - parser->state == JSON_STATE_ARRAY_NEXT || - parser->state == JSON_STATE_ARRAY_OPEN); - - if (parser->state == JSON_STATE_OBJECT_OPEN || - parser->state == JSON_STATE_ARRAY_OPEN) - parser->nested_skip_count++; - - parser->skipping = TRUE; - if (parser->state == JSON_STATE_ARRAY_NEXT) - parser->state = JSON_STATE_ARRAY_NEXT_SKIP; -} - -static void json_strinput_destroyed(struct json_parser *parser) -{ - i_assert(parser->strinput != NULL); - - parser->strinput = NULL; -} - -static int -json_try_parse_stream_start(struct json_parser *parser, - struct istream **input_r) -{ - if (!json_parse_whitespace(parser)) - return -1; - - if (parser->state == JSON_STATE_OBJECT_COLON) { - if (*parser->data != ':') { - parser->error = "Expected ':' after key"; - return -1; - } - parser->data++; - parser->state = JSON_STATE_OBJECT_VALUE; - if (!json_parse_whitespace(parser)) - return -1; - } - - if (*parser->data != '"') - return -1; - parser->data++; - json_parser_update_input_pos(parser); - - parser->state = parser->state == JSON_STATE_OBJECT_VALUE ? - JSON_STATE_OBJECT_SKIP_STRING : JSON_STATE_ARRAY_SKIP_STRING; - parser->strinput = i_stream_create_jsonstr(parser->input); - i_stream_add_destroy_callback(parser->strinput, - json_strinput_destroyed, parser); - - *input_r = parser->strinput; - return 0; -} - -int json_parse_next_stream(struct json_parser *parser, - struct istream **input_r) -{ - int ret; - - i_assert(!parser->skipping); - i_assert(parser->strinput == NULL); - i_assert(parser->state == JSON_STATE_OBJECT_COLON || - parser->state == JSON_STATE_OBJECT_VALUE || - parser->state == JSON_STATE_ARRAY_VALUE); - - *input_r = NULL; - - while ((ret = json_parser_read_more(parser)) > 0) { - if (json_try_parse_stream_start(parser, input_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; - parser->highwater_offset = parser->input->v_offset + - i_stream_get_data_size(parser->input); - } - return ret; -} - -static void json_append_escaped_char(string_t *dest, unsigned char src) -{ - switch (src) { - case '\b': - str_append(dest, "\\b"); - break; - case '\f': - str_append(dest, "\\f"); - break; - case '\n': - str_append(dest, "\\n"); - break; - case '\r': - str_append(dest, "\\r"); - break; - case '\t': - str_append(dest, "\\t"); - break; - case '"': - str_append(dest, "\\\""); - break; - case '\\': - str_append(dest, "\\\\"); - break; - default: - if (src < 0x20 || src >= 0x80) - str_printfa(dest, "\\u%04x", src); - else - str_append_c(dest, src); - break; - } -} - -void json_append_escaped_ucs4(string_t *dest, unichar_t chr) -{ - if (chr < 0x80) - json_append_escaped_char(dest, (unsigned char)chr); - else if (chr == 0x2028 || chr == 0x2029) - str_printfa(dest, "\\u%04x", chr); - else - uni_ucs4_to_utf8_c(chr, dest); -} - -void ostream_escaped_json_format(string_t *dest, unsigned char src) -{ - json_append_escaped_char(dest, src); -} - -void json_append_escaped(string_t *dest, const char *src) -{ - json_append_escaped_data(dest, (const unsigned char*)src, strlen(src)); -} - -void json_append_escaped_data(string_t *dest, const unsigned char *src, size_t size) -{ - size_t i; - int bytes = 0; - unichar_t chr; - - for (i = 0; i < size;) { - bytes = uni_utf8_get_char_n(src+i, size-i, &chr); - if (bytes > 0 && uni_is_valid_ucs4(chr)) { - json_append_escaped_ucs4(dest, chr); - i += bytes; - } else { - str_append_data(dest, UNICODE_REPLACEMENT_CHAR_UTF8, - UTF8_REPLACEMENT_CHAR_LEN); - i++; - } - } -} diff --git a/src/lib/json-parser.h b/src/lib/json-parser.h deleted file mode 100644 index 745f4a771e..0000000000 --- a/src/lib/json-parser.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef JSON_PARSER_H -#define JSON_PARSER_H - -#include "unichar.h" - -enum json_type { - /* { key: */ - JSON_TYPE_OBJECT_KEY, - /* : { new object */ - JSON_TYPE_OBJECT, - /* } (not returned for the root object) */ - JSON_TYPE_OBJECT_END, - - JSON_TYPE_ARRAY, - JSON_TYPE_ARRAY_END, - - JSON_TYPE_STRING, - JSON_TYPE_NUMBER, - JSON_TYPE_TRUE, - JSON_TYPE_FALSE, - JSON_TYPE_NULL -}; - -enum json_parser_flags { - /* By default we assume that the input is an object and parsing skips - the root level "{" and "}". If this flag is set, it's possible to - parse any other type of JSON values directly. */ - JSON_PARSER_NO_ROOT_OBJECT = 0x01 -}; - -/* Parse JSON tokens from the input stream. */ -struct json_parser *json_parser_init(struct istream *input); -struct json_parser *json_parser_init_flags(struct istream *input, - enum json_parser_flags flags); - -int json_parser_deinit(struct json_parser **parser, const char **error_r); - -/* Parse the next token. Returns 1 if found, 0 if more input stream is - non-blocking and needs more input, -1 if input stream is at EOF. */ -int json_parse_next(struct json_parser *parser, enum json_type *type_r, - const char **value_r); -/* Skip the next object value. If it's an object, its members are also - skipped. */ -void json_parse_skip_next(struct json_parser *parser); -/* Skip the remainder of the value parsed earlier by json_parse_next(). */ -void json_parse_skip(struct json_parser *parser); -/* Return the following string as input stream. Returns 1 if ok, 0 if - input stream is non-blocking and needs more input, -1 if the next token - isn't a string (call json_parse_next()). */ -int json_parse_next_stream(struct json_parser *parser, - struct istream **input_r); - -/* Append UCS4 to already opened JSON string. */ -void json_append_escaped_ucs4(string_t *dest, unichar_t chr); -/* Append data to already opened JSON string. src should be valid UTF-8 data. */ -void json_append_escaped(string_t *dest, const char *src); -/* Same as json_append_escaped(), but append non-\0 terminated input. */ -void json_append_escaped_data(string_t *dest, const unsigned char *src, size_t size); -void ostream_escaped_json_format(string_t *dest, unsigned char src); - -#endif diff --git a/src/lib/json-tree.c b/src/lib/json-tree.c deleted file mode 100644 index cb721c2b97..0000000000 --- a/src/lib/json-tree.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "json-tree.h" - -struct json_tree { - pool_t pool; - struct json_tree_node *root, *cur, *cur_child; -}; - -struct json_tree * -json_tree_init_type(enum json_type container) -{ - struct json_tree *tree; - pool_t pool; - - pool = pool_alloconly_create("json tree", 1024); - tree = p_new(pool, struct json_tree, 1); - tree->pool = pool; - tree->root = tree->cur = p_new(tree->pool, struct json_tree_node, 1); - tree->cur->value_type = container == JSON_TYPE_ARRAY ? container : JSON_TYPE_OBJECT; - return tree; -} - -void json_tree_deinit(struct json_tree **_tree) -{ - struct json_tree *tree = *_tree; - - *_tree = NULL; - pool_unref(&tree->pool); -} - -static void -json_tree_append_child(struct json_tree *tree, enum json_type type, - const char *value) -{ - struct json_tree_node *node; - - node = p_new(tree->pool, struct json_tree_node, 1); - node->parent = tree->cur; - node->value_type = type; - node->value.str = p_strdup(tree->pool, value); - - if (tree->cur_child == NULL) - tree->cur->value.child = node; - else - tree->cur_child->next = node; - tree->cur_child = node; -} - -static void -json_tree_set_cur(struct json_tree *tree, struct json_tree_node *node) -{ - tree->cur = node; - tree->cur_child = tree->cur->value.child; - if (tree->cur_child != NULL) { - while (tree->cur_child->next != NULL) - tree->cur_child = tree->cur_child->next; - } -} - -static int -json_tree_append_value(struct json_tree *tree, enum json_type type, - const char *value) -{ - switch (tree->cur->value_type) { - case JSON_TYPE_OBJECT_KEY: - /* "key": value - we already added the node and set its key, - so now just set the value */ - tree->cur->value_type = type; - tree->cur->value.str = p_strdup(tree->pool, value); - json_tree_set_cur(tree, tree->cur->parent); - break; - case JSON_TYPE_ARRAY: - /* element in array - add a new node */ - json_tree_append_child(tree, type, value); - break; - default: - return -1; - } - return 0; -} - -int json_tree_append(struct json_tree *tree, enum json_type type, - const char *value) -{ - switch (type) { - case JSON_TYPE_OBJECT_KEY: - if (tree->cur->value_type != JSON_TYPE_OBJECT) - return -1; - json_tree_append_child(tree, type, NULL); - json_tree_set_cur(tree, tree->cur_child); - tree->cur->key = p_strdup(tree->pool, value); - break; - case JSON_TYPE_ARRAY: - if (json_tree_append_value(tree, type, NULL) < 0) - return -1; - json_tree_set_cur(tree, tree->cur_child); - break; - case JSON_TYPE_OBJECT: - if (tree->cur->value_type == JSON_TYPE_OBJECT_KEY) - tree->cur->value_type = JSON_TYPE_OBJECT; - else if (tree->cur->value_type == JSON_TYPE_ARRAY) { - json_tree_append_child(tree, type, NULL); - json_tree_set_cur(tree, tree->cur_child); - } else { - return -1; - } - break; - case JSON_TYPE_OBJECT_END: - if (tree->cur->parent == NULL || - tree->cur->value_type != JSON_TYPE_OBJECT) - return -1; - json_tree_set_cur(tree, tree->cur->parent); - break; - case JSON_TYPE_ARRAY_END: - if (tree->cur->parent == NULL || - tree->cur->value_type != JSON_TYPE_ARRAY) - return -1; - json_tree_set_cur(tree, tree->cur->parent); - break; - case JSON_TYPE_STRING: - case JSON_TYPE_NUMBER: - case JSON_TYPE_TRUE: - case JSON_TYPE_FALSE: - case JSON_TYPE_NULL: - if (json_tree_append_value(tree, type, value) < 0) - return -1; - break; - } - return 0; -} - -const struct json_tree_node * -json_tree_root(const struct json_tree *tree) -{ - return tree->root; -} - -const struct json_tree_node * -json_tree_find_key(const struct json_tree_node *node, const char *key) -{ - i_assert(node->value_type == JSON_TYPE_OBJECT); - - node = json_tree_get_child(node); - for (; node != NULL; node = node->next) { - if (node->key != NULL && strcmp(node->key, key) == 0) - return node; - } - return NULL; -} - -const struct json_tree_node * -json_tree_find_child_with(const struct json_tree_node *node, - const char *key, const char *value) -{ - const struct json_tree_node *child; - - i_assert(node->value_type == JSON_TYPE_OBJECT || - node->value_type == JSON_TYPE_ARRAY); - - for (node = json_tree_get_child(node); node != NULL; node = node->next) { - if (node->value_type != JSON_TYPE_OBJECT) - continue; - - child = json_tree_find_key(node, key); - if (child != NULL && - json_tree_get_value_str(child) != NULL && - strcmp(json_tree_get_value_str(child), value) == 0) - return node; - } - return NULL; -} diff --git a/src/lib/json-tree.h b/src/lib/json-tree.h deleted file mode 100644 index a995c755be..0000000000 --- a/src/lib/json-tree.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef JSON_TREE_H -#define JSON_TREE_H - -#include "json-parser.h" - -/* Direct access to this structure is not encouraged, use the inline - function accessors where possible, so that the implementation - details can remain fluid, or, even better, hidden. */ -struct json_tree_node { - /* object key, or NULL if we're in a list */ - const char *key; - struct json_tree_node *parent, *next; - - enum json_type value_type; - struct { - /* for JSON_TYPE_OBJECT and JSON_TYPE_ARRAY */ - struct json_tree_node *child; - /* for other types */ - const char *str; - } value; -}; -static inline ATTR_PURE const struct json_tree_node *json_tree_get_child(const struct json_tree_node *node) -{ - return node->value.child; -} -static inline ATTR_PURE const char *json_tree_get_value_str(const struct json_tree_node *node) -{ - return node->value.str; -} - -/* You can build a list or an object, nothing else. */ -struct json_tree *json_tree_init_type(enum json_type container); -static inline struct json_tree *json_tree_init(void) -{ - return json_tree_init_type(JSON_TYPE_OBJECT); -} -static inline struct json_tree *json_tree_init_array(void) -{ - return json_tree_init_type(JSON_TYPE_ARRAY); -} - -void json_tree_deinit(struct json_tree **tree); - -/* Append data to a tree. The type/value should normally come from json-parser. - Returns 0 on success, -1 if the input was invalid (which should never happen - if it's coming from json-parser). */ -int json_tree_append(struct json_tree *tree, enum json_type type, - const char *value); - -/* Return the root node. */ -const struct json_tree_node * -json_tree_root(const struct json_tree *tree); -/* Find a node with the specified key from an OBJECT node */ -const struct json_tree_node * -json_tree_find_key(const struct json_tree_node *node, const char *key); -/* Find an object node (from an array), which contains the specified key=value - in its values. */ -const struct json_tree_node * -json_tree_find_child_with(const struct json_tree_node *node, - const char *key, const char *value); - -#endif diff --git a/src/lib/test-istream-jsonstr.c b/src/lib/test-istream-jsonstr.c deleted file mode 100644 index 7b432e893c..0000000000 --- a/src/lib/test-istream-jsonstr.c +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ - -#include "test-lib.h" -#include "str.h" -#include "istream-private.h" -#include "istream-jsonstr.h" - -static const struct { - const char *input; - const char *output; - int stream_errno; -} tests[] = { - { "foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\uffff\"", - "foo\\\"\b\f\n\r\t\001\xEF\xBF\xBF", 0 }, - { "\\ud801\\udc37\"", "\xf0\x90\x90\xb7", 0 }, /* valid codepoint */ - { "\"", "", 0 }, - { "foo\\?\"", "foo", EINVAL }, - { "foo\\?\"", "foo", EINVAL }, - { "", "", EPIPE }, - { "\\\"", "\"", EPIPE }, - { "foo", "foo", EPIPE }, - { "\\ud801", "", EPIPE }, /* high surrogate alone */ - { "\\udced\\udc37\"", "", EINVAL }, /* low surrogate before high */ - { "\\ud8011\\udc37\"", "", EINVAL }, /* has extra 1 in middle */ - { "hello \\udc37\"", "hello ", EINVAL }, /* low surrogate before high with valid prefix*/ - { "hello \\ud801", "hello ", EPIPE }, /* high surrogate alone with valid prefix */ - { "\\uabcg", "", EINVAL }, /* invalid hex value */ -}; - -static void -run_test_buffer(const char *json_input, const char *output, int stream_errno, - unsigned int skip_count) -{ - size_t json_input_len = strlen(json_input); - struct istream *input_data, *input; - const unsigned char *data; - size_t i, size; - ssize_t ret = 0; - - input_data = test_istream_create_data(json_input, json_input_len); - test_istream_set_allow_eof(input_data, FALSE); - input = i_stream_create_jsonstr(input_data); - - for (i = 1; i < json_input_len;) { - test_istream_set_size(input_data, i); - while ((ret = i_stream_read(input)) > 0) ; - if (ret == -1 && stream_errno != 0) - break; - test_assert_idx(ret == 0, i); - if (i + skip_count < json_input_len) - i += skip_count; - else - i++; - } - test_istream_set_allow_eof(input_data, TRUE); - test_istream_set_size(input_data, json_input_len); - ret = i_stream_read(input); - while (ret > 0 && stream_errno != 0) - ret = i_stream_read(input); - test_assert(ret == -1); - test_assert(input->stream_errno == stream_errno); - - if (stream_errno == 0) { - data = i_stream_get_data(input, &size); - test_assert(size == strlen(output)); - if (size > 0) - test_assert(memcmp(data, output, size) == 0); - } - i_stream_unref(&input); - i_stream_unref(&input_data); -} - -static void -run_test(const char *json_input, const char *output, int stream_errno) -{ - for (unsigned int i = 1; i <= 5; i++) - run_test_buffer(json_input, output, stream_errno, i); -} - -static void test_istream_jsonstr_autoretry(void) -{ - const char *json_input = "\\u0001\""; - const size_t json_input_len = strlen(json_input); - struct istream *input_data, *input; - - test_begin("istream-jsonstr autoretry"); - input_data = test_istream_create_data(json_input, json_input_len); - input = i_stream_create_jsonstr(input_data); - - test_istream_set_size(input_data, 2); - test_assert(i_stream_read(input_data) == 2); - test_istream_set_size(input_data, json_input_len); - test_assert(i_stream_read(input) == 1); - test_assert(i_stream_read(input) == -1); - - i_stream_unref(&input); - i_stream_unref(&input_data); - test_end(); -} - -static void test_istream_jsonstr_partial(void) -{ - size_t len = 0; - const char *json_input = "hello\\u0060x\""; - const char *output = "hello`x"; - const size_t json_input_len = strlen(json_input); - struct istream *input_data, *input; - - test_begin("istream-jsonstr partial"); - - input_data = test_istream_create_data(json_input, json_input_len); - input = i_stream_create_jsonstr(input_data); - test_istream_set_size(input_data, 9); - test_assert(i_stream_read(input) == 5); - test_istream_set_size(input_data, json_input_len); - test_assert(i_stream_read(input) == 2); - test_assert(i_stream_read(input) == -1); - - const unsigned char *data = i_stream_get_data(input, &len); - test_assert_cmp(len, ==, strlen(output)); - test_assert_strcmp((const char*) data, output); - - i_stream_unref(&input); - i_stream_unref(&input_data); - - test_end(); -} - -void test_istream_jsonstr(void) -{ - unsigned int i; - - for (i = 0; i < N_ELEMENTS(tests); i++) { - test_begin(t_strdup_printf("istream-jsonstr %u", i+1)); - run_test(tests[i].input, tests[i].output, tests[i].stream_errno); - test_end(); - } - test_istream_jsonstr_autoretry(); - test_istream_jsonstr_partial(); -} diff --git a/src/lib/test-json-parser.c b/src/lib/test-json-parser.c deleted file mode 100644 index 92aa4258fd..0000000000 --- a/src/lib/test-json-parser.c +++ /dev/null @@ -1,440 +0,0 @@ -/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ - -#include "test-lib.h" -#include "str.h" -#include "istream-private.h" -#include "json-parser.h" - -#define TYPE_SKIP 100 -#define TYPE_STREAM 101 - -static const char json_input[] = - "{\n" - "\t\"key\"\t:\t\t\"string\"," - " \"key2\" : 1234, \n" - "\"key3\":true," - "\"key4\":false," - "\"skip1\": \"jsifjaisfjiasji\"," - "\"skip2\": { \"x\":{ \"y\":123}, \"z\":[5,[6],{\"k\":0},3]}," - "\"key5\":null," - "\"key6\": {}," - "\"key7\": {" - " \"sub1\":\"value\"" - "}," - "\"key8\": {" - " \"sub2\":-12.456,\n" - " \"sub3\":12.456e9,\n" - " \"sub4\":0.456e-789" - "}," - "\"key9\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\u10ff\"," - "\"key10\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\u10ff\"," - "\"key11\": []," - "\"key12\": [ \"foo\" , 5.24,[true],{\"aobj\":[]}]," - "\"key13\": \"\\ud801\\udc37\"," - "\"key14\": \"\xd8\xb3\xd9\x84\xd8\xa7\xd9\x85\"," - "\"key15\": \"\\u10000\"" - "}\n"; - -static const struct { - enum json_type type; - const char *value; -} json_output[] = { - { JSON_TYPE_OBJECT_KEY, "key" }, - { JSON_TYPE_STRING, "string" }, - { JSON_TYPE_OBJECT_KEY, "key2" }, - { JSON_TYPE_NUMBER, "1234" }, - { JSON_TYPE_OBJECT_KEY, "key3" }, - { JSON_TYPE_TRUE, "true" }, - { JSON_TYPE_OBJECT_KEY, "key4" }, - { JSON_TYPE_FALSE, "false" }, - { JSON_TYPE_OBJECT_KEY, "skip1" }, - { TYPE_SKIP, NULL }, - { JSON_TYPE_OBJECT_KEY, "skip2" }, - { TYPE_SKIP, NULL }, - { JSON_TYPE_OBJECT_KEY, "key5" }, - { JSON_TYPE_NULL, NULL }, - { JSON_TYPE_OBJECT_KEY, "key6" }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_END, NULL }, - { JSON_TYPE_OBJECT_KEY, "key7" }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_KEY, "sub1" }, - { JSON_TYPE_STRING, "value" }, - { JSON_TYPE_OBJECT_END, NULL }, - { JSON_TYPE_OBJECT_KEY, "key8" }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_KEY, "sub2" }, - { JSON_TYPE_NUMBER, "-12.456" }, - { JSON_TYPE_OBJECT_KEY, "sub3" }, - { JSON_TYPE_NUMBER, "12.456e9" }, - { JSON_TYPE_OBJECT_KEY, "sub4" }, - { JSON_TYPE_NUMBER, "0.456e-789" }, - { JSON_TYPE_OBJECT_END, NULL }, - { JSON_TYPE_OBJECT_KEY, "key9" }, - { JSON_TYPE_STRING, "foo\\\"\b\f\n\r\t\001\xe1\x83\xbf" }, - { JSON_TYPE_OBJECT_KEY, "key10" }, - { TYPE_STREAM, "foo\\\"\b\f\n\r\t\001\xe1\x83\xbf" }, - { JSON_TYPE_OBJECT_KEY, "key11" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_ARRAY_END, NULL }, - { JSON_TYPE_OBJECT_KEY, "key12" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_STRING, "foo" }, - { JSON_TYPE_NUMBER, "5.24" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_TRUE, "true" }, - { JSON_TYPE_ARRAY_END, NULL }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_KEY, "aobj" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_ARRAY_END, NULL }, - { JSON_TYPE_OBJECT_END, NULL }, - { JSON_TYPE_ARRAY_END, NULL }, - { JSON_TYPE_OBJECT_KEY, "key13" }, - { JSON_TYPE_STRING, "\xf0\x90\x90\xb7" }, - { JSON_TYPE_OBJECT_KEY, "key14" }, - { JSON_TYPE_STRING, "\xd8\xb3\xd9\x84\xd8\xa7\xd9\x85" }, - { JSON_TYPE_OBJECT_KEY, "key15" }, - { JSON_TYPE_STRING, "\xe1\x80\x80""0" }, -}; - -static int -stream_read_value(struct istream **input, const char **value_r) -{ - const unsigned char *data; - size_t size; - ssize_t ret; - - while ((ret = i_stream_read(*input)) > 0) ; - if (ret == 0) - return 0; - i_assert(ret == -1); - if ((*input)->stream_errno != 0) - return -1; - - data = i_stream_get_data(*input, &size); - *value_r = t_strndup(data, size); - i_stream_unref(input); - return 1; -} - -static void test_json_parser_success(bool full_size) -{ - struct json_parser *parser; - struct istream *input, *jsoninput = NULL; - enum json_type type; - const char *value, *error; - unsigned int i, pos, json_input_len = strlen(json_input); - int ret = 0; - - test_begin(full_size ? "json parser" : "json parser (nonblocking)"); - input = test_istream_create_data(json_input, json_input_len); - test_istream_set_allow_eof(input, FALSE); - parser = json_parser_init(input); - - i = full_size ? json_input_len : 0; - for (pos = 0; i <= json_input_len; i++) { - test_istream_set_size(input, i); - - for (;;) { - value = NULL; - if (pos < N_ELEMENTS(json_output) && - json_output[pos].type == (enum json_type)TYPE_SKIP) { - json_parse_skip_next(parser); - pos++; - continue; - } else if (pos == N_ELEMENTS(json_output) || - json_output[pos].type != (enum json_type)TYPE_STREAM) { - ret = json_parse_next(parser, &type, &value); - } else { - ret = jsoninput != NULL ? 1 : - json_parse_next_stream(parser, &jsoninput); - if (ret > 0 && jsoninput != NULL) - ret = stream_read_value(&jsoninput, &value); - type = TYPE_STREAM; - } - if (ret <= 0) - break; - - i_assert(pos < N_ELEMENTS(json_output)); - test_assert_idx(json_output[pos].type == type, pos); - test_assert_idx(null_strcmp(json_output[pos].value, value) == 0, pos); - - pos++; - } - test_assert_idx(ret == 0, pos); - } - test_assert(pos == N_ELEMENTS(json_output)); - test_istream_set_allow_eof(input, TRUE); - test_assert(json_parse_next(parser, &type, &value) == -1); - - i_stream_unref(&input); - test_assert(json_parser_deinit(&parser, &error) == 0); - test_end(); -} - -static void test_json_parser_skip_array(void) -{ - static const char *test_input = - "[ 1, {\"foo\": 1 }, 2, \"bar\", 3, 1.234, 4, [], 5, [[]], 6, true ]"; - struct json_parser *parser; - struct istream *input; - enum json_type type; - const char *value, *error; - int i; - - test_begin("json parser skip array"); - - input = test_istream_create_data(test_input, strlen(test_input)); - parser = json_parser_init_flags(input, JSON_PARSER_NO_ROOT_OBJECT); - test_assert(json_parse_next(parser, &type, &value) > 0 && - type == JSON_TYPE_ARRAY); - for (i = 1; i <= 6; i++) { - test_assert(json_parse_next(parser, &type, &value) > 0 && - type == JSON_TYPE_NUMBER && atoi(value) == i); - json_parse_skip_next(parser); - } - test_assert(json_parse_next(parser, &type, &value) > 0 && - type == JSON_TYPE_ARRAY_END); - test_assert(json_parser_deinit(&parser, &error) == 0); - i_stream_unref(&input); - test_end(); -} - -static void test_json_parser_skip_object_fields(void) -{ - static const char *test_input = - "{\"access_token\":\"9a2dea3c-f8be-4271-b9c8-5b37da4f2f7e\"," - "\"grant_type\":\"authorization_code\"," - "\"openid\":\"\"," - "\"scope\":[\"openid\",\"profile\",\"email\"]," - "\"profile\":\"\"," - "\"realm\":\"/employees\"," - "\"token_type\":\"Bearer\"," - "\"expires_in\":2377," - "\"client_i\\u0064\":\"mosaic\\u0064\"," - "\"email\":\"\"," - "\"extensions\":" - "{\"algorithm\":\"cuttlefish\"," - "\"tentacles\":8" - "}" - "}"; - static const char *const keys[] = { - "access_token", "grant_type", "openid", "scope", "profile", - "realm", "token_type", "expires_in", "client_id", "email", - "extensions" - }; - static const unsigned int keys_count = N_ELEMENTS(keys); - struct json_parser *parser; - struct istream *input; - enum json_type type; - const char *value, *error; - unsigned int i; - size_t pos; - int ret; - - test_begin("json parser skip object fields (by key)"); - input = test_istream_create_data(test_input, strlen(test_input)); - parser = json_parser_init(input); - for (i = 0; i < keys_count; i++) { - ret = json_parse_next(parser, &type, &value); - if (ret < 0) - break; - test_assert(ret > 0 && type == JSON_TYPE_OBJECT_KEY); - test_assert(strcmp(value, keys[i]) == 0); - json_parse_skip_next(parser); - } - test_assert(i == keys_count); - test_assert(json_parser_deinit(&parser, &error) == 0); - i_stream_unref(&input); - - i = 0; - input = test_istream_create_data(test_input, strlen(test_input)); - parser = json_parser_init(input); - for (pos = 0; pos <= strlen(test_input)*2; pos++) { - test_istream_set_size(input, pos/2); - ret = json_parse_next(parser, &type, &value); - if (ret == 0) - continue; - if (ret < 0) - break; - i_assert(i < keys_count); - test_assert(ret > 0 && type == JSON_TYPE_OBJECT_KEY); - test_assert(strcmp(value, keys[i]) == 0); - json_parse_skip_next(parser); - i++; - } - test_assert(i == keys_count); - test_assert(json_parser_deinit(&parser, &error) == 0); - i_stream_unref(&input); - test_end(); - - test_begin("json parser skip object fields (by value type)"); - input = test_istream_create_data(test_input, strlen(test_input)); - parser = json_parser_init(input); - for (i = 0; i < keys_count; i++) { - ret = json_parse_next(parser, &type, &value); - if (ret < 0) - break; - test_assert(ret > 0 && type == JSON_TYPE_OBJECT_KEY); - test_assert(strcmp(value, keys[i]) == 0); - ret = json_parse_next(parser, &type, &value); - test_assert(ret > 0 && type != JSON_TYPE_OBJECT_KEY); - json_parse_skip(parser); - } - test_assert(i == keys_count); - test_assert(json_parser_deinit(&parser, &error) == 0); - i_stream_unref(&input); - - i = 0; - input = test_istream_create_data(test_input, strlen(test_input)); - parser = json_parser_init(input); - for (pos = 0; pos <= strlen(test_input)*2; pos++) { - test_istream_set_size(input, pos/2); - ret = json_parse_next(parser, &type, &value); - if (ret < 0) - break; - if (ret == 0) - continue; - test_assert(ret > 0); - if (type == JSON_TYPE_OBJECT_KEY) { - i_assert(i < keys_count); - test_assert(strcmp(value, keys[i]) == 0); - i++; - } else { - json_parse_skip(parser); - } - } - test_assert(i == keys_count); - test_assert(json_parser_deinit(&parser, &error) == 0); - i_stream_unref(&input); - - test_end(); -} - -static int -test_json_parse_input(const void *test_input, size_t test_input_size, - enum json_parser_flags flags) -{ - struct json_parser *parser; - struct istream *input; - enum json_type type; - const char *value, *error; - int ret = 0; - - input = test_istream_create_data(test_input, test_input_size); - parser = json_parser_init_flags(input, flags); - while (json_parse_next(parser, &type, &value) > 0) - ret++; - if (json_parser_deinit(&parser, &error) < 0) - ret = -1; - i_stream_unref(&input); - return ret; -} - -static void test_json_parser_primitive_values(void) -{ - static const struct { - const char *str; - int ret; - } test_inputs[] = { - { "\"hello\"", 1 }, - { "null", 1 }, - { "1234", 1 }, - { "1234.1234", 1 }, - { "{}", 2 }, - { "[]", 2 }, - { "true", 1 }, - { "false", 1 } - }; - unsigned int i; - - test_begin("json_parser (primitives)"); - for (i = 0; i < N_ELEMENTS(test_inputs); i++) - test_assert_idx(test_json_parse_input(test_inputs[i].str, - strlen(test_inputs[i].str), - JSON_PARSER_NO_ROOT_OBJECT) == test_inputs[i].ret, i); - test_end(); -} - -static void test_json_parser_errors(void) -{ - static const char *test_inputs[] = { - "{", - "{:}", - "{\"foo\":}", - "{\"foo\" []}", - "{\"foo\": [1}", - "{\"foo\": [1,]}", - "{\"foo\": [1,]}", - "{\"foo\": 1,}", - "{\"foo\": 1.}}", - "{\"foo\": 1},{}", - "{\"foo\": \"\\ud808\"}", - "{\"foo\": \"\\udfff\"}", - "{\"foo\": \"\\uyyyy\"}", - "{\"a\":\"", - "{\"a\":nul", - "{\"a\":fals", - "{\"a\":tru", - }; - unsigned int i; - - test_begin("json parser error handling"); - for (i = 0; i < N_ELEMENTS(test_inputs); i++) - test_assert_idx(test_json_parse_input(test_inputs[i], - strlen(test_inputs[i]), - 0) < 0, i); - test_end(); -} - -static void test_json_parser_nuls_in_string(void) -{ - static const unsigned char test_input[] = - { '{', '"', 'k', '"', ':', '"', '\0', '"', '}' }; - static const unsigned char test_input2[] = - { '{', '"', 'k', '"', ':', '"', '\\', '\0', '"', '}' }; - static const unsigned char test_input3[] = - { '{', '"', 'k', '"', ':', '"', '\\', 'u', '0', '0', '0', '0', '"', '}' }; - - test_begin("json parser nuls in string"); - test_assert(test_json_parse_input(test_input, sizeof(test_input), 0) < 0); - test_assert(test_json_parse_input(test_input2, sizeof(test_input2), 0) < 0); - test_assert(test_json_parse_input(test_input3, sizeof(test_input3), 0) < 0); - test_end(); -} - -static void test_json_append_escaped(void) -{ - string_t *str = t_str_new(32); - - test_begin("json_append_escaped()"); - json_append_escaped(str, "\b\f\r\n\t\"\\\001\002-\xC3\xA4\xf0\x90\x90\xb7\xe2\x80\xa8\xe2\x80\xa9\xff"); - test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0001\\u0002-\xC3\xA4\xf0\x90\x90\xb7\\u2028\\u2029" UNICODE_REPLACEMENT_CHAR_UTF8) == 0); - test_end(); -} - -static void test_json_append_escaped_data(void) -{ - static const unsigned char test_input[] = - "\b\f\r\n\t\"\\\000\001\002-\xC3\xA4\xf0\x90\x90\xb7\xe2\x80\xa8\xe2\x80\xa9\xff"; - string_t *str = t_str_new(32); - - test_begin("json_append_escaped_data()"); - json_append_escaped_data(str, test_input, sizeof(test_input)-1); - test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0000\\u0001\\u0002-\xC3\xA4\xf0\x90\x90\xb7\\u2028\\u2029" UNICODE_REPLACEMENT_CHAR_UTF8) == 0); - test_end(); -} - -void test_json_parser(void) -{ - test_json_parser_success(TRUE); - test_json_parser_success(FALSE); - test_json_parser_skip_array(); - test_json_parser_skip_object_fields(); - test_json_parser_primitive_values(); - test_json_parser_errors(); - test_json_parser_nuls_in_string(); - test_json_append_escaped(); - test_json_append_escaped_data(); -} diff --git a/src/lib/test-json-tree.c b/src/lib/test-json-tree.c deleted file mode 100644 index 40eff8c39c..0000000000 --- a/src/lib/test-json-tree.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */ - -#include "test-lib.h" -#include "json-tree.h" - -struct { - enum json_type type; - const char *value; -} test_input[] = { - { JSON_TYPE_OBJECT_KEY, "key-str" }, - { JSON_TYPE_STRING, "string" }, - { JSON_TYPE_OBJECT_KEY, "key-num" }, - { JSON_TYPE_NUMBER, "1234" }, - { JSON_TYPE_OBJECT_KEY, "key-true" }, - { JSON_TYPE_TRUE, "true" }, - { JSON_TYPE_OBJECT_KEY, "key-false" }, - { JSON_TYPE_FALSE, "false" }, - { JSON_TYPE_OBJECT_KEY, "key-null" }, - { JSON_TYPE_NULL, NULL }, - - { JSON_TYPE_OBJECT_KEY, "key-obj-empty" }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_END, NULL }, - - { JSON_TYPE_OBJECT_KEY, "key-obj" }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_KEY, "sub" }, - { JSON_TYPE_STRING, "value" }, - { JSON_TYPE_OBJECT_END, NULL }, - - { JSON_TYPE_OBJECT_KEY, "key-arr-empty" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_ARRAY_END, NULL }, - - { JSON_TYPE_OBJECT_KEY, "key-arr" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_STRING, "foo" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_TRUE, "true" }, - { JSON_TYPE_ARRAY_END, NULL }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_KEY, "aobj" }, - { JSON_TYPE_ARRAY, NULL }, - { JSON_TYPE_ARRAY_END, NULL }, - { JSON_TYPE_OBJECT_END, NULL }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_KEY, "aobj-key" }, - { JSON_TYPE_STRING, "value1" }, - { JSON_TYPE_OBJECT_END, NULL }, - { JSON_TYPE_OBJECT, NULL }, - { JSON_TYPE_OBJECT_KEY, "aobj-key" }, - { JSON_TYPE_STRING, "value2" }, - { JSON_TYPE_OBJECT_END, NULL }, - { JSON_TYPE_ARRAY_END, NULL } -}; - -void test_json_tree(void) -{ - struct json_tree *tree; - const struct json_tree_node *root, *node, *node1, *node2; - unsigned int i; - - test_begin("json tree"); - tree = json_tree_init(); - for (i = 0; i < N_ELEMENTS(test_input); i++) { - test_assert_idx(json_tree_append(tree, test_input[i].type, - test_input[i].value) == 0, i); - } - - root = json_tree_root(tree); - i_assert(root != NULL); - test_assert(root->value_type == JSON_TYPE_OBJECT); - i_assert(root != NULL); - - for (i = 0; i < 10+2; i += 2) { - node = json_tree_find_key(root, test_input[i].value); - test_assert(node != NULL && - node->value_type == test_input[i+1].type && - null_strcmp(json_tree_get_value_str(node), test_input[i+1].value) == 0); - } - - node = json_tree_find_key(root, "key-obj"); - test_assert(node != NULL); - - node = json_tree_find_key(root, "key-arr-empty"); - test_assert(node != NULL && node->value_type == JSON_TYPE_ARRAY && - json_tree_get_child(node) == NULL); - - node = json_tree_find_key(root, "key-arr"); - test_assert(node != NULL && node->value_type == JSON_TYPE_ARRAY); - node = json_tree_get_child(node); - test_assert(node != NULL && node->value_type == JSON_TYPE_STRING && - strcmp(json_tree_get_value_str(node), "foo") == 0); - node = node->next; - test_assert(node != NULL && node->value_type == JSON_TYPE_ARRAY && - json_tree_get_child(node) != NULL && - json_tree_get_child(node)->next == NULL && - json_tree_get_child(node)->value_type == JSON_TYPE_TRUE); - node = node->next; - test_assert(node != NULL && node->value_type == JSON_TYPE_OBJECT && - json_tree_get_child(node) != NULL && - json_tree_get_child(node)->next == NULL && - json_tree_get_child(node)->value_type == JSON_TYPE_ARRAY && - json_tree_get_child(json_tree_get_child(node)) == NULL); - - node1 = json_tree_find_child_with(node->parent, "aobj-key", "value1"); - node2 = json_tree_find_child_with(node->parent, "aobj-key", "value2"); - test_assert(node1 != NULL && node2 != NULL && node1 != node2); - test_assert(json_tree_find_child_with(node->parent, "aobj-key", "value3") == NULL); - - json_tree_deinit(&tree); - test_end(); -} diff --git a/src/lib/test-lib.inc b/src/lib/test-lib.inc index 557d753a43..59e7042850 100644 --- a/src/lib/test-lib.inc +++ b/src/lib/test-lib.inc @@ -54,7 +54,6 @@ TEST(test_istream_chain) TEST(test_istream_concat) TEST(test_istream_crlf) TEST(test_istream_failure_at) -TEST(test_istream_jsonstr) TEST(test_istream_multiplex) TEST(test_istream_noop) TEST(test_istream_seekable) @@ -62,8 +61,6 @@ TEST(test_istream_sized) TEST(test_istream_tee) TEST(test_istream_try) TEST(test_istream_unix) -TEST(test_json_parser) -TEST(test_json_tree) TEST(test_lib_event) TEST(test_lib_signals) TEST(test_llist)