Based on patch by Aki Tuomi.
JSON_STATE_ARRAY_VALUE,
JSON_STATE_ARRAY_SKIP_STRING,
JSON_STATE_ARRAY_NEXT,
+ JSON_STATE_VALUE,
JSON_STATE_DONE
};
}
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;
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;
}
return 0;
case JSON_STATE_OBJECT_VALUE:
case JSON_STATE_ARRAY_VALUE:
+ case JSON_STATE_VALUE:
if (*parser->data == '{') {
json_parser_object_open(parser);
}
return -1;
}
- parser->state = parser->state == JSON_STATE_OBJECT_VALUE ?
- JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
+ 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 == '}')
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
test_end();
}
-static int test_json_parse_input(const char *test_input)
+static int
+test_json_parse_input(const char *test_input, enum json_parser_flags flags)
{
struct json_parser *parser;
struct istream *input;
int ret = 0;
input = test_istream_create_data(test_input, strlen(test_input));
- parser = json_parser_init(input);
+ parser = json_parser_init_flags(input, flags);
while (json_parse_next(parser, &type, &value) > 0)
ret++;
if (json_parser_deinit(&parser, &error) < 0)
return ret;
}
+static void test_json_parser_primitive_values(void)
+{
+ static const char *test_inputs[] = {
+ "\"hello\"",
+ "null",
+ "1234",
+ "1234.1234",
+ "{}",
+ "[]",
+ "true",
+ "false"
+ };
+ 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], JSON_PARSER_NO_ROOT_OBJECT) == 1, i);
+ test_end();
+}
+
static void test_json_parser_errors(void)
{
static const char *test_inputs[] = {
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]) < 0, i);
+ test_assert_idx(test_json_parse_input(test_inputs[i], 0) < 0, i);
test_end();
}
{
test_json_parser_success(TRUE);
test_json_parser_success(FALSE);
+ test_json_parser_primitive_values();
test_json_parser_errors();
test_json_append_escaped();
test_json_append_escaped_data();