json REFACTOR major rewrite of JSON parser
diff --git a/src/json.c b/src/json.c
index eeb7478..53f41dc 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1,9 +1,10 @@
/**
* @file json.c
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief Generic JSON format parser for libyang
*
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -30,30 +31,30 @@
switch (status) {
case LYJSON_ERROR:
return "error";
- case LYJSON_ROOT:
- return "document root";
- case LYJSON_FALSE:
- return "false";
- case LYJSON_TRUE:
- return "true";
- case LYJSON_NULL:
- return "null";
case LYJSON_OBJECT:
return "object";
+ case LYJSON_OBJECT_NEXT:
+ return "object next";
case LYJSON_OBJECT_CLOSED:
return "object closed";
- case LYJSON_OBJECT_EMPTY:
- return "empty object";
case LYJSON_ARRAY:
return "array";
+ case LYJSON_ARRAY_NEXT:
+ return "array next";
case LYJSON_ARRAY_CLOSED:
return "array closed";
- case LYJSON_ARRAY_EMPTY:
- return "empty array";
+ case LYJSON_OBJECT_NAME:
+ return "object name";
case LYJSON_NUMBER:
return "number";
case LYJSON_STRING:
return "string";
+ case LYJSON_TRUE:
+ return "true";
+ case LYJSON_FALSE:
+ return "false";
+ case LYJSON_NULL:
+ return "null";
case LYJSON_END:
return "end of input";
}
@@ -61,25 +62,48 @@
return "";
}
-static LY_ERR
-skip_ws(struct lyjson_ctx *jsonctx)
+enum LYJSON_PARSER_STATUS
+lyjson_ctx_status(struct lyjson_ctx *jsonctx)
{
- /* skip leading whitespaces */
- while (*jsonctx->in->current != '\0' && is_jsonws(*jsonctx->in->current)) {
+ assert(jsonctx);
+
+ if (!jsonctx->status.count) {
+ return LYJSON_END;
+ }
+
+ return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - 1];
+}
+
+uint32_t
+lyjson_ctx_depth(struct lyjson_ctx *jsonctx)
+{
+ return jsonctx->status.count;
+}
+
+/**
+ * @brief Skip WS in the JSON context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ */
+static void
+lyjson_skip_ws(struct lyjson_ctx *jsonctx)
+{
+ /* skip whitespaces */
+ while (is_jsonws(*jsonctx->in->current)) {
if (*jsonctx->in->current == '\n') {
LY_IN_NEW_LINE(jsonctx->in);
}
ly_in_skip(jsonctx->in, 1);
}
- if (*jsonctx->in->current == '\0') {
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_END);
- }
-
- return LY_SUCCESS;
}
-/*
- * @brief Set value corresponding to the current context's status
+/**
+ * @brief Set value in the JSON context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @param[in] value Value to set.
+ * @param[in] value_len Length of @p value.
+ * @param[in] dynamic Whether @p value is dynamically-allocated.
*/
static void
lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, size_t value_len, ly_bool dynamic)
@@ -94,48 +118,24 @@
jsonctx->dynamic = dynamic;
}
-static LY_ERR
-lyjson_check_next(struct lyjson_ctx *jsonctx)
-{
- if (jsonctx->status.count == 1) {
- /* top level value (JSON-text), ws expected */
- if ((*jsonctx->in->current == '\0') || is_jsonws(*jsonctx->in->current)) {
- return LY_SUCCESS;
- }
- } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_OBJECT) {
- LY_CHECK_RET(skip_ws(jsonctx));
- if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == '}')) {
- return LY_SUCCESS;
- }
- } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_ARRAY) {
- LY_CHECK_RET(skip_ws(jsonctx));
- if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == ']')) {
- return LY_SUCCESS;
- }
- }
-
- LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Unexpected character \"%c\" after JSON %s.",
- *jsonctx->in->current, lyjson_token2str(lyjson_ctx_status(jsonctx, 0)));
- return LY_EVALID;
-}
-
/**
- * Input is expected to start after the opening quotation-mark.
- * When succeeds, input is moved after the closing quotation-mark.
+ * @brief Parse a JSON string (starting after double quotes) and store it in the context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
*/
static LY_ERR
-lyjson_string_(struct lyjson_ctx *jsonctx)
+lyjson_string(struct lyjson_ctx *jsonctx)
{
-#define BUFSIZE 24
-#define BUFSIZE_STEP 128
-
- const char *in = jsonctx->in->current, *start;
+ const char *in = jsonctx->in->current, *start, *c;
char *buf = NULL;
size_t offset; /* read offset in input buffer */
size_t len; /* length of the output string (write offset in output buffer) */
size_t size = 0; /* size of the output buffer */
size_t u;
uint64_t start_line;
+ uint32_t value;
+ uint8_t i;
assert(jsonctx);
@@ -146,17 +146,15 @@
/* parse */
while (in[offset]) {
- if (in[offset] == '\\') {
+ switch (in[offset]) {
+ case '\\':
/* escape sequence */
- const char *slash = &in[offset];
- uint32_t value;
- uint8_t i = 1;
-
+ c = &in[offset];
if (!buf) {
/* prepare output buffer */
- buf = malloc(BUFSIZE);
+ buf = malloc(LYJSON_STRING_BUF_START);
LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
- size = BUFSIZE;
+ size = LYJSON_STRING_BUF_START;
}
/* allocate enough for the offset and next character,
@@ -165,10 +163,10 @@
if (len + offset + 4 >= size) {
size_t increment;
- for (increment = BUFSIZE_STEP; len + offset + 4 >= size + increment; increment += BUFSIZE_STEP) {}
+ for (increment = LYJSON_STRING_BUF_STEP; len + offset + 4 >= size + increment; increment += LYJSON_STRING_BUF_STEP) {}
buf = ly_realloc(buf, size + increment);
LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
- size += BUFSIZE_STEP;
+ size += LYJSON_STRING_BUF_STEP;
}
if (offset) {
@@ -179,6 +177,7 @@
offset = 0;
}
+ i = 1;
switch (in[++offset]) {
case '"':
/* quotation mark */
@@ -217,7 +216,7 @@
offset++;
for (value = i = 0; i < 4; i++) {
if (!in[offset + i]) {
- LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", slash);
+ LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", c);
goto error;
} else if (isdigit(in[offset + i])) {
u = (in[offset + i] - '0');
@@ -239,13 +238,14 @@
offset += i; /* add read escaped characters */
LY_CHECK_ERR_GOTO(ly_pututf8(&buf[len], value, &u),
LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character reference \"%.*s\" (0x%08x).",
- (int)(&in[offset] - slash), slash, value),
+ (int)(&in[offset] - c), c, value),
error);
len += u; /* update number of bytes in buffer */
in += offset; /* move the input by the processed bytes stored in the buffer ... */
offset = 0; /* ... and reset the offset index for future moving data into buffer */
+ break;
- } else if (in[offset] == '"') {
+ case '"':
/* end of string */
if (buf) {
/* realloc exact size string */
@@ -263,22 +263,21 @@
++offset;
in += offset;
goto success;
- } else {
- /* get it as UTF-8 character for check */
- const char *c = &in[offset];
- uint32_t code = 0;
- size_t code_len = 0;
- LY_CHECK_ERR_GOTO(ly_getutf8(&c, &code, &code_len),
+ default:
+ /* get it as UTF-8 character for check */
+ c = &in[offset];
+ LY_CHECK_ERR_GOTO(ly_getutf8(&c, &value, &u),
LOGVAL(jsonctx->ctx, LY_VCODE_INCHAR, in[offset]), error);
- LY_CHECK_ERR_GOTO(!is_jsonstrchar(code),
+ LY_CHECK_ERR_GOTO(!is_jsonstrchar(value),
LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON string \"%.*s\" (0x%08x).",
- (int)(&in[offset] - start + code_len), start, code),
+ (int)(&in[offset] - start + u), start, value),
error);
/* character is ok, continue */
- offset += code_len;
+ offset += u;
+ break;
}
}
@@ -299,24 +298,6 @@
}
return LY_SUCCESS;
-
-#undef BUFSIZE
-#undef BUFSIZE_STEP
-}
-
-/*
- *
- * Wrapper around lyjson_string_() adding LYJSON_STRING status into context to allow using lyjson_string_() for parsing object's name.
- */
-static LY_ERR
-lyjson_string(struct lyjson_ctx *jsonctx)
-{
- LY_CHECK_RET(lyjson_string_(jsonctx));
-
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_STRING);
- LY_CHECK_RET(lyjson_check_next(jsonctx));
-
- return LY_SUCCESS;
}
/**
@@ -414,8 +395,7 @@
* @return Number of characters written to the @p dst.
*/
static uint32_t
-lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len,
- char *dec_point, int32_t dp_position, char *dst)
+lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len, char *dec_point, int32_t dp_position, char *dst)
{
int32_t dec_point_idx;
int32_t n, d;
@@ -456,8 +436,8 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent,
- uint64_t total_len, char **res, size_t *res_len)
+lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent, uint64_t total_len, char **res,
+ size_t *res_len)
{
#define MAYBE_WRITE_MINUS(ARRAY, INDEX, FLAG) \
@@ -642,6 +622,12 @@
return LY_SUCCESS;
}
+/**
+ * @brief Parse a JSON number and store it in the context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
static LY_ERR
lyjson_number(struct lyjson_ctx *jsonctx)
{
@@ -713,159 +699,16 @@
}
ly_in_skip(jsonctx->in, offset);
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NUMBER);
- LY_CHECK_RET(lyjson_check_next(jsonctx));
-
- return LY_SUCCESS;
-}
-
-static LY_ERR
-lyjson_object_name(struct lyjson_ctx *jsonctx)
-{
- if (*jsonctx->in->current != '"') {
- LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
- jsonctx->in->current, "a JSON object's member");
- return LY_EVALID;
- }
- ly_in_skip(jsonctx->in, 1);
-
- LY_CHECK_RET(lyjson_string_(jsonctx));
- LY_CHECK_RET(skip_ws(jsonctx));
- if (*jsonctx->in->current != ':') {
- LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
- "a JSON object's name-separator ':'");
- return LY_EVALID;
- }
- ly_in_skip(jsonctx->in, 1);
- LY_CHECK_RET(skip_ws(jsonctx));
-
- return LY_SUCCESS;
-}
-
-static LY_ERR
-lyjson_object(struct lyjson_ctx *jsonctx)
-{
- LY_CHECK_RET(skip_ws(jsonctx));
-
- if (*jsonctx->in->current == '}') {
- assert(jsonctx->depth);
- jsonctx->depth--;
- /* empty object */
- ly_in_skip(jsonctx->in, 1);
- lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_EMPTY);
- return LY_SUCCESS;
- }
-
- LY_CHECK_RET(lyjson_object_name(jsonctx));
-
- /* output data are set by lyjson_string_() */
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT);
-
- return LY_SUCCESS;
-}
-
-/**
- * @brief Process JSON array envelope
- *
- * @param[in] jsonctx JSON parser context
- * @return LY_SUCCESS or LY_EMEM
- */
-static LY_ERR
-lyjson_array(struct lyjson_ctx *jsonctx)
-{
- LY_CHECK_RET(skip_ws(jsonctx));
-
- if (*jsonctx->in->current == ']') {
- /* empty array */
- ly_in_skip(jsonctx->in, 1);
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_EMPTY);
- } else {
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY);
- }
-
- /* erase previous values, array has no value on its own */
- lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
-
- return LY_SUCCESS;
-}
-
-static LY_ERR
-lyjson_value(struct lyjson_ctx *jsonctx)
-{
- if (jsonctx->status.count && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
- return LY_SUCCESS;
- }
-
- if ((*jsonctx->in->current == 'f') && !strncmp(jsonctx->in->current, "false", ly_strlen_const("false"))) {
- /* false */
- lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
- ly_in_skip(jsonctx->in, ly_strlen_const("false"));
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_FALSE);
- LY_CHECK_RET(lyjson_check_next(jsonctx));
-
- } else if ((*jsonctx->in->current == 't') && !strncmp(jsonctx->in->current, "true", ly_strlen_const("true"))) {
- /* true */
- lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
- ly_in_skip(jsonctx->in, ly_strlen_const("true"));
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_TRUE);
- LY_CHECK_RET(lyjson_check_next(jsonctx));
-
- } else if ((*jsonctx->in->current == 'n') && !strncmp(jsonctx->in->current, "null", ly_strlen_const("null"))) {
- /* none */
- lyjson_ctx_set_value(jsonctx, "", 0, 0);
- ly_in_skip(jsonctx->in, ly_strlen_const("null"));
- LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NULL);
- LY_CHECK_RET(lyjson_check_next(jsonctx));
-
- } else if (*jsonctx->in->current == '"') {
- /* string */
- ly_in_skip(jsonctx->in, 1);
- LY_CHECK_RET(lyjson_string(jsonctx));
-
- } else if (*jsonctx->in->current == '[') {
- /* array */
- ly_in_skip(jsonctx->in, 1);
- LY_CHECK_RET(lyjson_array(jsonctx));
-
- } else if (*jsonctx->in->current == '{') {
- jsonctx->depth++;
-
- /* object */
- ly_in_skip(jsonctx->in, 1);
- LY_CHECK_RET(lyjson_object(jsonctx));
-
- } else if ((*jsonctx->in->current == '-') || ((*jsonctx->in->current >= '0') && (*jsonctx->in->current <= '9'))) {
- /* number */
- LY_CHECK_RET(lyjson_number(jsonctx));
-
- } else {
- /* unexpected value */
- LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
- jsonctx->in->current, "a JSON value");
- return LY_EVALID;
- }
-
- if (jsonctx->depth > LY_MAX_BLOCK_DEPTH) {
- LOGERR(jsonctx->ctx, LY_EINVAL, "Maximum number %d of block nestings has been exceeded.", LY_MAX_BLOCK_DEPTH);
- return LY_EINVAL;
- } else if (jsonctx->status.count > LY_MAX_BLOCK_DEPTH * 10) {
- LOGERR(jsonctx->ctx, LY_EINVAL, "Maximum number %d of nestings has been exceeded.", LY_MAX_BLOCK_DEPTH * 10);
- return LY_EINVAL;
- }
-
return LY_SUCCESS;
}
LY_ERR
-lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, ly_bool subtree, struct lyjson_ctx **jsonctx_p)
+lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lyjson_ctx **jsonctx_p)
{
LY_ERR ret = LY_SUCCESS;
struct lyjson_ctx *jsonctx;
- assert(ctx);
- assert(in);
- assert(jsonctx_p);
+ assert(ctx && in && jsonctx_p);
/* new context */
jsonctx = calloc(1, sizeof *jsonctx);
@@ -875,23 +718,18 @@
LOG_LOCSET(NULL, NULL, NULL, in);
- /* parse JSON value, if any */
- LY_CHECK_GOTO(ret = skip_ws(jsonctx), cleanup);
- if (lyjson_ctx_status(jsonctx, 0) == LYJSON_END) {
- /* empty data input */
+ /* WS are always expected to be skipped */
+ lyjson_skip_ws(jsonctx);
+
+ if (jsonctx->in->current[0] == '\0') {
+ /* empty file, invalid */
+ LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Empty JSON file.");
+ ret = LY_EVALID;
goto cleanup;
}
- if (subtree) {
- ret = lyjson_object(jsonctx);
- jsonctx->depth++;
- } else {
- ret = lyjson_value(jsonctx);
- }
- if ((jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
- LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
- ret = LY_EVALID;
- }
+ /* start JSON parsing */
+ LY_CHECK_GOTO(ret = lyjson_ctx_next(jsonctx, NULL), cleanup);
cleanup:
if (ret) {
@@ -902,19 +740,318 @@
return ret;
}
+/**
+ * @brief Parse next JSON token, object-name is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_object_name(struct lyjson_ctx *jsonctx)
+{
+ switch (*jsonctx->in->current) {
+ case '\0':
+ /* EOF */
+ LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+ return LY_EVALID;
+
+ case '"':
+ /* object name */
+ ly_in_skip(jsonctx->in, 1);
+ LY_CHECK_RET(lyjson_string(jsonctx));
+ lyjson_skip_ws(jsonctx);
+
+ if (*jsonctx->in->current != ':') {
+ LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
+ "a JSON value name-separator ':'");
+ return LY_EVALID;
+ }
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_NAME);
+ break;
+
+ case '}':
+ /* object end */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_CLOSED);
+ break;
+
+ default:
+ /* unexpected value */
+ LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+ jsonctx->in->current, "a JSON object name");
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse next JSON token, value is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @param[in] array_end Whether array-end is accepted or not.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_value(struct lyjson_ctx *jsonctx, ly_bool array_end)
+{
+ switch (*jsonctx->in->current) {
+ case '\0':
+ /* EOF */
+ LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+ return LY_EVALID;
+
+ case '"':
+ /* string */
+ ly_in_skip(jsonctx->in, 1);
+ LY_CHECK_RET(lyjson_string(jsonctx));
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_STRING);
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* number */
+ LY_CHECK_RET(lyjson_number(jsonctx));
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NUMBER);
+ break;
+
+ case '{':
+ /* object */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT);
+ break;
+
+ case '[':
+ /* array */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY);
+ break;
+
+ case 't':
+ if (strncmp(jsonctx->in->current + 1, "rue", ly_strlen_const("rue"))) {
+ goto unexpected_value;
+ }
+
+ /* true */
+ lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
+ ly_in_skip(jsonctx->in, ly_strlen_const("true"));
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_TRUE);
+ break;
+
+ case 'f':
+ if (strncmp(jsonctx->in->current + 1, "alse", ly_strlen_const("alse"))) {
+ goto unexpected_value;
+ }
+
+ /* false */
+ lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
+ ly_in_skip(jsonctx->in, ly_strlen_const("false"));
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_FALSE);
+ break;
+
+ case 'n':
+ if (strncmp(jsonctx->in->current + 1, "ull", ly_strlen_const("ull"))) {
+ goto unexpected_value;
+ }
+
+ /* null */
+ lyjson_ctx_set_value(jsonctx, "", 0, 0);
+ ly_in_skip(jsonctx->in, ly_strlen_const("null"));
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NULL);
+ break;
+
+ case ']':
+ if (!array_end) {
+ goto unexpected_value;
+ }
+
+ /* array end */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_CLOSED);
+ break;
+
+ default:
+unexpected_value:
+ LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+ jsonctx->in->current, "a JSON value");
+ return LY_EVALID;
+ }
+
+ if (jsonctx->status.count > LY_MAX_BLOCK_DEPTH * 10) {
+ LOGERR(jsonctx->ctx, LY_EINVAL, "Maximum number %d of nestings has been exceeded.", LY_MAX_BLOCK_DEPTH * 10);
+ return LY_EINVAL;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse next JSON token, object-next-item is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_object_item(struct lyjson_ctx *jsonctx)
+{
+ switch (*jsonctx->in->current) {
+ case '\0':
+ /* EOF */
+ LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+ return LY_EVALID;
+
+ case '}':
+ /* object end */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_CLOSED);
+ break;
+
+ case ',':
+ /* next object item */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_NEXT);
+ break;
+
+ default:
+ /* unexpected value */
+ LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+ jsonctx->in->current, "a JSON object-end or next item");
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse next JSON token, array-next-item is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_array_item(struct lyjson_ctx *jsonctx)
+{
+ switch (*jsonctx->in->current) {
+ case '\0':
+ /* EOF */
+ LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+ return LY_EVALID;
+
+ case ']':
+ /* array end */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_CLOSED);
+ break;
+
+ case ',':
+ /* next array item */
+ ly_in_skip(jsonctx->in, 1);
+ LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_NEXT);
+ break;
+
+ default:
+ /* unexpected value */
+ LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+ jsonctx->in->current, "a JSON array-end or next item");
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
+{
+ LY_ERR ret = LY_SUCCESS;
+ enum LYJSON_PARSER_STATUS cur;
+
+ assert(jsonctx);
+
+ cur = lyjson_ctx_status(jsonctx);
+ switch (cur) {
+ case LYJSON_OBJECT:
+ LY_CHECK_GOTO(ret = lyjson_next_object_name(jsonctx), cleanup);
+ break;
+ case LYJSON_ARRAY:
+ LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 1), cleanup);
+ break;
+ case LYJSON_OBJECT_NEXT:
+ LYJSON_STATUS_POP(jsonctx);
+ LY_CHECK_GOTO(ret = lyjson_next_object_name(jsonctx), cleanup);
+ break;
+ case LYJSON_ARRAY_NEXT:
+ LYJSON_STATUS_POP(jsonctx);
+ LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
+ break;
+ case LYJSON_OBJECT_NAME:
+ lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
+ LYJSON_STATUS_POP(jsonctx);
+ LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
+ break;
+ case LYJSON_OBJECT_CLOSED:
+ case LYJSON_ARRAY_CLOSED:
+ LYJSON_STATUS_POP(jsonctx);
+ /* fallthrough */
+ case LYJSON_NUMBER:
+ case LYJSON_STRING:
+ case LYJSON_TRUE:
+ case LYJSON_FALSE:
+ case LYJSON_NULL:
+ lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
+ LYJSON_STATUS_POP(jsonctx);
+ cur = lyjson_ctx_status(jsonctx);
+
+ if (cur == LYJSON_OBJECT) {
+ LY_CHECK_GOTO(ret = lyjson_next_object_item(jsonctx), cleanup);
+ break;
+ } else if (cur == LYJSON_ARRAY) {
+ LY_CHECK_GOTO(ret = lyjson_next_array_item(jsonctx), cleanup);
+ break;
+ }
+
+ assert(cur == LYJSON_END);
+ goto cleanup;
+ case LYJSON_END:
+ LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
+ break;
+ case LYJSON_ERROR:
+ LOGINT(jsonctx->ctx);
+ ret = LY_EINT;
+ goto cleanup;
+ }
+
+ /* skip WS */
+ lyjson_skip_ws(jsonctx);
+
+cleanup:
+ if (!ret && status) {
+ *status = lyjson_ctx_status(jsonctx);
+ }
+ return ret;
+}
+
void
lyjson_ctx_backup(struct lyjson_ctx *jsonctx)
{
if (jsonctx->backup.dynamic) {
free((char *)jsonctx->backup.value);
}
- jsonctx->backup.status = lyjson_ctx_status(jsonctx, 0);
+ jsonctx->backup.status = lyjson_ctx_status(jsonctx);
jsonctx->backup.status_count = jsonctx->status.count;
jsonctx->backup.value = jsonctx->value;
jsonctx->backup.value_len = jsonctx->value_len;
jsonctx->backup.input = jsonctx->in->current;
jsonctx->backup.dynamic = jsonctx->dynamic;
- jsonctx->backup.depth = jsonctx->depth;
jsonctx->dynamic = 0;
}
@@ -930,105 +1067,9 @@
jsonctx->value_len = jsonctx->backup.value_len;
jsonctx->in->current = jsonctx->backup.input;
jsonctx->dynamic = jsonctx->backup.dynamic;
- jsonctx->depth = jsonctx->backup.depth;
jsonctx->backup.dynamic = 0;
}
-LY_ERR
-lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
-{
- LY_ERR ret = LY_SUCCESS;
- ly_bool toplevel = 0;
- enum LYJSON_PARSER_STATUS prev;
-
- assert(jsonctx);
-
- prev = lyjson_ctx_status(jsonctx, 0);
-
- if ((prev == LYJSON_OBJECT) || (prev == LYJSON_ARRAY)) {
- /* get value for the object's member OR the first value in the array */
- ret = lyjson_value(jsonctx);
- goto result;
- } else {
- /* the previous token is closed and should be completely processed */
- LYJSON_STATUS_POP_RET(jsonctx);
- prev = lyjson_ctx_status(jsonctx, 0);
- }
-
- if (!jsonctx->status.count) {
- /* we are done with the top level value */
- toplevel = 1;
- }
- LY_CHECK_RET(skip_ws(jsonctx));
- if (toplevel && !jsonctx->status.count) {
- /* EOF expected, but there are some data after the top level token */
- LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Expecting end-of-input, but some data follows the top level JSON value.");
- return LY_EVALID;
- }
-
- if (toplevel) {
- /* we are done */
- goto result;
- }
-
- /* continue with the next token */
- assert(prev == LYJSON_OBJECT || prev == LYJSON_ARRAY);
-
- if (*jsonctx->in->current == ',') {
- /* sibling item in the ... */
- ly_in_skip(jsonctx->in, 1);
- LY_CHECK_RET(skip_ws(jsonctx));
-
- if (prev == LYJSON_OBJECT) {
- /* ... object - get another object's member */
- ret = lyjson_object_name(jsonctx);
- } else { /* LYJSON_ARRAY */
- /* ... array - get another complete value */
- ret = lyjson_value(jsonctx);
- }
- } else if (((prev == LYJSON_OBJECT) && (*jsonctx->in->current == '}')) ||
- ((prev == LYJSON_ARRAY) && (*jsonctx->in->current == ']'))) {
- if (*jsonctx->in->current == '}') {
- assert(jsonctx->depth);
- jsonctx->depth--;
- }
- ly_in_skip(jsonctx->in, 1);
- LYJSON_STATUS_POP_RET(jsonctx);
- LYJSON_STATUS_PUSH_RET(jsonctx, prev + 1);
- } else {
- /* unexpected value */
- LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
- prev == LYJSON_ARRAY ? "another JSON value in array" : "another JSON object's member");
- return LY_EVALID;
- }
-
-result:
- if ((ret == LY_SUCCESS) && (jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
- LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
- ret = LY_EVALID;
- }
-
- if ((ret == LY_SUCCESS) && status) {
- *status = lyjson_ctx_status(jsonctx, 0);
- }
-
- return ret;
-}
-
-enum LYJSON_PARSER_STATUS
-lyjson_ctx_status(struct lyjson_ctx *jsonctx, uint32_t index)
-{
- assert(jsonctx);
-
- if (jsonctx->status.count < index) {
- return LYJSON_ERROR;
- } else if (jsonctx->status.count == index) {
- return LYJSON_ROOT;
- } else {
- return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - (index + 1)];
- }
-}
-
void
lyjson_ctx_free(struct lyjson_ctx *jsonctx)
{
diff --git a/src/json.h b/src/json.h
index 53efe2a..61c561a 100644
--- a/src/json.h
+++ b/src/json.h
@@ -1,9 +1,10 @@
/**
* @file json.h
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief Generic JSON format parser routines.
*
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -24,6 +25,9 @@
struct ly_ctx;
struct ly_in;
+#define LYJSON_STRING_BUF_START 24
+#define LYJSON_STRING_BUF_STEP 128
+
/* Macro to test if character is whitespace */
#define is_jsonws(c) (c == 0x20 || c == 0x9 || c == 0xa || c == 0xd)
@@ -35,27 +39,27 @@
LY_CHECK_RET(ly_set_add(&CTX->status, (void *)(uintptr_t)(STATUS), 1, NULL))
/* Macro to pop JSON parser status */
-#define LYJSON_STATUS_POP_RET(CTX) \
+#define LYJSON_STATUS_POP(CTX) \
assert(CTX->status.count); CTX->status.count--;
/**
* @brief Status of the parser providing information what is expected next (which function is supposed to be called).
*/
enum LYJSON_PARSER_STATUS {
- LYJSON_ERROR, /* JSON parser error - value is used as an error return code */
- LYJSON_ROOT, /* JSON document root, used internally */
- LYJSON_OBJECT, /* JSON object */
- LYJSON_OBJECT_CLOSED, /* JSON object closed */
- LYJSON_OBJECT_EMPTY, /* empty JSON object { } */
- LYJSON_ARRAY, /* JSON array */
- LYJSON_ARRAY_CLOSED, /* JSON array closed */
- LYJSON_ARRAY_EMPTY, /* empty JSON array */
- LYJSON_NUMBER, /* JSON number value */
- LYJSON_STRING, /* JSON string value */
- LYJSON_FALSE, /* JSON false value */
- LYJSON_TRUE, /* JSON true value */
- LYJSON_NULL, /* JSON null value */
- LYJSON_END /* end of input data */
+ LYJSON_ERROR = 0, /* JSON parser error - value is used as an error return code */
+ LYJSON_OBJECT, /* JSON object */
+ LYJSON_OBJECT_NEXT, /* JSON object next item */
+ LYJSON_OBJECT_CLOSED, /* JSON object closed */
+ LYJSON_ARRAY, /* JSON array */
+ LYJSON_ARRAY_NEXT, /* JSON array next item */
+ LYJSON_ARRAY_CLOSED, /* JSON array closed */
+ LYJSON_OBJECT_NAME, /* JSON object name */
+ LYJSON_NUMBER, /* JSON number value */
+ LYJSON_STRING, /* JSON string value */
+ LYJSON_TRUE, /* JSON true value */
+ LYJSON_FALSE, /* JSON false value */
+ LYJSON_NULL, /* JSON null value */
+ LYJSON_END /* end of input data */
};
struct lyjson_ctx {
@@ -64,10 +68,9 @@
struct ly_set status; /* stack of ::LYJSON_PARSER_STATUS values corresponding to the JSON items being processed */
- const char *value; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT */
- size_t value_len; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT */
- ly_bool dynamic; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT */
- uint32_t depth; /* current number of nested blocks, see ::LY_MAX_BLOCK_DEPTH */
+ const char *value; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
+ size_t value_len; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
+ ly_bool dynamic; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
struct {
enum LYJSON_PARSER_STATUS status;
@@ -75,32 +78,11 @@
const char *value;
size_t value_len;
ly_bool dynamic;
- uint32_t depth;
const char *input;
} backup;
};
/**
- * @brief Create a new JSON parser context and start parsing.
- *
- * @param[in] ctx libyang context.
- * @param[in] in JSON string data to parse.
- * @param[in] subtree Whether this is a special case of parsing a subtree (starting with object name).
- * @param[out] jsonctx New JSON context with status referring the parsed value.
- * @return LY_ERR value.
- */
-LY_ERR lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, ly_bool subtree, struct lyjson_ctx **jsonctx);
-
-/**
- * @brief Get status of the parser as the last/previous parsed token
- *
- * @param[in] jsonctx JSON context to check.
- * @param[in] index Index of the token, starting by 0 for the last token
- * @return ::LYJSON_ERROR in case of invalid index, other ::LYJSON_PARSER_STATUS corresponding to the token.
- */
-enum LYJSON_PARSER_STATUS lyjson_ctx_status(struct lyjson_ctx *jsonctx, uint32_t index);
-
-/**
* @brief Get string representation of the JSON context status (token).
*
* @param[in] status Context status (aka JSON token)
@@ -109,6 +91,33 @@
const char *lyjson_token2str(enum LYJSON_PARSER_STATUS status);
/**
+ * @brief Get current status of the parser.
+ *
+ * @param[in] jsonctx JSON parser context to check.
+ * @return ::LYJSON_PARSER_STATUS according to the last parsed token.
+ */
+enum LYJSON_PARSER_STATUS lyjson_ctx_status(struct lyjson_ctx *jsonctx);
+
+/**
+ * @brief Get current nesting (object/array) depth.
+ *
+ * @param[in] jsonctx JSON parser context to check.
+ * @return Current nesting depth.
+ */
+uint32_t lyjson_ctx_depth(struct lyjson_ctx *jsonctx);
+
+/**
+ * @brief Create a new JSON parser context and start parsing.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] in JSON string data to parse.
+ * @param[in] subtree Whether this is a special case of parsing a subtree (starting with object name).
+ * @param[out] jsonctx New JSON parser context with status referring the parsed value.
+ * @return LY_ERR value.
+ */
+LY_ERR lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lyjson_ctx **jsonctx);
+
+/**
* @brief Move to the next JSON artifact and update parser status.
*
* @param[in] jsonctx XML context to move.
@@ -119,12 +128,14 @@
/**
* @brief Backup the JSON parser context's state To restore the backup, use ::lyjson_ctx_restore().
+ *
* @param[in] jsonctx JSON parser context to backup.
*/
void lyjson_ctx_backup(struct lyjson_ctx *jsonctx);
/**
- * @brief REstore the JSON parser context's state from the backup created by ::lyjson_ctx_backup().
+ * @brief Restore the JSON parser context's state from the backup created by ::lyjson_ctx_backup().
+ *
* @param[in] jsonctx JSON parser context to restore.
*/
void lyjson_ctx_restore(struct lyjson_ctx *jsonctx);
@@ -132,7 +143,7 @@
/**
* @brief Remove the allocated working memory of the context.
*
- * @param[in] jsonctx JSON context to clear.
+ * @param[in] jsonctx JSON parser context to clear.
*/
void lyjson_ctx_free(struct lyjson_ctx *jsonctx);
diff --git a/src/parser_json.c b/src/parser_json.c
index 4c9858e..3abb1b5 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief JSON data parser for libyang
*
- * Copyright (c) 2020 - 2022 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -195,36 +195,39 @@
lydjson_data_skip(struct lyjson_ctx *jsonctx)
{
enum LYJSON_PARSER_STATUS status, current;
- uint32_t orig_depth;
+ uint32_t depth;
- status = lyjson_ctx_status(jsonctx, 0);
- orig_depth = jsonctx->depth;
+ status = lyjson_ctx_status(jsonctx);
+ depth = lyjson_ctx_depth(jsonctx);
- /* next */
- LY_CHECK_RET(lyjson_ctx_next(jsonctx, ¤t));
+ switch (status) {
+ case LYJSON_OBJECT:
+ ++depth;
- if ((status != LYJSON_OBJECT) && (status != LYJSON_ARRAY)) {
- return LY_SUCCESS;
- }
-
- if ((status == LYJSON_OBJECT) && (current != LYJSON_OBJECT) && (current != LYJSON_ARRAY)) {
- /* no nested objects */
- return LY_SUCCESS;
- }
-
- /* skip after the content */
- while ((jsonctx->depth > orig_depth) || (current != status + 1)) {
- if (current == LYJSON_ARRAY) {
- /* skip the array separately */
- LY_CHECK_RET(lydjson_data_skip(jsonctx));
- current = lyjson_ctx_status(jsonctx, 0);
- } else {
+ /* skip until object closes */
+ do {
LY_CHECK_RET(lyjson_ctx_next(jsonctx, ¤t));
- }
+ } while ((current != LYJSON_OBJECT_CLOSED) || (depth != lyjson_ctx_depth(jsonctx)));
+ break;
+ case LYJSON_ARRAY:
+ ++depth;
- if (current == LYJSON_END) {
- break;
+ /* skip until array closes */
+ do {
+ LY_CHECK_RET(lyjson_ctx_next(jsonctx, ¤t));
+ } while ((current != LYJSON_ARRAY_CLOSED) || (depth != lyjson_ctx_depth(jsonctx)));
+ break;
+ case LYJSON_OBJECT_NAME:
+ /* just get to the value */
+ LY_CHECK_RET(lyjson_ctx_next(jsonctx, ¤t));
+ if ((current == LYJSON_OBJECT) || (current == LYJSON_ARRAY)) {
+ LY_CHECK_RET(lydjson_data_skip(jsonctx));
}
+ break;
+ default:
+ /* no other status expected */
+ LOGINT(jsonctx->ctx);
+ return LY_EINT;
}
return LY_SUCCESS;
@@ -347,30 +350,34 @@
static LY_ERR
lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list)
{
- LY_ERR ret = LY_SUCCESS;
- enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx, 0);
+ LY_ERR rc = LY_SUCCESS;
+ enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx);
struct ly_set key_set = {0};
const struct lysc_node *snode;
- uint32_t i, status_count;
+ uint32_t i;
assert(list && (list->nodetype == LYS_LIST));
/* get all keys into a set (keys do not have if-features or anything) */
snode = NULL;
while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
- ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = ly_set_add(&key_set, (void *)snode, 1, NULL);
+ LY_CHECK_GOTO(rc, cleanup);
+ }
+ if (!key_set.count) {
+ /* no keys */
+ goto cleanup;
}
if (status == LYJSON_OBJECT) {
- status_count = jsonctx->status.count;
-
- while (key_set.count && (status != LYJSON_OBJECT_CLOSED)) {
+ do {
const char *name, *prefix;
size_t name_len, prefix_len;
ly_bool is_attr;
/* match the key */
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
+ assert(status == LYJSON_OBJECT_NAME);
snode = NULL;
lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
@@ -381,45 +388,43 @@
break;
}
}
- /* go into the item to a) process it as a key or b) start skipping it as another list child */
- ret = lyjson_ctx_next(jsonctx, &status);
- LY_CHECK_GOTO(ret, cleanup);
+
+ /* get the value */
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
if (snode) {
/* we have the key, validate the value */
- if (status < LYJSON_NUMBER) {
+ if ((status < LYJSON_NUMBER) && (status > LYJSON_NULL)) {
/* not a terminal */
- ret = LY_ENOT;
+ rc = LY_ENOT;
goto cleanup;
}
- ret = lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL);
+ LY_CHECK_GOTO(rc, cleanup);
/* key with a valid value, remove from the set */
ly_set_rm_index(&key_set, i, NULL);
}
+
+ /* next object */
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
} else {
- /* start skipping the member we are not interested in */
- ret = lyjson_ctx_next(jsonctx, &status);
- LY_CHECK_GOTO(ret, cleanup);
+ /* skip the uninteresting object */
+ LY_CHECK_GOTO(rc = lydjson_data_skip(jsonctx), cleanup);
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
}
- /* move to the next child */
- while (status_count < jsonctx->status.count) {
- ret = lyjson_ctx_next(jsonctx, &status);
- LY_CHECK_GOTO(ret, cleanup);
- }
- }
+ } while (key_set.count && (status == LYJSON_OBJECT_NEXT));
}
if (key_set.count) {
/* some keys are missing/did not validate */
- ret = LY_ENOT;
+ rc = LY_ENOT;
}
cleanup:
ly_set_erase(&key_set, NULL);
- return ret;
+ return rc;
}
/**
@@ -448,7 +453,7 @@
}
LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
- if (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_ARRAY_CLOSED) {
+ if (lyjson_ctx_status(lydctx->jsonctx) != LYJSON_ARRAY_CLOSED) {
LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Expected array end, but input data contains %s.",
lyjson_token2str(*status_p));
return LY_EINVAL;
@@ -502,7 +507,7 @@
/* backup parser */
lyjson_ctx_backup(jsonctx);
- status = lyjson_ctx_status(jsonctx, 0);
+ status = lyjson_ctx_status(jsonctx);
if (lydctx->parse_opts & LYD_PARSE_OPAQ) {
/* check if the node is parseable. if not, NULL the snode to announce that it is supposed to be parsed
@@ -529,7 +534,6 @@
break;
}
} else if (snode->nodetype & LYD_NODE_TERM) {
- status = lyjson_ctx_status(jsonctx, 0);
ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
}
@@ -715,7 +719,7 @@
static LY_ERR
lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR rc = LY_SUCCESS;
enum LYJSON_PARSER_STATUS status;
const char *expected;
ly_bool in_parent = 0;
@@ -735,33 +739,29 @@
LOG_LOCSET(snode, NULL, NULL, NULL);
/* move to the second item in the name/X pair */
- ret = lyjson_ctx_next(lydctx->jsonctx, &status);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
/* check attribute encoding */
switch (nodetype) {
case LYS_LEAFLIST:
expected = "@name/array of objects/nulls";
-
LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
next_entry:
- instance++;
-
- /* move into array/next entry */
- ret = lyjson_ctx_next(lydctx->jsonctx, &status);
- LY_CHECK_GOTO(ret, cleanup);
-
if (status == LYJSON_ARRAY_CLOSED) {
/* no more metadata */
goto cleanup;
}
+
+ /* move into the array/next item */
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
+ instance++;
LY_CHECK_GOTO((status != LYJSON_OBJECT) && (status != LYJSON_NULL), representation_error);
if (!node || (node->schema != prev->schema)) {
LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing JSON data instance #%u of %s:%s to be coupled with metadata.",
instance, prev->schema->module->name, prev->schema->name);
- ret = LY_EVALID;
+ rc = LY_EVALID;
goto cleanup;
}
@@ -769,6 +769,8 @@
/* continue with the next entry in the leaf-list array */
prev = node;
node = node->next;
+
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
goto next_entry;
}
break;
@@ -790,31 +792,31 @@
break;
default:
LOGINT(ctx);
- ret = LY_EINT;
+ rc = LY_EINT;
goto cleanup;
}
/* process all the members inside a single metadata object */
assert(status == LYJSON_OBJECT);
- while (status != LYJSON_OBJECT_CLOSED) {
- LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
-
+ do {
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
+ assert(status == LYJSON_OBJECT_NAME);
lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
lyjson_ctx_give_dynamic_value(lydctx->jsonctx, &dynamic_prefname);
if (!name_len) {
LOGVAL(ctx, LYVE_SYNTAX_JSON, "Metadata in JSON found with an empty name, followed by: %.10s", name);
- ret = LY_EVALID;
+ rc = LY_EVALID;
goto cleanup;
} else if (!prefix_len) {
LOGVAL(ctx, LYVE_SYNTAX_JSON, "Metadata in JSON must be namespace-qualified, missing prefix for \"%.*s\".",
(int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
- ret = LY_EVALID;
+ rc = LY_EVALID;
goto cleanup;
} else if (is_attr) {
LOGVAL(ctx, LYVE_SYNTAX_JSON, "Invalid format of the Metadata identifier in JSON, unexpected '@' in \"%.*s\"",
(int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
- ret = LY_EVALID;
+ rc = LY_EVALID;
goto cleanup;
}
@@ -824,14 +826,13 @@
if (lydctx->parse_opts & LYD_PARSE_STRICT) {
LOGVAL(ctx, LYVE_REFERENCE, "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
(int)prefix_len, prefix, (int)name_len, name);
- ret = LY_EVALID;
+ rc = LY_EVALID;
goto cleanup;
}
if (node->schema) {
/* skip element with children */
- ret = lydjson_data_skip(lydctx->jsonctx);
- LY_CHECK_GOTO(ret, cleanup);
- status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ LY_CHECK_GOTO(rc = lydjson_data_skip(lydctx->jsonctx), cleanup);
+ status = lyjson_ctx_status(lydctx->jsonctx);
/* end of the item */
continue;
}
@@ -839,22 +840,20 @@
}
/* get the value */
- ret = lyjson_ctx_next(lydctx->jsonctx, &status);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
/* get value hints */
- ret = lydjson_value_type_hint(lydctx, &status, &val_hints);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx, &status, &val_hints), cleanup);
if (node->schema) {
/* create metadata */
- ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod, name, name_len, lydctx->jsonctx->value,
+ rc = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod, name, name_len, lydctx->jsonctx->value,
lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL, val_hints, node->schema);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc, cleanup);
/* add/correct flags */
- ret = lyd_parse_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, NULL);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = lyd_parse_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, NULL);
+ LY_CHECK_GOTO(rc, cleanup);
} else {
/* create attribute */
const char *module_name;
@@ -863,22 +862,24 @@
lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
/* attr2 is always changed to the created attribute */
- ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name,
+ rc = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name,
module_name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic,
LY_VALUE_JSON, NULL, val_hints);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(rc, cleanup);
}
+
/* next member */
- ret = lyjson_ctx_next(lydctx->jsonctx, &status);
- LY_CHECK_GOTO(ret, cleanup);
- LY_CHECK_GOTO((status != LYJSON_OBJECT) && (status != LYJSON_OBJECT_CLOSED), representation_error);
- }
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
+ } while (status == LYJSON_OBJECT_NEXT);
+ LY_CHECK_GOTO(status != LYJSON_OBJECT_CLOSED, representation_error);
if (nodetype == LYS_LEAFLIST) {
/* continue by processing another metadata object for the following
* leaf-list instance since they are always instantiated in JSON array */
prev = node;
node = node->next;
+
+ LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
goto next_entry;
}
@@ -890,12 +891,12 @@
"The attribute(s) of %s \"%s\" is expected to be represented as JSON %s, but input data contains @%s/%s.",
lys_nodetype2str(nodetype), node ? LYD_NAME(node) : LYD_NAME(prev), expected, lyjson_token2str(status),
in_parent ? "" : "name");
- ret = LY_EVALID;
+ rc = LY_EVALID;
cleanup:
free(dynamic_prefname);
LOG_LOCBACK(1, 0, 0, 0);
- return ret;
+ return rc;
}
/**
@@ -959,7 +960,7 @@
ly_bool dynamic = 0;
uint32_t type_hint = 0;
- if ((*status_inner_p != LYJSON_OBJECT) && (*status_inner_p != LYJSON_OBJECT_EMPTY)) {
+ if (*status_inner_p != LYJSON_OBJECT) {
/* prepare for creating opaq node with a value */
value = lydctx->jsonctx->value;
value_len = lydctx->jsonctx->value_len;
@@ -1024,18 +1025,17 @@
goto finish;
}
- while ((*status_p == LYJSON_ARRAY) || (*status_p == LYJSON_ARRAY_EMPTY)) {
+ while (*status_p == LYJSON_ARRAY) {
/* process another instance of the same node */
-
- if ((*status_inner_p == LYJSON_OBJECT) || (*status_inner_p == LYJSON_OBJECT_EMPTY)) {
+ if (*status_inner_p == LYJSON_OBJECT) {
/* array with objects, list */
((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LIST;
/* but first process children of the object in the array */
- while ((*status_inner_p != LYJSON_OBJECT_CLOSED) && (*status_inner_p != LYJSON_OBJECT_EMPTY)) {
+ do {
LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
- *status_inner_p = lyjson_ctx_status(lydctx->jsonctx, 0);
- }
+ *status_inner_p = lyjson_ctx_status(lydctx->jsonctx);
+ } while (*status_inner_p == LYJSON_OBJECT_NEXT);
} else {
/* array with values, leaf-list */
((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LEAFLIST;
@@ -1045,19 +1045,21 @@
if (*status_inner_p == LYJSON_ARRAY_CLOSED) {
goto finish;
}
+ assert(*status_inner_p == LYJSON_ARRAY_NEXT);
/* continue with the next instance */
+ LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
assert(node_p);
lydjson_maintain_children(parent, first_p, node_p, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0, NULL);
LY_CHECK_RET(lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p));
}
- if ((*status_p == LYJSON_OBJECT) || (*status_p == LYJSON_OBJECT_EMPTY)) {
+ if (*status_p == LYJSON_OBJECT) {
/* process children */
- while (*status_p != LYJSON_OBJECT_CLOSED && *status_p != LYJSON_OBJECT_EMPTY) {
+ do {
LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
- *status_p = lyjson_ctx_status(lydctx->jsonctx, 0);
- }
+ *status_p = lyjson_ctx_status(lydctx->jsonctx);
+ } while (*status_p == LYJSON_OBJECT_NEXT);
}
finish:
@@ -1086,8 +1088,8 @@
* @return LY_ERR value.
*/
static LY_ERR
-lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len,
- const char *prefix, size_t prefix_len, struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p,
+lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix,
+ size_t prefix_len, struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p,
struct lyd_node **first_p, struct lyd_node **node_p)
{
enum LYJSON_PARSER_STATUS status_inner = 0;
@@ -1228,17 +1230,18 @@
uint32_t prev_parse_opts, prev_int_opts;
struct ly_in in_start;
char *val = NULL;
+ const char *end;
struct lyd_node *tree = NULL;
assert(snode->nodetype & LYD_NODE_ANY);
/* status check according to allowed JSON types */
if (snode->nodetype == LYS_ANYXML) {
- LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY) && (*status != LYJSON_ARRAY) &&
- (*status != LYJSON_ARRAY_EMPTY) && (*status != LYJSON_NUMBER) && (*status != LYJSON_STRING) &&
- (*status != LYJSON_FALSE) && (*status != LYJSON_TRUE) && (*status != LYJSON_NULL), LY_ENOT);
+ LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_ARRAY) && (*status != LYJSON_NUMBER) &&
+ (*status != LYJSON_STRING) && (*status != LYJSON_FALSE) && (*status != LYJSON_TRUE) &&
+ (*status != LYJSON_NULL), LY_ENOT);
} else {
- LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY), LY_ENOT);
+ LY_CHECK_RET(*status != LYJSON_OBJECT, LY_ENOT);
}
/* create any node */
@@ -1253,12 +1256,12 @@
lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
/* process the anydata content */
- while (*status != LYJSON_OBJECT_CLOSED) {
+ do {
r = lydjson_subtree_r(lydctx, NULL, &tree, NULL);
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
- *status = lyjson_ctx_status(lydctx->jsonctx, 0);
- }
+ *status = lyjson_ctx_status(lydctx->jsonctx);
+ } while (*status == LYJSON_OBJECT_NEXT);
/* restore parser options */
lydctx->parse_opts = prev_parse_opts;
@@ -1271,22 +1274,19 @@
r = lyd_create_any(snode, tree, LYD_ANYDATA_DATATREE, 1, node);
LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
break;
- case LYJSON_ARRAY_EMPTY:
- /* store the empty array */
- if (asprintf(&val, "[]") == -1) {
- LOGMEM(lydctx->jsonctx->ctx);
- return LY_EMEM;
- }
- r = lyd_create_any(snode, val, LYD_ANYDATA_JSON, 1, node);
- LY_CHECK_ERR_GOTO(r, rc = r, val_err);
- break;
case LYJSON_ARRAY:
/* skip until the array end */
in_start = *lydctx->jsonctx->in;
LY_CHECK_RET(lydjson_data_skip(lydctx->jsonctx));
+ /* return back by all the WS */
+ end = lydctx->jsonctx->in->current;
+ while (is_jsonws(end[-1])) {
+ --end;
+ }
+
/* make a copy of the whole array and store it */
- if (asprintf(&val, "[%.*s", (int)(lydctx->jsonctx->in->current - in_start.current), in_start.current) == -1) {
+ if (asprintf(&val, "[%.*s", (int)(end - in_start.current), in_start.current) == -1) {
LOGMEM(lydctx->jsonctx->ctx);
return LY_EMEM;
}
@@ -1322,11 +1322,6 @@
r = lyd_create_any(snode, NULL, LYD_ANYDATA_JSON, 1, node);
LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
break;
- case LYJSON_OBJECT_EMPTY:
- /* empty object */
- r = lyd_create_any(snode, NULL, LYD_ANYDATA_DATATREE, 1, node);
- LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
- break;
default:
LOGINT_RET(lydctx->jsonctx->ctx);
}
@@ -1358,7 +1353,7 @@
LY_ERR r, rc = LY_SUCCESS;
uint32_t prev_parse_opts = lydctx->parse_opts;
- LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY), LY_ENOT);
+ LY_CHECK_RET(*status != LYJSON_OBJECT, LY_ENOT);
/* create inner node */
LY_CHECK_RET(lyd_create_inner(snode, node));
@@ -1372,12 +1367,12 @@
}
/* process children */
- while ((*status != LYJSON_OBJECT_CLOSED) && (*status != LYJSON_OBJECT_EMPTY)) {
+ do {
r = lydjson_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL);
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
- *status = lyjson_ctx_status(lydctx->jsonctx, 0);
- }
+ *status = lyjson_ctx_status(lydctx->jsonctx);
+ } while (*status == LYJSON_OBJECT_NEXT);
/* finish linking metadata */
r = lydjson_metadata_finish(lydctx, lyd_node_child_p(*node));
@@ -1520,7 +1515,7 @@
lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
{
LY_ERR r, rc = LY_SUCCESS;
- enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx);
const char *name, *prefix = NULL, *expected = NULL;
size_t name_len, prefix_len = 0;
ly_bool is_meta = 0, parse_subtree;
@@ -1531,13 +1526,21 @@
char *value = NULL;
assert(parent || first_p);
- assert(status == LYJSON_OBJECT);
+ assert((status == LYJSON_OBJECT) || (status == LYJSON_OBJECT_NEXT));
parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
/* all descendants should be parsed */
lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
+ r = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ if (status == LYJSON_OBJECT_CLOSED) {
+ /* empty object, fine... */
+ goto cleanup;
+ }
+
/* process the node name */
+ assert(status == LYJSON_OBJECT_NAME);
lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_meta);
lyjson_ctx_give_dynamic_value(lydctx->jsonctx, &value);
@@ -1643,18 +1646,18 @@
switch (snode->nodetype) {
case LYS_LEAFLIST:
case LYS_LIST:
- if (status == LYJSON_ARRAY_EMPTY) {
- /* no instances, skip */
- break;
- }
LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
- /* move into array */
- r = lyjson_ctx_next(lydctx->jsonctx, &status);
- LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
-
/* process all the values/objects */
do {
+ /* move into array/next value */
+ r = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ if (status == LYJSON_ARRAY_CLOSED) {
+ /* empty array, fine... */
+ break;
+ }
+
r = lydjson_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
&status, &node);
if (r == LY_ENOT) {
@@ -1667,7 +1670,7 @@
/* move after the item(s) */
r = lyjson_ctx_next(lydctx->jsonctx, &status);
LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
- } while (status != LYJSON_ARRAY_CLOSED);
+ } while (status == LYJSON_ARRAY_NEXT);
break;
case LYS_LEAF:
@@ -1735,20 +1738,17 @@
* @param[in] parse_opts Options for parser, see @ref dataparseroptions.
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
* @param[out] lydctx_p Data parser context to finish validation.
- * @param[out] status Storage for the current context's status
* @return LY_ERR value.
*/
static LY_ERR
lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
- struct lyd_json_ctx **lydctx_p, enum LYJSON_PARSER_STATUS *status)
+ struct lyd_json_ctx **lydctx_p)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_json_ctx *lydctx;
- size_t i;
- ly_bool subtree;
+ enum LYJSON_PARSER_STATUS status;
assert(lydctx_p);
- assert(status);
/* init context */
lydctx = calloc(1, sizeof *lydctx);
@@ -1757,28 +1757,20 @@
lydctx->val_opts = val_opts;
lydctx->free = lyd_json_ctx_free;
- /* starting top-level */
- for (i = 0; in->current[i] != '\0' && is_jsonws(in->current[i]); i++) {
- if (in->current[i] == '\n') {
- /* new line */
- LY_IN_NEW_LINE(in);
- }
- }
+ LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
+ status = lyjson_ctx_status(lydctx->jsonctx);
- subtree = (parse_opts & LYD_PARSE_SUBTREE) ? 1 : 0;
- LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, subtree, &lydctx->jsonctx), free(lydctx), ret);
- *status = lyjson_ctx_status(lydctx->jsonctx, 0);
-
- if ((*status == LYJSON_END) || (*status == LYJSON_OBJECT_EMPTY) || (*status == LYJSON_OBJECT)) {
- *lydctx_p = lydctx;
- return LY_SUCCESS;
- } else {
+ /* parse_opts & LYD_PARSE_SUBTREE not implemented */
+ if (status != LYJSON_OBJECT) {
/* expecting top-level object */
- LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.", lyjson_token2str(*status));
+ LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.", lyjson_token2str(status));
*lydctx_p = NULL;
lyd_json_ctx_free((struct lyd_ctx *)lydctx);
return LY_EVALID;
}
+
+ *lydctx_p = lydctx;
+ return LY_SUCCESS;
}
LY_ERR
@@ -1790,10 +1782,8 @@
struct lyd_json_ctx *lydctx = NULL;
enum LYJSON_PARSER_STATUS status;
- rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx, &status);
- LY_CHECK_GOTO(rc || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
-
- assert(status == LYJSON_OBJECT);
+ rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx);
+ LY_CHECK_GOTO(rc, cleanup);
lydctx->int_opts = int_opts;
lydctx->ext = ext;
@@ -1802,20 +1792,20 @@
LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
/* read subtree(s) */
- while (status == LYJSON_OBJECT) {
+ do {
r = lydjson_subtree_r(lydctx, parent, first_p, parsed);
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
- status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ status = lyjson_ctx_status(lydctx->jsonctx);
if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
break;
}
- }
+ } while (status == LYJSON_OBJECT_NEXT);
assert((status == LYJSON_END) || (status == LYJSON_OBJECT_CLOSED));
if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && lydctx->jsonctx->in->current[0] &&
- (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_OBJECT_CLOSED)) {
+ (lyjson_ctx_status(lydctx->jsonctx) != LYJSON_OBJECT_CLOSED)) {
LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
r = LY_EVALID;
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
diff --git a/tests/utests/basic/test_json.c b/tests/utests/basic/test_json.c
index e6774d4..08b7719 100644
--- a/tests/utests/basic/test_json.c
+++ b/tests/utests/basic/test_json.c
@@ -27,39 +27,40 @@
/* empty */
str = "";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ CHECK_LOG_CTX("Empty JSON file.", "Line number 1.");
str = " \n\t \n";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
- lyjson_ctx_free(jsonctx);
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ CHECK_LOG_CTX("Empty JSON file.", "Line number 3.");
/* constant values */
str = "true";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
str = "false";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
str = "null";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
ly_in_free(in, 0);
@@ -75,8 +76,8 @@
/* simple value */
str = "11";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("11", jsonctx->value);
assert_int_equal(2, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
@@ -85,8 +86,8 @@
/* fraction number */
str = "37.7668";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("37.7668", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
@@ -95,8 +96,8 @@
/* negative number */
str = "-122.3959";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-122.3959", jsonctx->value);
assert_int_equal(9, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
@@ -105,8 +106,8 @@
/* integer, positive exponent */
str = "550E3";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("550000", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -114,8 +115,8 @@
str = "-550E3";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-550000", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -124,8 +125,8 @@
/* integer, negative exponent */
str = "1E-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.1", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -133,8 +134,8 @@
str = "15E-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("1.5", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -142,8 +143,8 @@
str = "-15E-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-1.5", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -151,8 +152,8 @@
str = "16E-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.16", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -160,8 +161,8 @@
str = "-16E-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-0.16", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -169,8 +170,8 @@
str = "17E-3";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.017", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -178,8 +179,8 @@
str = "-17E-3";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-0.017", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -187,8 +188,8 @@
str = "21000E-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("210", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -196,8 +197,8 @@
str = "21000E-4";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("2.1", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -205,8 +206,8 @@
str = "21000E-7";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.0021", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -215,8 +216,8 @@
/* decimal number, positive exponent */
str = "5.087E1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("50.87", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -224,8 +225,8 @@
str = "-5.087E1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-50.87", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -233,8 +234,8 @@
str = "5.087E5";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("508700", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -242,8 +243,8 @@
str = "59.1e+1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("591", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -251,8 +252,8 @@
str = "0.005087E1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.05087", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -260,8 +261,8 @@
str = "0.005087E2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.5087", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -269,8 +270,8 @@
str = "0.005087E6";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("5087", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -278,8 +279,8 @@
str = "0.05087E6";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("50870", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -287,8 +288,8 @@
str = "0.005087E8";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("508700", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -297,8 +298,8 @@
/* decimal number, negative exponent */
str = "35.94e-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("3.594", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -306,8 +307,8 @@
str = "-35.94e-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-3.594", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -315,8 +316,8 @@
str = "35.94e-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.3594", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -324,8 +325,8 @@
str = "35.94e-3";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.03594", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -333,8 +334,8 @@
str = "0.3594e-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.03594", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -342,8 +343,8 @@
str = "0.03594e-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.003594", jsonctx->value);
assert_int_equal(8, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -351,8 +352,8 @@
str = "0.003594e-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.0003594", jsonctx->value);
assert_int_equal(9, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -360,8 +361,8 @@
str = "0.3594e-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.003594", jsonctx->value);
assert_int_equal(8, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -369,8 +370,8 @@
str = "0.03594e-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.0003594", jsonctx->value);
assert_int_equal(9, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -378,8 +379,8 @@
str = "0.003594e-2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.00003594", jsonctx->value);
assert_int_equal(10, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -388,8 +389,8 @@
/* zero */
str = "0";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '0');
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
@@ -397,8 +398,8 @@
str = "-0";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '-');
assert_true(jsonctx->value[1] == '0');
assert_int_equal(2, jsonctx->value_len);
@@ -407,8 +408,8 @@
str = "94E0";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '9');
assert_true(jsonctx->value[1] == '4');
assert_int_equal(2, jsonctx->value_len);
@@ -417,8 +418,8 @@
str = "0E2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '0');
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
@@ -426,8 +427,8 @@
str = "-0E2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '-');
assert_true(jsonctx->value[1] == '0');
assert_int_equal(2, jsonctx->value_len);
@@ -436,8 +437,8 @@
str = "5.320e+2";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("532", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -445,8 +446,8 @@
str = "5.320e-1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.532", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
@@ -455,69 +456,64 @@
/* various invalid inputs */
str = "-x";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", "Line number 1.");
str = " -";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
str = "--1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"-\").", "Line number 1.");
str = "+1";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character sequence \"+1\", expected a JSON value.", "Line number 1.");
str = " 1.x ";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", "Line number 1.");
str = "1.";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
str = " 1eo ";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"o\").", "Line number 1.");
str = "1e";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
str = "1E1000";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.", "Line number 1.");
str = "1e9999999999999999999";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1e9999999999999999999).", "Line number 1.");
str = "1.1e66000";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e66000).", "Line number 1.");
str = "1.1e-66000";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e-66000).", "Line number 1.");
- str = "-2.1e0.";
- assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- CHECK_LOG_CTX("Unexpected character \".\" after JSON number.", "Line number 1.");
-
ly_in_free(in, 0);
}
@@ -535,7 +531,7 @@
/* unterminated string */
str = "\"unterminated string";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Missing quotation-mark at the end of a JSON string.", "Line number 1.");
CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
@@ -552,95 +548,122 @@
/* empty */
str = " { } ";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_OBJECT_EMPTY, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* simple value */
str = "{\"name\" : \"Radek\"}";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_ptr_equal(&str[2], jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("\"Radek\"}", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
assert_string_equal("Radek\"}", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("}", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* two values */
str = "{\"smart\" : true,\"handsom\":false}";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("smart\" : true,\"handsom\":false}", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("true,\"handsom\":false}", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx, 0));
- assert_string_equal(",\"handsom\":false}", jsonctx->in->current);
+ assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_OBJECT_NEXT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("handsom\":false}", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("false}", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx, 0));
- assert_string_equal("}", jsonctx->in->current);
+ assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* inherited objects */
str = "{\"person\" : {\"name\":\"Radek\"}}";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("person\" : {\"name\":\"Radek\"}}", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("{\"name\":\"Radek\"}}", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("name\":\"Radek\"}}", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("\"Radek\"}}", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
assert_string_equal("Radek\"}}", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("}}", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
- assert_string_equal("}", jsonctx->in->current);
+ assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
- /* new line is allowed only as escaped character in JSON */
+ /* unquoted string */
str = "{ unquoted : \"data\"}";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- CHECK_LOG_CTX("Invalid character sequence \"unquoted : \"data\"}\", expected a JSON object's member.", "Line number 1.");
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
+ CHECK_LOG_CTX("Invalid character sequence \"unquoted : \"data\"}\", expected a JSON object name.", "Line number 1.");
+ lyjson_ctx_free(jsonctx);
ly_in_free(in, 0);
}
@@ -655,67 +678,79 @@
/* empty */
str = " [ ] ";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_ARRAY_EMPTY, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* simple value */
str = "[ null]";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
assert_null(jsonctx->value);
assert_int_equal(0, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("null]", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0));
- assert_string_equal("]", jsonctx->in->current);
+ assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* two values */
str = "[{\"a\":null},\"x\"]";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
- assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+ assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
assert_null(jsonctx->value);
assert_int_equal(0, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("{\"a\":null},\"x\"]", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("a\":null},\"x\"]", jsonctx->value);
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("null},\"x\"]", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0));
- assert_string_equal("},\"x\"]", jsonctx->in->current);
+ assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
- assert_string_equal(",\"x\"]", jsonctx->in->current);
+ assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_ARRAY_NEXT, lyjson_ctx_status(jsonctx));
+
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+ assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
assert_string_equal("x\"]", jsonctx->value);
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
- assert_string_equal("]", jsonctx->in->current);
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
+
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
- assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+ assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* new line is allowed only as escaped character in JSON */
str = "[ , null]";
assert_non_null(ly_in_memory(in, str));
- assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+ assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
CHECK_LOG_CTX("Invalid character sequence \", null]\", expected a JSON value.", "Line number 1.");
lyjson_ctx_free(jsonctx);
diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c
index 17a7433..a953330 100644
--- a/tests/utests/data/test_validation.c
+++ b/tests/utests/data/test_validation.c
@@ -1219,7 +1219,7 @@
CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements");
CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left");
CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation");
- CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\", line number 8.", NULL);
+ CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\", line number 9.", NULL);
CHECK_LOG_CTX_APPTAG("Invalid non-number-encoded uint32 value \"ahoy\".", "Data location \"/ii:cont/ll\", line number 7.", NULL);
/* validation */
@@ -1511,7 +1511,7 @@
" }\n"
"}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.",
- "Data location \"/k:ch\", line number 5.");
+ "Data location \"/k:ch\", line number 6.");
CHECK_PARSE_LYD_PARAM(
"{\n"
@@ -1521,7 +1521,7 @@
" }\n"
"}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.",
- "Data location \"/k:ch\", line number 5.");
+ "Data location \"/k:ch\", line number 6.");
}
int
diff --git a/tests/utests/types/int8.c b/tests/utests/types/int8.c
index 14b1852..198d1f7 100644
--- a/tests/utests/types/int8.c
+++ b/tests/utests/types/int8.c
@@ -1243,10 +1243,10 @@
TEST_SUCCESS_JSON("T0", "127", INT8, "127", 127);
/* leading zeros */
TEST_ERROR_JSON("T0", "015");
- CHECK_LOG_CTX("Unexpected character \"1\" after JSON number.",
+ CHECK_LOG_CTX("Invalid character sequence \"15}\", expected a JSON object-end or next item.",
"Line number 1.");
TEST_ERROR_JSON("T0", "-015");
- CHECK_LOG_CTX("Unexpected character \"1\" after JSON number.",
+ CHECK_LOG_CTX("Invalid character sequence \"15}\", expected a JSON object-end or next item.",
"Line number 1.");
TEST_ERROR_JSON("defs", "+50");
CHECK_LOG_CTX("Invalid character sequence \"+50}\", expected a JSON value.",
diff --git a/tests/utests/types/string.c b/tests/utests/types/string.c
index a64a552..68c1d0a 100644
--- a/tests/utests/types/string.c
+++ b/tests/utests/types/string.c
@@ -868,7 +868,7 @@
CHECK_LOG_CTX("Invalid character reference \"\\f\" (0x0000000c).", "Line number 1.");
TEST_ERROR_JSON("T0", "\"");
- CHECK_LOG_CTX("Unexpected character \"\"\" after JSON string.", "Line number 1.");
+ CHECK_LOG_CTX("Invalid character sequence \"\"}\", expected a JSON object-end or next item.", "Line number 1.");
TEST_ERROR_JSON("T0", "aabb \\x");
CHECK_LOG_CTX("Invalid character escape sequence \\x.", "Line number 1.");