data FEATURE parser for YANG data in JSON format
diff --git a/src/common.h b/src/common.h
index 8010c0b..f7faa86 100644
--- a/src/common.h
+++ b/src/common.h
@@ -343,6 +343,11 @@
int ly_strncmp(const char *refstr, const char *str, size_t str_len);
/**
+ * @brief Wrapper around strlen() to handle NULL strings.
+ */
+#define ly_strlen(STR) (STR ? strlen(STR) : 0)
+
+/**
* @brief Get UTF8 code point of the next character in the input string.
*
* @param[in,out] input Input string to process, updated according to the processed/read data.
@@ -454,7 +459,7 @@
const char **value, size_t *value_len, const char **errmsg);
/**
- * @brief ly_clb_get_prefix implementation for JSON. For its simplicity, this implementation is used
+ * @brief ly_get_prefix_clb implementation for JSON. For its simplicity, this implementation is used
* internally for various purposes.
*
* Implemented in printer_json.c
diff --git a/src/json.h b/src/json.h
index 8373284..7b2221e 100644
--- a/src/json.h
+++ b/src/json.h
@@ -52,6 +52,9 @@
};
struct lyjson_ctx {
+ const struct ly_ctx *ctx;
+ uint64_t line; /* current line */
+ struct ly_in *in; /* input structure */
struct ly_set status; /* stack of LYJSON_PARSER_STATUS values corresponding to the JSON items being processed */
diff --git a/src/log.h b/src/log.h
index e71608f..9176a04 100644
--- a/src/log.h
+++ b/src/log.h
@@ -174,6 +174,7 @@
LYVE_XPATH, /**< invalid XPath expression */
LYVE_SEMANTICS, /**< generic semantic error */
LYVE_SYNTAX_XML, /**< XML-related syntax error */
+ LYVE_SYNTAX_JSON, /**< JSON-related syntax error */
LYVE_DATA, /**< YANG data does not reflect some of the module restrictions */
LYVE_OTHER /**< Unknown error */
diff --git a/src/lyb.h b/src/lyb.h
index bc159f3..000fab3 100644
--- a/src/lyb.h
+++ b/src/lyb.h
@@ -18,6 +18,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "parser_internal.h"
#include "set.h"
#include "tree.h"
@@ -26,10 +27,13 @@
struct lyd_node;
struct lysc_node;
-/**
- * @brief Internal structure for LYB parser/printer.
- */
-struct lyd_lyb_ctx {
+struct lylyb_ctx {
+ const struct ly_ctx *ctx;
+ uint64_t line; /* current line */
+ struct ly_in *in; /* input structure */
+
+ const struct lys_module **models;
+
struct lyd_lyb_subtree {
size_t written;
size_t position;
@@ -37,24 +41,6 @@
} *subtrees;
LY_ARRAY_COUNT_TYPE subtree_size;
- const struct ly_ctx *ctx;
- union {
- struct {
- int parse_options;
- int validate_options;
- };
- int print_options;
- };
-
- /* LYB parser only */
- struct ly_in *in;
- int int_opts;
- const struct lys_module **models;
- struct ly_set unres_node_type;
- struct ly_set unres_meta_type;
- struct ly_set when_check;
- struct lyd_node *op_ntf;
-
/* LYB printer only */
struct lyd_lyb_sib_ht {
struct lysc_node *first_sibling;
@@ -63,6 +49,39 @@
};
/**
+ * @brief Internal structure for LYB parser/printer.
+ *
+ * Note that the structure maps to the lyd_ctx which is common for all the data parsers
+ */
+struct lyd_lyb_ctx {
+ union {
+ struct {
+ uint32_t parse_options; /**< various @ref dataparseroptions. */
+ uint32_t validate_options; /**< various @ref datavalidationoptions. */
+ };
+ uint32_t print_options;
+ };
+ uint32_t int_opts; /**< internal data parser options */
+ uint32_t path_len; /**< used bytes in the path buffer */
+ char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
+ struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
+ struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
+ struct ly_set when_check; /**< set of nodes with "when" conditions */
+ struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
+
+ /* callbacks */
+ lyd_ctx_free_clb free; /* destructor */
+ ly_resolve_prefix_clb resolve_prefix;
+
+ struct lylyb_ctx *lybctx; /* lyb format context */
+};
+
+/**
+ * @brief Destructor for the lylyb_ctx structure
+ */
+void lyd_lyb_ctx_free(struct lyd_ctx *lydctx);
+
+/**
* LYB format
*
* Unlike XML or JSON, it is binary format so most data are represented in similar way but in binary.
diff --git a/src/parser.c b/src/parser.c
index fe8528b..e84dc58 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -28,7 +28,9 @@
#include "compat.h"
#include "dict.h"
#include "log.h"
+#include "parser_data.h"
#include "parser_internal.h"
+#include "tree_data_internal.h"
#include "tree_schema_internal.h"
API LY_IN_TYPE
@@ -353,3 +355,83 @@
in->current += count;
return LY_SUCCESS;
}
+
+void
+lyd_ctx_free(struct lyd_ctx *lydctx)
+{
+ ly_set_erase(&lydctx->unres_node_type, NULL);
+ ly_set_erase(&lydctx->unres_meta_type, NULL);
+ ly_set_erase(&lydctx->when_check, NULL);
+}
+
+LY_ERR
+lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
+{
+ /* alternatively, we could provide line for the error messages, but it doesn't work for the LYB format */
+
+ if ((lydctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
+ LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LY_VCODE_INNODE, "state", snode->name);
+ return LY_EVALID;
+ }
+
+ if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
+ if (lydctx->int_opts & LYD_INTOPT_RPC) {
+ if (lydctx->op_node) {
+ LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
+ lys_nodetype2str(snode->nodetype), snode->name,
+ lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
+ return LY_EVALID;
+ }
+ } else {
+ LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
+ lys_nodetype2str(snode->nodetype), snode->name);
+ return LY_EVALID;
+ }
+ } else if (snode->nodetype == LYS_NOTIF) {
+ if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
+ if (lydctx->op_node) {
+ LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
+ lys_nodetype2str(snode->nodetype), snode->name,
+ lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
+ return LY_EVALID;
+ }
+ } else {
+ LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
+ lys_nodetype2str(snode->nodetype), snode->name);
+ return LY_EVALID;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const char *value, size_t value_len,
+ int *dynamic, int value_hints, ly_resolve_prefix_clb get_prefix, void *prefix_data,
+ LYD_FORMAT format, struct lyd_node **node)
+{
+ LY_ERR ret;
+
+ ret = lyd_create_term(schema, value, value_len, dynamic, value_hints, get_prefix, prefix_data, format, node);
+ if (ret == LY_EINCOMPLETE) {
+ if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
+ ly_set_add(&lydctx->unres_node_type, *node, LY_SET_OPT_USEASLIST);
+ }
+ ret = LY_SUCCESS;
+ }
+ return ret;
+}
+
+LY_ERR
+lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
+ const char *name, size_t name_len, const char *value, size_t value_len, int *dynamic, int value_hints,
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
+{
+ LY_ERR ret;
+ ret = lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, value_hints, resolve_prefix, prefix_data, format, ctx_snode);
+ if (ret == LY_EINCOMPLETE) {
+ ly_set_add(&lydctx->unres_meta_type, *meta, LY_SET_OPT_USEASLIST);
+ ret = LY_SUCCESS;
+ }
+ return ret;
+}
diff --git a/src/parser_data.h b/src/parser_data.h
index de9f992..a2bac8b 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -220,8 +220,9 @@
* @param[in] format Format of the input data to be parsed.
* @param[out] tree Resulting full RPC/action reply tree built from the input data. The returned data are expected to be freed using lyd_free_all().
* The reply tree always includes duplicated operation node (and its parents) of the @p request, so in contrast to YANG data tree,
- * the result of parsing RPC/action reply cannot be NULL until an error occurs.
- * @param[out] op Optional pointer to the actual operation node inside the full action reply @p tree, useful only for action.
+ * the result of parsing RPC/action reply cannot be NULL until an error occurs. At least one of the @p tree and @p op output variables must be provided.
+ * @param[out] op Pointer to the actual operation node inside the full action reply @p tree, useful only for action. At least one of the @p op
+ * and @p tree output variables must be provided.
* @return LY_SUCCESS in case of successful parsing (and validation).
* @return LY_ERR value in case of error. Additional error information can be obtained from the request's context using ly_err* functions.
*/
diff --git a/src/parser_internal.h b/src/parser_internal.h
index f60e5bd..b2c4f15 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -28,6 +28,40 @@
*/
#define LYD_VALIDATE_OPTS_MASK 0x0000FFFF
+struct lyd_ctx;
+/**
+ * @brief Callback for lyd_ctx to free the structure
+ *
+ * @param[in] ctx Data parser context to free.
+ */
+typedef void (*lyd_ctx_free_clb)(struct lyd_ctx *ctx);
+
+/**
+ * @brief Internal (common) context for YANG data parsers.
+ */
+struct lyd_ctx {
+ uint32_t parse_options; /**< various @ref dataparseroptions. */
+ uint32_t validate_options; /**< various @ref datavalidationoptions. */
+ uint32_t int_opts; /**< internal data parser options */
+ uint32_t path_len; /**< used bytes in the path buffer */
+#define LYD_PARSER_BUFSIZE 4078
+ char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
+ struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
+ struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
+ struct ly_set when_check; /**< set of nodes with "when" conditions */
+ struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
+
+ /* callbacks */
+ lyd_ctx_free_clb free; /* destructor */
+ ly_resolve_prefix_clb resolve_prefix;
+
+ struct {
+ const struct ly_ctx *ctx;
+ uint64_t line; /* current line */
+ struct ly_in *in; /* input structure */
+ } *data_ctx; /* generic pointer supposed to map to and access (common part of) XML/JSON/... parser contexts */
+};
+
/**
* @brief Parser input structure specifying where the data are read.
*/
@@ -48,6 +82,11 @@
};
/**
+ * @brief Common part of the lyd_ctx_free_t callbacks.
+ */
+void lyd_ctx_free(struct lyd_ctx *);
+
+/**
* @brief Read bytes from an input.
*
* @param[in] in Input structure.
@@ -115,4 +154,33 @@
LY_ERR yin_parse_submodule(struct lys_yin_parser_ctx **yin_ctx, struct ly_ctx *ctx, struct lys_parser_ctx *main_ctx,
struct ly_in *in, struct lysp_submodule **submod);
+/**
+ * @brief Check that a data node representing the @p snode is suitable based on options.
+ *
+ * @param[in] lydctx Common data parsers context.
+ * @param[in] snode Schema node to check.
+ * @return LY_SUCCESS or LY_EVALID
+ */
+LY_ERR lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode);
+
+/**
+ * @brief Wrapper around lyd_create_term() for data parsers.
+ *
+ * @param[in] lydctx Data parser context.
+ * @param[in] value_hints Data parser's hint for the value's type.
+ */
+LY_ERR lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const char *value, size_t value_len,
+ int *dynamic, int value_hints, ly_resolve_prefix_clb get_prefix, void *prefix_data,
+ LYD_FORMAT format, struct lyd_node **node);
+
+/**
+ * @brief Wrapper around lyd_create_meta() for data parsers.
+ *
+ * @param[in] lydctx Data parser context.
+ * @param[in] value_hints [Value hint](@ref lydvalueparseopts) from the parser regarding the value type.
+ */
+LY_ERR lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
+ const char *name, size_t name_len, const char *value, size_t value_len, int *dynamic, int value_hints,
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode);
+
#endif /* LY_PARSER_INTERNAL_H_ */
diff --git a/src/parser_json.c b/src/parser_json.c
index 3163693..37ee765 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3,7 +3,7 @@
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief JSON data parser for libyang
*
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2020 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.
@@ -14,6 +14,7 @@
#define _GNU_SOURCE
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -21,23 +22,1846 @@
#include "compat.h"
#include "config.h"
#include "context.h"
+#include "json.h"
+#include "parser_internal.h"
+#include "tree_data.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+#include "validation.h"
/**
- * @brief JSON-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
- * in the values to the schema via context module names.
+ * @brief Internal context for JSON YANG data parser.
+ *
+ * Note that the structure maps to the lyd_ctx which is common for all the data parsers
+ */
+struct lyd_json_ctx {
+ uint32_t parse_options; /**< various @ref dataparseroptions. */
+ uint32_t validate_options; /**< various @ref datavalidationoptions. */
+ uint32_t int_opts; /**< internal data parser options */
+ uint32_t path_len; /**< used bytes in the path buffer */
+ char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
+ struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
+ struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
+ struct ly_set when_check; /**< set of nodes with "when" conditions */
+ struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
+
+ /* callbacks */
+ lyd_ctx_free_clb free; /* destructor */
+ ly_resolve_prefix_clb resolve_prefix;
+
+ struct lyjson_ctx *jsonctx; /**< JSON context */
+};
+
+/**
+ * @brief Free the JSON data parser context.
+ *
+ * JSON implementation of lyd_ctx_free_clb().
+ */
+static void
+lyd_json_ctx_free(struct lyd_ctx *lydctx)
+{
+ struct lyd_json_ctx *ctx = (struct lyd_json_ctx *)lydctx;
+
+ if (lydctx) {
+ lyd_ctx_free(lydctx);
+ lyjson_ctx_free(ctx->jsonctx);
+ free(ctx);
+ }
+}
+
+/**
+ * @brief JSON implementation of ly_resolve_prefix_clb.
*/
const struct lys_module *
lydjson_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *UNUSED(parser))
{
- const struct lys_module *mod;
- char *name;
+ return ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
+}
- name = strndup(prefix, prefix_len);
- if (!name) {
- return NULL;
+/**
+ * @brief Parse JSON member-name as [\@][prefix:][name]
+ *
+ * \@ - metadata flag, maps to 1 in @p is_attr_p
+ * prefix - name of the module of the data node
+ * name - name of the data node
+ *
+ * All the output parameter are mandatory. Function only parse the member-name, all the appropriate checks are up to the caller.
+ *
+ * @param[in] value String to parse
+ * @param[in] value_len Length of the @p str.
+ * @param[out] name_p Pointer to the beginning of the parsed name.
+ * @param[out] name_len_p Pointer to the length of the parsed name.
+ * @param[out] prefix_p Pointer to the beginning of the parsed prefix. If the member-name does not contain prefix, result is NULL.
+ * @param[out] prefix_len_p Pointer to the length of the parsed prefix. If the member-name does not contain prefix, result is 0.
+ * @param[out] is_attr_p Pointer to the metadata flag, set to 1 if the member-name contains \@, 0 otherwise.
+ */
+static void
+lydjson_parse_name(const char *value, size_t value_len, const char **name_p, size_t *name_len_p, const char **prefix_p, size_t *prefix_len_p, int *is_attr_p)
+{
+ const char *name, *prefix = NULL;
+ size_t name_len, prefix_len = 0;
+ int is_attr = 0;
+
+ name = memchr(value, ':', value_len);
+ if (name != NULL) {
+ prefix = value;
+ if (*prefix == '@') {
+ is_attr = 1;
+ prefix++;
+ }
+ prefix_len = name - prefix;
+ name++;
+ name_len = value_len - (prefix_len + 1) - is_attr;
+ } else {
+ name = value;
+ if (name[0] == '@') {
+ is_attr = 1;
+ name++;
+ }
+ name_len = value_len - is_attr;
}
- mod = ly_ctx_get_module_implemented(ctx, name);
- free(name);
- return mod;
+ *name_p = name;
+ *name_len_p = name_len;
+ *prefix_p = prefix;
+ *prefix_len_p = prefix_len;
+ *is_attr_p = is_attr;
+}
+
+/**
+ * @brief Get correct prefix (module_name) inside the @p node.
+ *
+ * @param[in] node Data node to get inherited prefix.
+ * @param[in] local_prefix Local prefix to replace the inherited prefix.
+ * @param[in] local_prefix_len Length of the @p local_prefix string. In case of 0, the inherited prefix is taken.
+ * @param[out] prefix_p Pointer to the resulting prefix string, Note that the result can be NULL in case of no local prefix
+ * and no context @p node to get inherited prefix.
+ * @param[out] prefix_len_p Pointer to the length of the resulting @p prefix_p string. Note that the result can be 0 in case
+ * of no local prefix and no context @p node to get inherited prefix.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydjson_get_node_prefix(struct lyd_node *node, const char *local_prefix, size_t local_prefix_len, const char **prefix_p, size_t *prefix_len_p)
+{
+ struct lyd_node_opaq *onode;
+ const char *module_name = NULL;
+
+ assert(prefix_p && prefix_len_p);
+
+ if (local_prefix_len) {
+ *prefix_p = local_prefix;
+ *prefix_len_p = local_prefix_len;
+ return LY_SUCCESS;
+ }
+
+ *prefix_p = NULL;
+ while (node) {
+ if (node->schema) {
+ *prefix_p = node->schema->module->name;
+ break;
+ }
+ onode = (struct lyd_node_opaq*)node;
+ if (onode->prefix.module_name) {
+ *prefix_p = onode->prefix.module_name;
+ break;
+ } else if (onode->prefix.id) {
+ *prefix_p = onode->prefix.id;
+ break;
+ }
+ node = (struct lyd_node*)node->parent;
+ }
+ *prefix_len_p = ly_strlen(module_name);
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Get schema node corresponding to the input parameters.
+ *
+ * @param[in] lydctx JSON data parser context.
+ * @param[in] is_attr Flag if the reference to the node is an attribute, for logging only.
+ * @param[in] prefix Requested node's prefix (module name).
+ * @param[in] prefix_len Length of the @p prefix.
+ * @param[in] name Requested node's name.
+ * @param[in] name_len Length of the @p name.
+ * @param[in] parent Parent of the node beeing processed, can be NULL in case of top-level. Also the opaq node with LYD_NODE_OPAQ_ISENVELOPE hint
+ * is accepted for searching top-level nodes.
+ * @param[out] snode_p Pointer to the found schema node corresponding to the input parameters.
+ * @return LY_SUCCES on success, note that even in this case the returned value of @p snode_p can be NULL, so the data are expected to be parsed as opaq.
+ * @return LY_EVALID on failure, error message is logged
+ * @return LY_ENOT in case the input data are expected to be skipped
+ */
+static LY_ERR
+lydjson_get_snode(const struct lyd_json_ctx *lydctx, int is_attr, const char *prefix, size_t prefix_len, const char *name, size_t name_len,
+ const struct lyd_node_inner *parent, const struct lysc_node **snode_p)
+{
+ struct lys_module *mod = NULL;
+
+ /* leave if-feature check for validation */
+ int getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
+
+ /* init return value */
+ *snode_p = NULL;
+
+ /* get the element module */
+ if (prefix_len || (parent && !parent->schema && (((struct lyd_node_opaq*)parent)->hint & LYD_NODE_OPAQ_ISENVELOPE))) {
+ if (!prefix_len) {
+ /* opaq parent (envelope) - the second part of the condition */
+ lydjson_get_node_prefix((struct lyd_node*)parent, NULL, 0, &prefix, &prefix_len);
+ }
+ mod = ly_ctx_get_module_implemented2(lydctx->jsonctx->ctx, prefix, prefix_len);
+ } else if (parent) {
+ if (parent->schema) {
+ mod = parent->schema->module;
+ }
+ } else {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, parent, LYVE_SYNTAX_JSON, "Top-level JSON object member \"%.*s\" must be namespace-qualified.",
+ is_attr ? name_len + 1 : name_len, is_attr ? name - 1 : name);
+ return LY_EVALID;
+ }
+ if (!mod) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, parent, LYVE_REFERENCE, "No module named \"%.*s\" in the context.", prefix_len, prefix);
+ return LY_EVALID;
+ }
+ if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
+ return LY_ENOT;
+ }
+ }
+
+ if (parent && !parent->schema && (((struct lyd_node_opaq*)parent)->hint & LYD_NODE_OPAQ_ISENVELOPE)) {
+ /* ignore the envelope parent when searchinf for the schema node */
+ parent = NULL;
+ }
+
+ /* get the schema node */
+ if (mod && (!parent || parent->schema)) {
+ *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+ if (!*snode_p) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, parent, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
+ name_len, name, mod->name);
+ return LY_EVALID;
+ } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
+ /* skip element with children */
+ return LY_ENOT;
+ }
+ } else {
+ /* check that schema node is valid and can be used */
+ LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode_p));
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Skip the currently open JSON object/array
+ * @param[in] jsonctx JSON context with the input data to skip.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydjson_data_skip(struct lyjson_ctx *jsonctx)
+{
+ enum LYJSON_PARSER_STATUS status, current;
+ size_t sublevels = 1;
+
+ status = lyjson_ctx_status(jsonctx, 0);
+
+ /* skip after the content */
+ do {
+ LY_CHECK_RET(lyjson_ctx_next(jsonctx, ¤t));
+ if (current == status) {
+ sublevels++;
+ } else if (current == status + 1) {
+ sublevels--;
+ }
+ } while (current != status + 1 && sublevels);
+ /* open the next sibling */
+ LY_CHECK_RET(lyjson_ctx_next(jsonctx, NULL));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Go through the @p value and find all possible prefixes and store them in @p val_prefs_p [sized array](@ref sizedarrays).
+ *
+ * @param[in] ctx libyang context
+ * @param[in] value Pointer to the beginning of the value to check.
+ * @param[in] value_len Length of the string to examine in @p value.
+ * @param[out] val_prefs_p Pointer to the resulting [sized array](@ref sizedarrays) of found prefixes. NULL in case there are no prefixes.
+ * @return LY_EMEM on memory allocation failure.
+ * @return LY_SUCCESS on success, empty @p val_prefs_p (NULL) is valid result if there are no possible prefixes
+ */
+static LY_ERR
+lydjson_get_value_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len, struct ly_prefix **val_prefs_p)
+{
+ LY_ERR ret;
+ LY_ARRAY_COUNT_TYPE u;
+ uint32_t c;
+ const char *start, *stop;
+ struct ly_prefix *prefixes = NULL;
+ size_t len;
+
+ for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
+ size_t bytes;
+ ly_getutf8(&stop, &c, &bytes);
+ if (is_yangidentstartchar(c)) {
+ for (ly_getutf8(&stop, &c, &bytes);
+ is_yangidentchar(c) && (size_t)(stop - value) < value_len;
+ ly_getutf8(&stop, &c, &bytes));
+ stop = stop - bytes;
+ if (*stop == ':') {
+ /* we have a possible prefix */
+ struct ly_prefix *p = NULL;
+
+ len = stop - start;
+
+ /* check whether we do not already have this prefix stored */
+ LY_ARRAY_FOR(prefixes, u) {
+ if (!ly_strncmp(prefixes[u].id, start, len)) {
+ p = &prefixes[u];
+ break;
+ }
+ }
+ if (!p) {
+ LY_ARRAY_NEW_GOTO(ctx, prefixes, p, ret, error);
+ p->id = lydict_insert(ctx, start, len);
+ p->module_name = lydict_insert(ctx, start, len);
+ } /* else the prefix already present */
+ }
+ stop = stop + bytes;
+ }
+ }
+
+ *val_prefs_p = prefixes;
+ return LY_SUCCESS;
+
+error:
+ LY_ARRAY_FOR(prefixes, u) {
+ lydict_remove(ctx, prefixes[u].id);
+ lydict_remove(ctx, prefixes[u].module_name);
+ }
+ LY_ARRAY_FREE(prefixes);
+ return ret;
+}
+
+/**
+ * @brief Check that the input data are parseable as the @p list.
+ *
+ * Checks for all the list's keys. Function does not revert the context state.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @param[in] list List schema node corresponding to the input data object.
+ * @return LY_SUCCESS in case the data are ok for the @p list
+ * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance.
+ */
+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);
+ struct ly_set key_set = {0};
+ const struct lysc_node *snode;
+ uint32_t i, status_count;
+
+ assert(list && (list->nodetype == LYS_LIST));
+ assert(status == LYJSON_OBJECT);
+
+ /* get all keys into a set (keys do not have if-features or anything) */
+ snode = NULL;
+ while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
+ ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
+ }
+
+ if (status != LYJSON_OBJECT_EMPTY) {
+ status_count = jsonctx->status.count;
+
+ while (key_set.count && status != LYJSON_OBJECT_CLOSED) {
+ const char *name, *prefix;
+ size_t name_len, prefix_len;
+ int is_attr;
+
+ /* match the key */
+ snode = NULL;
+ lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
+
+ if (!is_attr && !prefix) {
+ for (i = 0; i < key_set.count; ++i) {
+ snode = (const struct lysc_node *)key_set.objs[i];
+ if (!ly_strncmp(snode->name, name, name_len)) {
+ 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);
+
+ if (snode) {
+ /* we have the key, validate the value */
+ if (status < LYJSON_NUMBER) {
+ /* not a terminal */
+ ret = LY_ENOT;
+ goto cleanup;
+ }
+
+ ret = _lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, lydjson_resolve_prefix, jsonctx, LYD_JSON);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* key with a valid value, remove from the set */
+ ly_set_rm_index(&key_set, i, NULL);
+ }
+ } else {
+ /* start skipping the member we are not interested in */
+ ret = lyjson_ctx_next(jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ /* move to the next child */
+ while (status_count < jsonctx->status.count) {
+ ret = lyjson_ctx_next(jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ }
+ }
+
+ if (key_set.count) {
+ /* some keys are missing/did not validate */
+ ret = LY_ENOT;
+ }
+
+cleanup:
+ ly_set_erase(&key_set, NULL);
+ return ret;
+}
+
+/**
+ * @brief Get the hint for the data type parsers according to the current JSON parser context.
+ *
+ * @param[in] lydctx JSON data parser context. The context is supposed to be on a value.
+ * @param[in,out] status Pointer to the current context status,
+ * in some circumstances the function manipulates with the context so the status is updated.
+ * @param[out] type_hint_p Pointer to the variable to store the result.
+ * @return LY_SUCCESS in case of success.
+ * @return LY_EINVAL in case of invalid context status not referring to a value.
+ */
+static LY_ERR
+lydjson_value_type_hint(struct lyd_json_ctx *lydctx, enum LYJSON_PARSER_STATUS *status_p, int *type_hint_p)
+{
+ *type_hint_p = 0;
+
+ if (*status_p == LYJSON_ARRAY) {
+ /* only [null] */
+ LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
+ LY_CHECK_RET(*status_p != LYJSON_NULL, LY_EINVAL);
+
+ LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
+ LY_CHECK_RET(lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_ARRAY_CLOSED, LY_EINVAL);
+
+ *type_hint_p = LYD_NODE_OPAQ_ISEMPTY;
+ } else if (*status_p == LYJSON_STRING) {
+ *type_hint_p = LYD_NODE_OPAQ_ISSTRING;
+ } else if (*status_p == LYJSON_NUMBER) {
+ *type_hint_p = LYD_NODE_OPAQ_ISNUMBER;
+ } else if (*status_p == LYJSON_FALSE || *status_p == LYJSON_TRUE) {
+ *type_hint_p = LYD_NODE_OPAQ_ISBOOLEAN;
+ } else if (*status_p == LYJSON_NULL) {
+ *type_hint_p = 0;
+ } else {
+ return LY_EINVAL;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Check in advance if the input data are parsable according to the provided @p snode.
+ *
+ * Note that the checks are done only in case the LYD_PARSE_OPAQ is allowed. Otherwise the same checking
+ * is naturally done when the data are really parsed.
+ *
+ * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
+ * as before calling, despite it is necessary to process input data for checking.
+ * @param[in] snode Schema node corresponding to the member currently being processed in the context.
+ * @param[out] type_hint_p Pointer to a variable to store detected value type hint in case of leaf or leaf-list.
+ * @return LY_SUCCESS in case the data are ok for the @p snode or the LYD_PARSE_OPAQ is not enabled.
+ * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance
+ * @return LY_EINVAL in case of invalid leaf JSON encoding
+ * and they are expected to be parsed as opaq nodes.
+ */
+static LY_ERR
+lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, int *type_hint_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyjson_ctx *jsonctx = lydctx->jsonctx;
+ enum LYJSON_PARSER_STATUS status;
+
+ assert(snode);
+ assert(snode->nodetype & (LYD_NODE_TERM | LYS_LIST));
+
+ if ((lydctx->parse_options & LYD_PARSE_OPAQ)) {
+ /* backup parser */
+ lyjson_ctx_backup(jsonctx);
+ status = lyjson_ctx_status(jsonctx, 0);
+
+ /* check if the node is parseable. if not, NULL the snode to announce that it is supposed to be parsed as an opaq node */
+ switch (snode->nodetype) {
+ case LYS_LEAFLIST:
+ case LYS_LEAF:
+ /* value may not be valid in which case we parse it as an opaque node */
+ ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
+ if (ret) {
+ break;
+ }
+
+ if (_lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, lydjson_resolve_prefix, jsonctx, LYD_JSON)) {
+ ret = LY_ENOT;
+ }
+ break;
+ case LYS_LIST:
+ /* lists may not have all its keys */
+ if (lydjson_check_list(jsonctx, snode)) {
+ /* invalid list, parse as opaque if it missing/has invalid some keys */
+ ret = LY_ENOT;
+ }
+ }
+
+ /* restore parser */
+ lyjson_ctx_restore(jsonctx);
+ } else if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+ status = lyjson_ctx_status(jsonctx, 0);
+ ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Join the forward-referencing metadata with their target data nodes.
+ *
+ * Note that JSON encoding for YANG data allows forward-referencing metadata only for leafs/leaf-lists.
+ *
+ * @param[in] lydctx JSON data parser context.
+ * @param[in,out] first_p Pointer to the first sibling node variable (top-level or in a particular parent node)
+ * as a starting point to search for the metadata's target data node
+ * @return LY_SUCCESS on success
+ * @return LY_EVALID in case there are some metadata with unresolved target data node instance
+ */
+static LY_ERR
+lydjson_metadata_finish(struct lyd_json_ctx *lydctx, struct lyd_node **first_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_node *node, *attr, *next, *start = *first_p, *meta_iter;
+ unsigned int instance = 0;
+ const char *prev = NULL;
+
+ /* finish linking metadata */
+ LY_LIST_FOR_SAFE(*first_p, next, attr) {
+ struct lyd_node_opaq *meta_container = (struct lyd_node_opaq*)attr;
+ unsigned int match = 0;
+ int is_attr;
+ const char *name, *prefix;
+ size_t name_len, prefix_len;
+ const struct lysc_node *snode;
+
+ if (attr->schema || meta_container->name[0] != '@') {
+ /* not an opaq metadata node */
+ continue;
+ }
+
+ if (prev != meta_container->name) {
+ /* metas' names are stored in dictionary, so checking pointers must works */
+ lydict_remove(lydctx->jsonctx->ctx, prev);
+ prev = lydict_insert(lydctx->jsonctx->ctx, meta_container->name, 0);
+ instance = 1;
+ } else {
+ instance++;
+ }
+
+ /* find the correspnding data node */
+ LY_LIST_FOR(start, node) {
+ if (!node->schema) {
+ /* opaq node - we are going to put into it just a generic attribute. */
+ if (strcmp(&meta_container->name[1], ((struct lyd_node_opaq*)node)->name)) {
+ continue;
+ }
+
+ if (((struct lyd_node_opaq*)node)->hint & LYD_NODE_OPAQ_ISLIST) {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, node, LYVE_SYNTAX,
+ "Metadata container references a sibling list node %s.", ((struct lyd_node_opaq*)node)->name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* match */
+ match++;
+ if (match != instance) {
+ continue;
+ }
+
+ LY_LIST_FOR(meta_container->child, meta_iter) {
+ /* convert opaq node to a attribute of the opaq node */
+ struct lyd_node_opaq *meta = (struct lyd_node_opaq*)meta_iter;
+ struct ly_prefix *val_prefs = NULL;
+ int dynamic = 0;
+
+ /* get value prefixes */
+ LY_CHECK_GOTO(ret = lydjson_get_value_prefixes(lydctx->jsonctx->ctx, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &val_prefs), cleanup);
+
+ ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, meta->name, strlen(meta->name), meta->value, ly_strlen(meta->value),
+ &dynamic, meta->hint, LYD_JSON, val_prefs, meta->prefix.id, ly_strlen(meta->prefix.id),
+ meta->prefix.module_name, ly_strlen(meta->prefix.module_name));
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ /* done */
+ break;
+ } else {
+ /* this is the second time we are resolving the schema node, so it must succeed,
+ * but remember that snode can be still NULL */
+ lydjson_parse_name(meta_container->name, strlen(meta_container->name), &name, &name_len, &prefix, &prefix_len, &is_attr);
+ assert(is_attr);
+ ret = lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, (*first_p)->parent, &snode);
+ assert(ret == LY_SUCCESS);
+
+ if (snode != node->schema) {
+ continue;
+ }
+
+ /* match */
+ match++;
+ if (match != instance) {
+ continue;
+ }
+
+ LY_LIST_FOR(meta_container->child, meta_iter) {
+ /* convert opaq node to a metadata of the node */
+ struct lyd_node_opaq *meta = (struct lyd_node_opaq*)meta_iter;
+ struct lys_module *mod = NULL;
+ int dynamic = 0;
+
+ mod = ly_ctx_get_module_implemented(lydctx->jsonctx->ctx, meta->prefix.id);
+ if (mod) {
+ ret = lyd_parser_create_meta((struct lyd_ctx*)lydctx, node, NULL, mod,
+ meta->name, strlen(meta->name), meta->value, ly_strlen(meta->value),
+ &dynamic, meta->hint, lydjson_resolve_prefix, NULL, LYD_JSON, snode);
+ LY_CHECK_GOTO(ret, cleanup);
+ } else if (lydctx->parse_options & LYD_PARSE_STRICT) {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, node, LYVE_REFERENCE,
+ "Unknown (or not implemented) YANG module \"%s\" for metadata \"%s%s%s\".",
+ meta->prefix.id, meta->prefix.id, ly_strlen(meta->prefix.id) ? ":" : "", meta->name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
+ /* add/correct flags */
+ lyd_parse_set_data_flags(node, &lydctx->when_check, &node->meta, lydctx->parse_options);
+
+ /* done */
+ break;
+ }
+ }
+
+ if (match != instance) {
+ /* there is no corresponding data node for the metadata */
+ if (instance > 1) {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, *first_p ? (*first_p)->parent : NULL, LYVE_REFERENCE,
+ "Missing %d%s JSON data instance to be coupled with %s metadata.", instance,
+ instance == 2 ? "nd" : (instance == 3 ? "rd" : "th"), meta_container->name);
+ } else {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, *first_p ? (*first_p)->parent : NULL, LYVE_REFERENCE,
+ "Missing JSON data instance to be coupled with %s metadata.", meta_container->name);
+ }
+ ret = LY_EVALID;
+ } else {
+ /* remove the opaq attr */
+ if (attr == (*first_p)) {
+ *first_p = attr->next;
+ }
+ lyd_free_tree(attr);
+ }
+ }
+
+cleanup:
+ lydict_remove(lydctx->jsonctx->ctx, prev);
+
+ return ret;
+}
+
+/**
+ * @brief Parse a metadata member.
+ *
+ * @param[in] lydctx JSON data parser context.
+ * @param[in] snode Schema node of the metadata parent.
+ * @param[in] node Parent node in case the metadata is not forward-referencing (only LYD_NODE_TERM)
+ * so the data node does not exists. In such a case the metadata is stored in the context for the later
+ * processing by lydjson_metadata_finish().
+ * @return LY_SUCCESS on success
+ * @return Various LY_ERR values in case of failure.
+ */
+static LY_ERR
+lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node)
+{
+ LY_ERR ret = LY_SUCCESS;
+ enum LYJSON_PARSER_STATUS status;
+ const char *expected;
+ int in_parent = 0;
+ const char *name, *prefix = NULL;
+ size_t name_len, prefix_len = 0;
+ struct lys_module *mod;
+ struct lyd_meta *meta = NULL;
+ const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
+ int is_attr = 0;
+ struct lyd_node *prev = node;
+ int instance = 0;
+ uint16_t nodetype;
+
+ assert(snode || node);
+
+ nodetype = snode ? snode->nodetype : LYS_CONTAINER;
+
+ /* move to the second item in the name/X pair */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, 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) {
+ /* we are done, move after the array */
+ ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(status != LYJSON_OBJECT && status != LYJSON_NULL, representation_error);
+
+ if (!node || node->schema != prev->schema) {
+ LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, prev->parent, LYVE_REFERENCE,
+ "Missing JSON data instance no. %d of %s:%s to be coupled with metadata.",
+ instance, prev->schema->module->name, prev->schema->name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ if (status == LYJSON_NULL) {
+ /* continue with the next entry in the leaf-list array */
+ prev = node;
+ node = node->next;
+ goto next_entry;
+ }
+ break;
+ case LYS_LEAF:
+ case LYS_ANYXML:
+ expected = "@name/object";
+
+ LY_CHECK_GOTO(status != LYJSON_OBJECT && (nodetype != LYS_LEAFLIST || status != LYJSON_NULL), representation_error);
+ break;
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_ANYDATA:
+ case LYS_NOTIF:
+ case LYS_ACTION:
+ case LYS_RPC:
+ in_parent = 1;
+ expected = "@/object";
+ LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
+ break;
+ }
+
+ /* process all the members inside a single metadata object */
+ assert(status == LYJSON_OBJECT);
+
+ while (status != LYJSON_OBJECT_CLOSED) {
+ lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
+ if (!prefix) {
+ LOGVAL(ctx, LY_VLOG_LYD, (void*)node, LYVE_SYNTAX_JSON,
+ "Metadata in JSON must be namespace-qualified, missing prefix for \"%.*s\".",
+ lydctx->jsonctx->value_len, lydctx->jsonctx->value);
+ ret = LY_EVALID;
+ goto cleanup;
+ } else if (is_attr) {
+ LOGVAL(ctx, LY_VLOG_LYD, (void*)node, LYVE_SYNTAX_JSON,
+ "Invalid format of the Metadata identifier in JSON, unexpected '@' in \"%.*s\"",
+ lydctx->jsonctx->value_len, lydctx->jsonctx->value);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* get the element module */
+ mod = ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
+ if (!mod) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
+ LOGVAL(ctx, LY_VLOG_LYD, (void*)node, LYVE_REFERENCE,
+ "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
+ prefix_len, prefix, name_len, name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
+ /* skip element with children */
+ ret = lydjson_data_skip(lydctx->jsonctx);
+ LY_CHECK_GOTO(ret, cleanup);
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ /* end of the item */
+ continue;
+ }
+ }
+
+ /* get the value */
+ ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (node->schema) {
+ /* create metadata */
+ meta = NULL;
+ ret = lyd_parser_create_meta((struct lyd_ctx*)lydctx, node, &meta, mod, name, name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len,
+ &lydctx->jsonctx->dynamic, 0, lydjson_resolve_prefix, lydctx->jsonctx, LYD_JSON, snode);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* add/correct flags */
+ lyd_parse_set_data_flags(node, &lydctx->when_check, &meta, lydctx->parse_options);
+ } else {
+ /* create attribute */
+ struct ly_prefix *val_prefs = NULL;
+ const char *module_name;
+ size_t module_name_len;
+
+ lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
+
+ /* get value prefixes */
+ LY_CHECK_GOTO(ret = lydjson_get_value_prefixes(lydctx->jsonctx->ctx, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &val_prefs), cleanup);
+
+ /* attr2 is always changed to the created attribute */
+ ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len,
+ &lydctx->jsonctx->dynamic, 0, LYD_JSON, val_prefs, prefix, prefix_len, module_name, module_name_len);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ /* next member */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ if (nodetype == LYS_LEAFLIST) {
+ /* continue by processing another metadata object for the following
+ * leaf-list instance since they are allways instantiated in JSON array */
+ prev = node;
+ node = node->next;
+ goto next_entry;
+ }
+
+ /* move after the metadata */
+ ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+
+cleanup:
+ return ret;
+
+representation_error:
+ LOGVAL(ctx, LY_VLOG_LYD, (void*)node, LYVE_SYNTAX_JSON,
+ "The attribute(s) of %s \"%s\" is expected to be represented as JSON %s, but input data contains @%s/%s.",
+ lys_nodetype2str(nodetype), node->schema ? node->schema->name : ((struct lyd_node_opaq*)node)->name,
+ expected, lyjson_token2str(status), in_parent ? "" : "name");
+
+ return LY_EVALID;
+}
+
+/**
+ * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing to the first child node.
+ *
+ * @param[in] parent Parent node to insert to, can be NULL in case of top-level (or provided first_p).
+ * @param[in, out] first_p Pointer to the first sibling node in case of top-level.
+ * @param[in, out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
+ */
+static void
+lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p)
+{
+ if (*node_p) {
+ /* insert, keep first pointer correct */
+ lyd_insert_node((struct lyd_node *)parent, first_p, *node_p);
+ if (first_p) {
+ if (parent) {
+ *first_p = parent->child;
+ } else {
+ while ((*first_p)->prev->next) {
+ *first_p = (*first_p)->prev;
+ }
+ }
+ }
+ *node_p = NULL;
+ }
+}
+
+static LY_ERR lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p);
+
+/**
+ * @brief Parse opaq node from the input.
+ *
+ * In case of processing array, the whole array is being processed and the resulting @p node_p is the last item of the array.
+ *
+ * @param[in] lydctx JSON data parser context.
+ * @param[in] name Name of the opaq node to create.
+ * @param[in] name_len Length of the @p name string.
+ * @param[in] prefix Prefix of the opaq node to create.
+ * @param[in] prefix_len Length of the @p prefx string.
+ * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
+ * but must be set if @p first is not.
+ * @param[in,out] status_p Pointer to the current status of the parser context,
+ * since the function manipulates with the context and process the input, the status can be updated.
+ * @param[in,out] status_inner_p In case of processing JSON array, this parameter points to a standalone
+ * context status of the array content. Otherwise, it is supposed to be the same as @p status_p.
+ * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
+ * @param[out] node_p Pointer to the created opaq node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydjson_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len,
+ const char *prefix, size_t prefix_len, struct lyd_node_inner *parent,
+ enum LYJSON_PARSER_STATUS *status_p, enum LYJSON_PARSER_STATUS *status_inner_p,
+ struct lyd_node **first_p, struct lyd_node **node_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ const char *value = NULL, *module_name;
+ size_t value_len = 0, module_name_len = 0;
+ struct ly_prefix *val_prefs = NULL;
+ int dynamic = 0;
+ int type_hint = 0;
+
+ if (*status_inner_p != LYJSON_OBJECT && *status_inner_p != LYJSON_OBJECT_EMPTY) {
+ /* prepare for creating opaq node with a value */
+ value = lydctx->jsonctx->value;
+ value_len = lydctx->jsonctx->value_len;
+ dynamic = lydctx->jsonctx->dynamic;
+ lydctx->jsonctx->dynamic = 0;
+
+ LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
+
+ if (value) {
+ /* get value prefixes */
+ LY_CHECK_RET(lydjson_get_value_prefixes(lydctx->jsonctx->ctx, value, value_len, &val_prefs));
+ }
+ }
+
+ /* create node */
+ lydjson_get_node_prefix((struct lyd_node*)parent, prefix, prefix_len, &module_name, &module_name_len);
+ ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, value, value_len, &dynamic, type_hint,
+ LYD_JSON, val_prefs, prefix, prefix_len, module_name, module_name_len, node_p);
+ if (dynamic) {
+ free((char*)value);
+ dynamic = 0;
+ }
+ value = NULL;
+ value_len = 0;
+ val_prefs = NULL;
+ LY_CHECK_RET(ret);
+
+ if (*status_p == LYJSON_OBJECT || *status_p == LYJSON_OBJECT_EMPTY) {
+ /* process children */
+ while (*status_p != LYJSON_OBJECT_CLOSED && *status_p != LYJSON_OBJECT_EMPTY) {
+ LY_CHECK_RET(lydjson_subtree_r(lydctx, (struct lyd_node_inner *)(*node_p), lyd_node_children_p(*node_p)));
+ *status_p = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+ } else if (*status_p == LYJSON_ARRAY || *status_p == LYJSON_ARRAY_EMPTY) {
+ /* process another instance of the same node */
+ /* but first mark the node to be expected a list or a leaf-list */
+ ((struct lyd_node_opaq*)*node_p)->hint |= LYD_NODE_OPAQ_ISLIST;
+
+ if (*status_inner_p == LYJSON_OBJECT || *status_inner_p == LYJSON_OBJECT_EMPTY) {
+ /* but first process children of the object in the array */
+ while (*status_inner_p != LYJSON_OBJECT_CLOSED && *status_inner_p != LYJSON_OBJECT_EMPTY) {
+ LY_CHECK_RET(lydjson_subtree_r(lydctx, (struct lyd_node_inner *)(*node_p), lyd_node_children_p(*node_p)));
+ *status_inner_p = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+ }
+
+ LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
+
+ /* continue with the next instance */
+ if (*status_inner_p != LYJSON_ARRAY_CLOSED) {
+ assert(node_p);
+ lydjson_maintain_children(parent, first_p, node_p);
+ return lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_p, status_inner_p, first_p, node_p);
+ }
+ }
+
+ /* finish linking metadata */
+ LY_CHECK_RET(lydjson_metadata_finish(lydctx, lyd_node_children_p(*node_p)));
+
+ /* move after the item */
+ return lyjson_ctx_next(lydctx->jsonctx, status_p);
+}
+
+/**
+ * @brief Process the attribute container (starting by @)
+ *
+ * @param[in] lydctx JSON data parser context.
+ * @param[in] attr_node The data node referenced by the attribute container, if already known.
+ * @param[in] snode The schema node of the data node referenced by the attribute container, if known.
+ * @param[in] name Name of the opaq node to create.
+ * @param[in] name_len Length of the @p name string.
+ * @param[in] prefix Prefix of the opaq node to create.
+ * @param[in] prefix_len Length of the @p prefx string.
+ * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
+ * but must be set if @p first is not.
+ * @param[in,out] status_p Pointer to the current status of the parser context,
+ * since the function manipulates with the context and process the input, the status can be updated.
+ * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
+ * @param[out] node_p Pointer to the created opaq node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydjson_parse_attribute(struct lyd_json_ctx *lydctx, struct lyd_node *attr_node, const struct lysc_node *snode,
+ const char *name, size_t name_len, const char *prefix, size_t prefix_len,
+ struct lyd_node_inner *parent, enum LYJSON_PARSER_STATUS *status_p,
+ struct lyd_node **first_p, struct lyd_node **node_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ enum LYJSON_PARSER_STATUS status_inner;
+
+ /* parse as an attribute to a node */
+ if (!attr_node && snode) {
+ /* try to find the instance */
+ for (struct lyd_node *iter = *first_p; iter; iter = iter->next) {
+ if (iter->schema == snode) {
+ attr_node = iter;
+ break;
+ }
+ }
+ }
+ if (!attr_node) {
+ /* parse just as an opaq node with the name beginning with @,
+ * later we have to check that it belongs to a standard node
+ * and it is supposed to be converted to a metadata */
+ uint32_t prev_opts;
+
+ /* move into metadata */
+ LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
+
+ if (*status_p == LYJSON_ARRAY) {
+ /* move into the array */
+ LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, &status_inner));
+ } else {
+ /* just a flag to pass correct parameters into lydjson_parse_opaq() */
+ status_inner = LYJSON_ERROR;
+ }
+
+ /* backup parser options to parse unknown metadata as opaq nodes and try to resolve them later */
+ prev_opts = lydctx->parse_options;
+ lydctx->parse_options &= ~LYD_PARSE_STRICT;
+ lydctx->parse_options |= LYD_PARSE_OPAQ;
+
+ ret = lydjson_parse_opaq(lydctx, prefix ? prefix - 1 : name - 1, prefix ? prefix_len + name_len + 2 : name_len + 1,
+ NULL, 0, parent, status_p, status_inner == LYJSON_ERROR ? status_p : &status_inner, first_p, node_p);
+
+ /* restore the parser options */
+ lydctx->parse_options = prev_opts;
+ } else {
+ ret = lydjson_metadata(lydctx, snode, attr_node);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Parse JSON subtree.
+ *
+ * @param[in] lydctx JSON data parser context.
+ * @param[in] parent Data parent of the subtree, must be set if @p first is not.
+ * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ enum LYJSON_PARSER_STATUS status_inner = 0;
+ const char *name, *prefix = NULL;
+ size_t name_len, prefix_len = 0;
+ int is_attr = 0;
+ const struct lysc_node *snode, *snode_backup = NULL;
+ struct lyd_node *node = NULL, *attr_node = NULL, *anchor = NULL;
+ const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
+ const char *expected = NULL;
+ int type_hint = 0;
+ uint32_t prev_opts;
+
+ assert(parent || first_p);
+ assert(status == LYJSON_OBJECT);
+
+ /* process the node name */
+ lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
+
+ if (is_attr && !name_len && !prefix_len) {
+ /* parent's attribute without a name - skip schema node detection and get the schema from the parent */
+ if (!parent) {
+ LOGVAL(ctx, LY_VLOG_LYD, NULL, LYVE_SYNTAX_JSON, "Invalid metadata format - \"@\" can be used only inside anydata, container or list entries.");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ attr_node = (struct lyd_node*)parent;
+ snode = parent->schema;
+ goto attribute;
+ }
+
+ /* get the schema node */
+ ret = lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, parent, &snode);
+ if (ret == LY_ENOT) {
+ /* skip element with children */
+ ret = lydjson_data_skip(lydctx->jsonctx);
+ LY_CHECK_GOTO(ret, cleanup);
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ /* nothing for now, continue with another call of lydjson_subtree_r() */
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (!snode) {
+ /* parse as an opaq node */
+ assert((lydctx->parse_options & LYD_PARSE_OPAQ) || (lydctx->int_opts));
+
+ /* move to the second item in the name/X pair */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (status == LYJSON_ARRAY) {
+ /* move into the array */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status_inner);
+ LY_CHECK_GOTO(ret, cleanup);
+ } else {
+ /* just a flag to pass correct parameters into lydjson_parse_opaq() */
+ status_inner = LYJSON_ERROR;
+ }
+
+ ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len,
+ parent, &status, status_inner == LYJSON_ERROR ? &status : &status_inner, first_p, &node);
+ LY_CHECK_GOTO(ret, cleanup);
+ is_attr = 1;
+ } else if (!is_attr) {
+ /* parse as a standard lyd_node */
+
+ /* move to the second item in the name/X pair */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* first check the expected representation according to the nodetype and then continue with the content */
+ switch (snode->nodetype) {
+ case LYS_LEAFLIST:
+ expected = "name/array of values";
+
+ LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
+
+ /* move into array */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* process the value */
+ goto next_term;
+ case LYS_LEAF:
+ if (status == LYJSON_ARRAY) {
+ expected = "name/[null]";
+ } else {
+ expected = "name/value";
+ }
+
+next_term:
+ ret = lydjson_data_check_opaq(lydctx, snode, &type_hint);
+ if (ret == LY_SUCCESS) {
+ /* create terminal node */
+ ret = lyd_parser_create_term((struct lyd_ctx*)lydctx, snode, lydctx->jsonctx->value, lydctx->jsonctx->value_len,
+ &lydctx->jsonctx->dynamic, type_hint, lydjson_resolve_prefix, lydctx->jsonctx, LYD_JSON, &node);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+ } else if (ret == LY_ENOT) {
+ /* parse it again as an opaq node */
+ ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent,
+ &status, &status, first_p, &node);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (snode->nodetype == LYS_LEAFLIST) {
+ ((struct lyd_node_opaq*)node)->hint |= LYD_NODE_OPAQ_ISLIST;
+ }
+ } else if (ret == LY_EINVAL) {
+ goto representation_error;
+ } else {
+ goto cleanup;
+ }
+
+ if (snode->nodetype == LYS_LEAFLIST) {
+ /* continue with the next instance of the leaf-list */
+ if(status != LYJSON_ARRAY_CLOSED) {
+ assert(node);
+ lydjson_maintain_children(parent, first_p, &node);
+ goto next_term;
+ }
+
+ /* move after the array */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ break;
+ case LYS_LIST:
+ expected = "name/array of objects";
+
+ LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
+
+ /* move into array */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+
+next_list:
+ if (lydjson_data_check_opaq(lydctx, snode, &type_hint)) {
+ snode_backup = snode;
+ snode = NULL;
+ /* parse it again as an opaq node */
+ ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent,
+ &status, &status, first_p, &node);
+ LY_CHECK_GOTO(ret, cleanup);
+ ((struct lyd_node_opaq*)node)->hint |= LYD_NODE_OPAQ_ISLIST;
+
+ snode = snode_backup;
+ snode_backup = NULL;
+ goto list_loop;
+ }
+ /* process children - no break */
+ case LYS_CONTAINER:
+ case LYS_NOTIF:
+ case LYS_ACTION:
+ case LYS_RPC:
+ if (snode->nodetype != LYS_LIST) {
+ expected = "name/object";
+ }
+
+ LY_CHECK_GOTO(status != LYJSON_OBJECT && status != LYJSON_OBJECT_EMPTY, representation_error);
+
+ /* create inner node */
+ ret = lyd_create_inner(snode, &node);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* process children */
+ while (status != LYJSON_OBJECT_CLOSED && status != LYJSON_OBJECT_EMPTY) {
+ ret = lydjson_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
+ LY_CHECK_GOTO(ret, cleanup);
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+
+ /* finish linking metadata */
+ ret = lydjson_metadata_finish(lydctx, lyd_node_children_p(node));
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (snode->nodetype == LYS_LIST) {
+ /* check all keys exist */
+ ret = lyd_parse_check_keys(node);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
+ /* new node validation, autodelete CANNOT occur, all nodes are new */
+ ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* add any missing default children */
+ ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lydctx->unres_node_type, &lydctx->when_check,
+ (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+ if (snode->nodetype == LYS_LIST) {
+list_loop:
+ /* continue with the next instance of the list */
+ if(status != LYJSON_ARRAY_CLOSED) {
+ assert(node);
+ lydjson_maintain_children(parent, first_p, &node);
+ goto next_list;
+ }
+
+ /* move after the array */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ } else if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ /* rememeber the RPC/action/notification */
+ lydctx->op_node = node;
+ }
+
+ break;
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ expected = "name/object";
+ LY_CHECK_GOTO(status != LYJSON_OBJECT && status != LYJSON_OBJECT_EMPTY, representation_error);
+
+ /* parse any data tree with correct options */
+ /* first backup the current options and then make the parser to process data as opaq nodes */
+ prev_opts = lydctx->parse_options;
+ lydctx->parse_options &= ~LYD_PARSE_STRICT;
+ lydctx->parse_options |= LYD_PARSE_OPAQ;
+
+ /* process the anydata content */
+ while (status != LYJSON_OBJECT_CLOSED && status != LYJSON_OBJECT_EMPTY) {
+ ret = lydjson_subtree_r(lydctx, NULL, &anchor);
+ LY_CHECK_GOTO(ret, cleanup);
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+
+ /* reset parser options */
+ lydctx->parse_options = prev_opts;
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* finish linking metadata */
+ ret = lydjson_metadata_finish(lydctx, &anchor);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* create any node */
+ ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &node);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ break;
+ }
+
+ } else {
+attribute:
+ ret = lydjson_parse_attribute(lydctx, attr_node, snode, name, name_len, prefix, prefix_len, parent, &status, first_p, &node);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ lydjson_maintain_children(parent, first_p, &node);
+
+cleanup:
+ lyd_free_tree(node);
+ return ret;
+
+representation_error:
+ LOGVAL(ctx, LY_VLOG_LYD, parent, LYVE_SYNTAX_JSON,
+ "The %s \"%s\" is expected to be represented as JSON %s, but input data contains name/%s.",
+ lys_nodetype2str(snode->nodetype), snode->name, expected, lyjson_token2str(status));
+
+ ret = LY_EVALID;
+ goto cleanup;
+}
+
+/**
+ * @brief Common start of JSON parser processing different types of the input data.
+ *
+ * @param[in] ctx libyang context
+ * @param[in] in Input structure.
+ * @param[in] parse_options Options for parser, see @ref dataparseroptions.
+ * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
+ * @param[out] lydctx_p Data parser context to finish validation.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options, struct lyd_json_ctx **lydctx_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_json_ctx *lydctx;
+ size_t i, line = 1;
+
+ /* starting top-level */
+ for (i = 0; in->current[i] != '\0' && is_jsonws(in->current[i]); i++) {
+ if (in->current[i] == 0x0a) { /* new line */
+ line++;
+ };
+ }
+ if (in->current[i] == '\0') {
+ /* empty data input */
+ return LY_SUCCESS;
+ }
+ if (in->current[i] != '{') {
+ LOGVAL(ctx, LY_VLOG_LINE, &line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(&in->current[i]), &in->current[i],
+ "a top-level JSON object ('{') holding encoded YANG data");
+ return LY_EVALID;
+ }
+
+ /* init context */
+ lydctx = calloc(1, sizeof *lydctx);
+ LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
+ lydctx->parse_options = parse_options;
+ lydctx->validate_options = validate_options;
+ lydctx->free = lyd_json_ctx_free;
+ lydctx->resolve_prefix = lydjson_resolve_prefix;
+
+ LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
+
+ *lydctx_p = lydctx;
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lyd_parse_json_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options, struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_json_ctx *lydctx = NULL;
+ enum LYJSON_PARSER_STATUS status;
+
+ assert(tree_p);
+ *tree_p = NULL;
+
+ ret = lyd_parse_json_init(ctx, in, parse_options, validate_options, &lydctx);
+ LY_CHECK_GOTO(ret || !lydctx, cleanup);
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ assert(status == LYJSON_OBJECT);
+
+ /* read subtree(s) */
+ while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
+ ret = lydjson_subtree_r(lydctx, NULL, tree_p);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+
+ /* finish linking metadata */
+ ret = lydjson_metadata_finish(lydctx, tree_p);
+ LY_CHECK_GOTO(ret, cleanup);
+
+cleanup:
+ /* there should be no unresolved types stored */
+ assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count
+ && !lydctx->when_check.count));
+
+ if (ret) {
+ lyd_json_ctx_free((struct lyd_ctx *)lydctx);
+ lyd_free_all(*tree_p);
+ *tree_p = NULL;
+ } else {
+ *lydctx_p = (struct lyd_ctx *)lydctx;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Parse optional JSON envelope around the Notification data, including the eventTime data.
+ *
+ * @param[in] jsonctx JSON parser context
+ * @param[out] envp_p Pointer to the created envelope opaq container.
+ * @return LY_SUCCESS if the envelope present and successfully parsed.
+ * @return LY_ENOT in case there is not the expected envelope.
+ * @return LY_ERR in case of parsing failure.
+ */
+static LY_ERR
+lydjson_notif_envelope(struct lyjson_ctx *jsonctx, struct lyd_node **envp_p)
+{
+ LY_ERR ret = LY_ENOT, r;
+ const char *name, *prefix, *value = NULL;
+ size_t name_len, prefix_len, value_len;
+ int is_attr, dynamic = 0;
+ enum LYJSON_PARSER_STATUS status;
+ struct lyd_node *et;
+
+ *envp_p = NULL;
+
+ /* backup the context */
+ lyjson_ctx_backup(jsonctx);
+
+ /* "notification" envelope */
+ lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
+ LY_CHECK_GOTO(is_attr, cleanup);
+ LY_CHECK_GOTO(prefix_len != 13 || strncmp(prefix, "ietf-restconf", 13), cleanup);
+ LY_CHECK_GOTO(name_len != 12 || strncmp(name, "notification", name_len), cleanup);
+
+ r = lyjson_ctx_next(jsonctx, &status);
+ LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
+ LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
+
+ /* "eventTime" child */
+ lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
+ LY_CHECK_GOTO(prefix_len || is_attr, cleanup);
+ LY_CHECK_GOTO(name_len != 9 || strncmp(name, "eventTime", name_len), cleanup);
+
+ /* go for the data */
+ r = lyjson_ctx_next(jsonctx, &status);
+ LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
+ LY_CHECK_GOTO(status != LYJSON_STRING, cleanup);
+
+ value = jsonctx->value;
+ value_len = jsonctx->value_len;
+ dynamic = jsonctx->dynamic;
+ jsonctx->dynamic = 0;
+
+ r = lyjson_ctx_next(jsonctx, &status);
+ LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
+ LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
+ /* now the notificationContent is expected, which will be parsed by the caller */
+
+ /* create notification envelope */
+ ret = lyd_create_opaq(jsonctx->ctx, "notification", 12, "", 0, NULL, LYD_NODE_OPAQ_ISENVELOPE,
+ LYD_JSON, NULL, NULL, 0, "ietf-restconf", 13, envp_p);
+ LY_CHECK_GOTO(ret, cleanup);
+ /* create notification envelope */
+ ret = lyd_create_opaq(jsonctx->ctx, "eventTime", 9, value, value_len, &dynamic, LYD_NODE_OPAQ_ISSTRING,
+ LYD_JSON, NULL, NULL, 0, "ietf-restconf", 13, &et);
+ LY_CHECK_GOTO(ret, cleanup);
+ /* insert eventTime into notification */
+ lyd_insert_node(*envp_p, NULL, et);
+
+ ret = LY_SUCCESS;
+cleanup:
+ if (ret) {
+ /* restore the context */
+ lyjson_ctx_restore(jsonctx);
+ if (dynamic) {
+ free((char*)value);
+ }
+ }
+ return ret;
+}
+
+LY_ERR
+lyd_parse_json_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_json_ctx *lydctx = NULL;
+ struct lyd_node *ntf_e = NULL;
+ struct lyd_node *tree = NULL;
+ enum LYJSON_PARSER_STATUS status;
+
+ /* init */
+ ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
+ LY_CHECK_GOTO(ret || !lydctx, cleanup);
+ lydctx->int_opts = LYD_INTOPT_NOTIF;
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ assert(status == LYJSON_OBJECT);
+
+ /* parse "notification" and "eventTime", if present */
+ ret = lydjson_notif_envelope(lydctx->jsonctx, &ntf_e);
+ if (ret == LY_ENOT) {
+ ret = LY_SUCCESS;
+ } else if (ret) {
+ goto cleanup;
+ }
+
+ /* read subtree(s) */
+ while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
+ ret = lydjson_subtree_r(lydctx, NULL, &tree);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+
+ /* finish linking metadata */
+ ret = lydjson_metadata_finish(lydctx, &tree);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* make sure we have parsed some notification */
+ if (!lydctx->op_node) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ if (ntf_e) {
+ /* finish notification envelope */
+ ret = lyjson_ctx_next(lydctx->jsonctx, &status);
+ LY_CHECK_GOTO(ret, cleanup);
+ if (status == LYJSON_END) {
+ LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LY_VCODE_EOF);
+ ret = LY_EVALID;
+ goto cleanup;
+ } else if (status != LYJSON_OBJECT_CLOSED) {
+ LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LYVE_SYNTAX, "Unexpected sibling member \"%.*s\" of \"notification\".",
+ lydctx->jsonctx->value_len, lydctx->jsonctx->value);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
+
+ if (ntf_p) {
+ *ntf_p = lydctx->op_node;
+ }
+ assert(tree);
+ if (tree_p) {
+ *tree_p = tree;
+ }
+ if (ntf_e) {
+ /* connect to the notification */
+ lyd_insert_node(ntf_e, NULL, *tree_p);
+ if (tree_p) {
+ *tree_p = ntf_e;
+ }
+ }
+
+cleanup:
+ /* we have used parse_only flag */
+ assert(!lydctx || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count && !lydctx->when_check.count));
+
+ lyd_json_ctx_free((struct lyd_ctx *)lydctx);
+ if (ret) {
+ lyd_free_all(tree);
+ lyd_free_tree(ntf_e);
+ }
+ return ret;
+}
+
+/**
+ * @brief Parse optional JSON envelope around the processed content.
+ *
+ * @param[in] jsonctx JSON parser context
+ * @param[in] parent Parent node (some other envelope).
+ * @param[in] module_key Name of the module where the envelope element is expected.
+ * @param[in] object_id Name of the envelope object.
+ * @param[out] envp_p Pointer to the created envelope opaq container.
+ * @return LY_SUCCESS if the envelope present and successfully parsed.
+ * @return LY_ENOT in case there is not the expected envelope.
+ * @return LY_ERR in case of parsing failure.
+ */
+static LY_ERR
+lydjson_object_envelope(struct lyjson_ctx *jsonctx, struct lyd_node *parent, const char *module_key, const char *object_id, struct lyd_node **envp_p)
+{
+ LY_ERR ret = LY_ENOT, r;
+ const char *name, *prefix;
+ size_t name_len, prefix_len;
+ int is_attr;
+ enum LYJSON_PARSER_STATUS status;
+
+ *envp_p = NULL;
+
+ /* "id" envelope */
+ lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
+ LY_CHECK_GOTO(is_attr, cleanup);
+ LY_CHECK_GOTO(lydjson_get_node_prefix(parent, prefix, prefix_len, &prefix, &prefix_len), cleanup);
+ LY_CHECK_GOTO(prefix_len != strlen(module_key) || strncmp(prefix, module_key, prefix_len), cleanup);
+ LY_CHECK_GOTO(name_len != strlen(object_id) || strncmp(name, object_id, name_len), cleanup);
+
+ r = lyjson_ctx_next(jsonctx, &status);
+ LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
+ LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
+
+ /* create the object envelope */
+ ret = lyd_create_opaq(jsonctx->ctx, object_id, strlen(object_id), "", 0, NULL,
+ LYD_NODE_OPAQ_ISENVELOPE, LYD_JSON, NULL, NULL, 0,
+ module_key, ly_strlen(module_key), envp_p);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (parent) {
+ lyd_insert_node(parent, NULL, *envp_p);
+ }
+
+ ret = LY_SUCCESS;
+cleanup:
+ return ret;
+}
+
+static LY_ERR
+lydjson_object_envelope_close(struct lyjson_ctx *jsonctx, const char *object_id)
+{
+ enum LYJSON_PARSER_STATUS status;
+
+ LY_CHECK_RET(lyjson_ctx_next(jsonctx, &status));
+ if (status == LYJSON_END) {
+ LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LY_VCODE_EOF);
+ return LY_EVALID;
+ } else if (status != LYJSON_OBJECT_CLOSED) {
+ LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LYVE_SYNTAX, "Unexpected sibling member \"%.*s\" of \"%s\".",
+ jsonctx->value_len, jsonctx->value, object_id);
+ return LY_EVALID;
+ }
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lyd_parse_json_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_json_ctx *lydctx = NULL;
+ struct lyd_node *rpc_e = NULL, *act_e = NULL;
+ struct lyd_node *tree = NULL;
+ enum LYJSON_PARSER_STATUS status;
+
+ /* init */
+ ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
+ LY_CHECK_GOTO(ret || !lydctx, cleanup);
+ lydctx->int_opts = LYD_INTOPT_RPC;
+
+ /* process envelope(s), if present */
+
+ /* process rpc */
+ ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc", &rpc_e);
+ if (ret == LY_ENOT) {
+ ret = LY_SUCCESS;
+ goto parse_content;
+ } else if (ret) {
+ goto cleanup;
+ }
+ /* process action */
+ ret = lydjson_object_envelope(lydctx->jsonctx, rpc_e, "yang", "action", &act_e);
+ if (ret == LY_ENOT) {
+ ret = LY_SUCCESS;
+ goto parse_content;
+ } else if (ret) {
+ goto cleanup;
+ }
+
+parse_content:
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ assert(status == LYJSON_OBJECT);
+
+ /* read subtree(s) */
+ while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
+ ret = lydjson_subtree_r(lydctx, act_e ? (struct lyd_node_inner*)act_e : (struct lyd_node_inner*)rpc_e, &tree);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+
+ /* finish linking metadata */
+ ret = lydjson_metadata_finish(lydctx, &tree);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* make sure we have parsed some operation */
+ if (!lydctx->op_node) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the %s node.",
+ act_e ? "action" : (rpc_e ? "rpc" : "rpc/action"));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ if (act_e) {
+ /* finish action envelope */
+ ret = lydjson_object_envelope_close(lydctx->jsonctx, "action");
+ LY_CHECK_GOTO(ret, cleanup);
+ if (lydctx->op_node->schema->nodetype != LYS_ACTION) {
+ LOGVAL(ctx, LY_VLOG_LYD, lydctx->op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
+ lys_nodetype2str(lydctx->op_node->schema->nodetype));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
+ if (rpc_e) {
+ /* finish rpc envelope */
+ ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc");
+ LY_CHECK_GOTO(ret, cleanup);
+ if (!act_e && lydctx->op_node->schema->nodetype != LYS_RPC) {
+ LOGVAL(ctx, LY_VLOG_LYD, lydctx->op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
+ lys_nodetype2str(lydctx->op_node->schema->nodetype));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
+
+ if (op_p) {
+ *op_p = lydctx->op_node;
+ }
+ assert(tree);
+ if (tree_p) {
+ if (rpc_e) {
+ *tree_p = rpc_e;
+ } else if (act_e) {
+ *tree_p = act_e;
+ } else {
+ *tree_p = tree;
+ }
+ }
+
+cleanup:
+ /* we have used parse_only flag */
+ assert(!lydctx || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count && !lydctx->when_check.count));
+
+ lyd_json_ctx_free((struct lyd_ctx *)lydctx);
+ if (ret) {
+ lyd_free_all(tree);
+ lyd_free_tree(act_e);
+ lyd_free_tree(rpc_e);
+ }
+ return ret;
+}
+
+LY_ERR
+lyd_parse_json_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_json_ctx *lydctx = NULL;
+ struct lyd_node *rpcr_e = NULL, *iter, *req_op, *rep_op = NULL;
+ enum LYJSON_PARSER_STATUS status;
+
+ /* init */
+ ret = lyd_parse_json_init(LYD_NODE_CTX(request), in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
+ LY_CHECK_GOTO(ret || !lydctx, cleanup);
+ lydctx->int_opts = LYD_INTOPT_REPLY;
+
+ /* find request OP */
+ LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
+ if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
+ break;
+ }
+ LYD_TREE_DFS_END(request, req_op);
+ }
+ if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
+ LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
+ ret = LY_EINVAL;
+ goto cleanup;
+ }
+
+ /* duplicate request OP with parents */
+ LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
+
+ /* parse "rpc-reply", if any */
+ ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc-reply", &rpcr_e);
+ if (ret == LY_ENOT) {
+ ret = LY_SUCCESS;
+ } else if (ret) {
+ goto cleanup;
+ }
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ assert(status == LYJSON_OBJECT);
+
+ /* read subtree(s) */
+ while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
+ ret = lydjson_subtree_r(lydctx, (struct lyd_node_inner*)rep_op, lyd_node_children_p(rep_op));
+ LY_CHECK_GOTO(ret, cleanup);
+
+ status = lyjson_ctx_status(lydctx->jsonctx, 0);
+ }
+
+ /* finish linking metadata */
+ ret = lydjson_metadata_finish(lydctx, lyd_node_children_p(rep_op));
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (rpcr_e) {
+ /* finish rpc-reply envelope */
+ ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc-reply");
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ if (op_p) {
+ *op_p = rep_op;
+ }
+ for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
+ if (tree_p) {
+ *tree_p = iter;
+ }
+ if (rpcr_e) {
+ /* connect to the operation */
+ lyd_insert_node(rpcr_e, NULL, iter);
+ if (tree_p) {
+ *tree_p = rpcr_e;
+ }
+ }
+
+cleanup:
+ /* we have used parse_only flag */
+ assert(!lydctx || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count && !lydctx->when_check.count));
+
+ lyd_json_ctx_free((struct lyd_ctx *)lydctx);
+ if (ret) {
+ lyd_free_all(rep_op);
+ lyd_free_tree(rpcr_e);
+ }
+ return ret;
}
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index fc74236..3c8fa76 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -33,6 +33,32 @@
#include "tree_schema.h"
#include "validation.h"
+void
+lylyb_ctx_free(struct lylyb_ctx *ctx)
+{
+ LY_ARRAY_COUNT_TYPE u;
+
+ LY_ARRAY_FREE(ctx->subtrees);
+ LY_ARRAY_FREE(ctx->models);
+
+ LY_ARRAY_FOR(ctx->sib_hts, u) {
+ lyht_free(ctx->sib_hts[u].ht);
+ }
+ LY_ARRAY_FREE(ctx->sib_hts);
+
+ free(ctx);
+}
+
+void
+lyd_lyb_ctx_free(struct lyd_ctx *lydctx)
+{
+ struct lyd_lyb_ctx *ctx = (struct lyd_lyb_ctx *)lydctx;
+
+ lyd_ctx_free(lydctx);
+ lylyb_ctx_free(ctx->lybctx);
+ free(ctx);
+}
+
/**
* @brief Read YANG data from LYB input. Metadata are handled transparently and not returned.
*
@@ -41,7 +67,7 @@
* @param[in] lybctx LYB context.
*/
static void
-lyb_read(uint8_t *buf, size_t count, struct lyd_lyb_ctx *lybctx)
+lyb_read(uint8_t *buf, size_t count, struct lylyb_ctx *lybctx)
{
LY_ARRAY_COUNT_TYPE u;
struct lyd_lyb_subtree *empty;
@@ -109,7 +135,7 @@
* @param[in] lybctx LYB context.
*/
static void
-lyb_read_number(void *num, size_t num_size, size_t bytes, struct lyd_lyb_ctx *lybctx)
+lyb_read_number(void *num, size_t num_size, size_t bytes, struct lylyb_ctx *lybctx)
{
uint64_t buf = 0;
@@ -145,7 +171,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_read_string(char **str, int with_length, struct lyd_lyb_ctx *lybctx)
+lyb_read_string(char **str, int with_length, struct lylyb_ctx *lybctx)
{
int next_chunk = 0;
size_t len = 0, cur_len;
@@ -194,7 +220,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_read_stop_subtree(struct lyd_lyb_ctx *lybctx)
+lyb_read_stop_subtree(struct lylyb_ctx *lybctx)
{
if (LYB_LAST_SUBTREE(lybctx).written) {
LOGINT_RET(lybctx->ctx);
@@ -211,7 +237,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_read_start_subtree(struct lyd_lyb_ctx *lybctx)
+lyb_read_start_subtree(struct lylyb_ctx *lybctx)
{
uint8_t meta_buf[LYB_META_BYTES];
LY_ARRAY_COUNT_TYPE u;
@@ -245,7 +271,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_model(struct lyd_lyb_ctx *lybctx, const struct lys_module **mod)
+lyb_parse_model(struct lylyb_ctx *lybctx, uint32_t parse_options, const struct lys_module **mod)
{
LY_ERR ret = LY_SUCCESS;
char *mod_name = NULL, mod_rev[11];
@@ -267,7 +293,7 @@
if (rev) {
sprintf(mod_rev, "%04u-%02u-%02u", ((rev & 0xFE00) >> 9) + 2000, (rev & 0x01E0) >> 5, rev & 0x001Fu);
*mod = ly_ctx_get_module(lybctx->ctx, mod_name, mod_rev);
- if ((lybctx->parse_options & LYD_PARSE_LYB_MOD_UPDATE) && !(*mod)) {
+ if ((parse_options & LYD_PARSE_LYB_MOD_UPDATE) && !(*mod)) {
/* try to use an updated module */
*mod = ly_ctx_get_module_implemented(lybctx->ctx, mod_name);
if (*mod && (!(*mod)->revision || (strcmp((*mod)->revision, mod_rev) < 0))) {
@@ -288,7 +314,7 @@
}*/
if (!*mod || !(*mod)->implemented) {
- if (lybctx->parse_options & LYD_PARSE_STRICT) {
+ if (parse_options & LYD_PARSE_STRICT) {
if (!*mod) {
LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, missing module \"%s%s%s\".",
mod_name, rev ? "@" : "", rev ? mod_rev : "");
@@ -325,37 +351,37 @@
const struct lys_module *mod;
/* read number of attributes stored */
- lyb_read(&count, 1, lybctx);
+ lyb_read(&count, 1, lybctx->lybctx);
/* read attributes */
for (i = 0; i < count; ++i) {
- ret = lyb_read_start_subtree(lybctx);
+ ret = lyb_read_start_subtree(lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* find model */
- ret = lyb_parse_model(lybctx, &mod);
+ ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_options, &mod);
LY_CHECK_GOTO(ret, cleanup);
if (!mod) {
/* skip it */
do {
- lyb_read(NULL, LYB_LAST_SUBTREE(lybctx).written, lybctx);
- } while (LYB_LAST_SUBTREE(lybctx).written);
+ lyb_read(NULL, LYB_LAST_SUBTREE(lybctx->lybctx).written, lybctx->lybctx);
+ } while (LYB_LAST_SUBTREE(lybctx->lybctx).written);
goto stop_subtree;
}
/* meta name */
- ret = lyb_read_string(&meta_name, 1, lybctx);
+ ret = lyb_read_string(&meta_name, 1, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* meta value */
- ret = lyb_read_string(&meta_value, 0, lybctx);
+ ret = lyb_read_string(&meta_value, 0, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
dynamic = 1;
/* create metadata */
- ret = lyd_create_meta(NULL, meta, mod, meta_name, strlen(meta_name), meta_value, strlen(meta_value), &dynamic,
- lydjson_resolve_prefix, NULL, LYD_JSON, sparent);
+ ret = lyd_parser_create_meta((struct lyd_ctx*)lybctx, NULL, meta, mod, meta_name, strlen(meta_name), meta_value, ly_strlen(meta_value),
+ &dynamic, 0, lydjson_resolve_prefix, NULL, LYD_JSON, sparent);
/* free strings */
free(meta_name);
@@ -365,14 +391,10 @@
dynamic = 0;
}
- if (ret == LY_EINCOMPLETE) {
- ly_set_add(&lybctx->unres_meta_type, *meta, LY_SET_OPT_USEASLIST);
- } else if (ret) {
- goto cleanup;
- }
+ LY_CHECK_GOTO(ret, cleanup);
stop_subtree:
- ret = lyb_read_stop_subtree(lybctx);
+ ret = lyb_read_stop_subtree(lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -393,7 +415,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_opaq_prefixes(struct lyd_lyb_ctx *lybctx, struct ly_prefix **prefs)
+lyb_parse_opaq_prefixes(struct lylyb_ctx *lybctx, struct ly_prefix **prefs)
{
LY_ERR ret = LY_SUCCESS;
uint8_t count, i;
@@ -412,12 +434,12 @@
/* prefix */
ret = lyb_read_string(&str, 1, lybctx);
LY_CHECK_GOTO(ret, cleanup);
- (*prefs)[i].pref = lydict_insert_zc(lybctx->ctx, str);
+ (*prefs)[i].id = lydict_insert_zc(lybctx->ctx, str);
- /* namespace */
+ /* module reference is the same as JSON name */
ret = lyb_read_string(&str, 1, lybctx);
LY_CHECK_GOTO(ret, cleanup);
- (*prefs)[i].ns = lydict_insert_zc(lybctx->ctx, str);
+ (*prefs)[i].module_name = lydict_insert_zc(lybctx->ctx, str);
}
cleanup:
@@ -436,12 +458,12 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_attributes(struct lyd_lyb_ctx *lybctx, struct ly_attr **attr)
+lyb_parse_attributes(struct lylyb_ctx *lybctx, struct lyd_attr **attr)
{
LY_ERR ret = LY_SUCCESS;
uint8_t count, i;
- struct ly_attr *attr2;
- char *prefix = NULL, *ns = NULL, *name = NULL, *value = NULL;
+ struct lyd_attr *attr2;
+ char *prefix = NULL, *module_name = NULL, *name = NULL, *value = NULL;
int dynamic = 0;
LYD_FORMAT format = 0;
struct ly_prefix *val_prefs = NULL;
@@ -463,11 +485,11 @@
}
/* namespace, may be empty */
- ret = lyb_read_string(&ns, 1, lybctx);
+ ret = lyb_read_string(&module_name, 1, lybctx);
LY_CHECK_GOTO(ret, cleanup);
- if (!ns[0]) {
- free(ns);
- ns = NULL;
+ if (!module_name[0]) {
+ free(module_name);
+ module_name = NULL;
}
/* name */
@@ -487,14 +509,14 @@
dynamic = 1;
/* attr2 is always changed to the created attribute */
- ret = ly_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format,
- val_prefs, prefix, prefix ? strlen(prefix) : 0, ns);
+ ret = lyd_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), value, ly_strlen(value), &dynamic, 0, format,
+ val_prefs, prefix, ly_strlen(prefix), module_name, ly_strlen(module_name));
LY_CHECK_GOTO(ret, cleanup);
free(prefix);
prefix = NULL;
- free(ns);
- ns = NULL;
+ free(module_name);
+ module_name = NULL;
free(name);
name = NULL;
val_prefs = NULL;
@@ -511,7 +533,7 @@
cleanup:
free(prefix);
- free(ns);
+ free(module_name);
free(name);
if (dynamic) {
free(value);
@@ -551,54 +573,6 @@
}
/**
- * @brief Check that a schema node is suitable based on options.
- *
- * @param[in] lybctx LYB context.
- * @param[in] snode Schema node to check.
- * @return LY_ERR value.
- */
-static LY_ERR
-lyb_parse_check_schema(struct lyd_lyb_ctx *lybctx, const struct lysc_node *snode)
-{
- LY_ERR ret = LY_SUCCESS;
-
- if ((lybctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
- LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LY_VCODE_INNODE, "state", snode->name);
- return LY_EVALID;
- }
-
- if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
- if (lybctx->int_opts & LYD_INTOPT_RPC) {
- if (lybctx->op_ntf) {
- LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
- lys_nodetype2str(snode->nodetype), snode->name,
- lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
- return LY_EVALID;
- }
- } else {
- LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
- lys_nodetype2str(snode->nodetype), snode->name);
- return LY_EVALID;
- }
- } else if (snode->nodetype == LYS_NOTIF) {
- if (lybctx->int_opts & LYD_INTOPT_NOTIF) {
- if (lybctx->op_ntf) {
- LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
- lys_nodetype2str(snode->nodetype), snode->name,
- lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
- return LY_EVALID;
- }
- } else {
- LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
- lys_nodetype2str(snode->nodetype), snode->name);
- return LY_EVALID;
- }
- }
-
- return ret;
-}
-
-/**
* @brief Parse schema node hash.
*
* @param[in] lybctx LYB context.
@@ -622,7 +596,7 @@
getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lybctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
/* read the first hash */
- lyb_read(&hash[0], sizeof *hash, lybctx);
+ lyb_read(&hash[0], sizeof *hash, lybctx->lybctx);
if (!hash[0]) {
/* opaque node */
@@ -632,7 +606,7 @@
/* based on the first hash read all the other ones, if any */
for (i = 0; !(hash[0] & (LYB_HASH_COLLISION_ID >> i)); ++i) {
if (i > LYB_HASH_BITS) {
- LOGINT_RET(lybctx->ctx);
+ LOGINT_RET(lybctx->lybctx->ctx);
}
}
@@ -641,7 +615,7 @@
/* read the rest of hashes */
for (j = i; j; --j) {
- lyb_read(&hash[j - 1], sizeof *hash, lybctx);
+ lyb_read(&hash[j - 1], sizeof *hash, lybctx->lybctx);
/* correct collision ID */
assert(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)));
@@ -653,7 +627,7 @@
sibling = NULL;
while ((sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts))) {
/* skip schema nodes from models not present during printing */
- if (lyb_has_schema_model(sibling, lybctx->models)
+ if (lyb_has_schema_model(sibling, lybctx->lybctx->models)
&& lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, i + 1)) {
/* match found */
break;
@@ -662,14 +636,14 @@
if (!sibling && (lybctx->parse_options & LYD_PARSE_STRICT)) {
if (mod) {
- LOGVAL(lybctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
+ LOGVAL(lybctx->lybctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
" from \"%s\".", mod->name);
} else {
- LOGVAL(lybctx->ctx, LY_VLOG_LYSC, sparent, LYVE_REFERENCE, "Failed to find matching hash for a child node"
+ LOGVAL(lybctx->lybctx->ctx, LY_VLOG_LYSC, sparent, LYVE_REFERENCE, "Failed to find matching hash for a child node"
" of \"%s\".", sparent->name);
}
return LY_EVALID;
- } else if (sibling && (ret = lyb_parse_check_schema(lybctx, sibling))) {
+ } else if (sibling && (ret = lyd_parser_check_schema((struct lyd_ctx *)lybctx, sibling))) {
return ret;
}
@@ -683,7 +657,7 @@
* @param[in] lybctx LYB context.
*/
static void
-lyb_skip_subtree(struct lyd_lyb_ctx *lybctx)
+lyb_skip_subtree(struct lylyb_ctx *lybctx)
{
do {
/* first skip any meta information inside */
@@ -710,20 +684,21 @@
const struct lys_module *mod;
const struct lysc_node *snode = NULL;
struct lyd_meta *meta = NULL, *m;
- struct ly_attr *attr = NULL, *a;
+ struct lyd_attr *attr = NULL, *a;
struct ly_prefix *val_prefs = NULL;
LYD_ANYDATA_VALUETYPE value_type;
- char *value = NULL, *name = NULL, *prefix = NULL, *ns = NULL;
+ char *value = NULL, *name = NULL, *prefix = NULL, *module_key = NULL;
int dynamic = 0;
LYD_FORMAT format = 0;
int prev_lo;
+ const struct ly_ctx *ctx = lybctx->lybctx->ctx;
/* register a new subtree */
- LY_CHECK_GOTO(ret = lyb_read_start_subtree(lybctx), cleanup);
+ LY_CHECK_GOTO(ret = lyb_read_start_subtree(lybctx->lybctx), cleanup);
if (!parent) {
/* top-level, read module name */
- ret = lyb_parse_model(lybctx, &mod);
+ ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_options, &mod);
LY_CHECK_GOTO(ret, cleanup);
/* read hash, find the schema node starting from mod */
@@ -737,7 +712,7 @@
if (!snode && !(lybctx->parse_options & LYD_PARSE_OPAQ)) {
/* unknown data, skip them */
- lyb_skip_subtree(lybctx);
+ lyb_skip_subtree(lybctx->lybctx);
goto stop_subtree;
}
@@ -746,73 +721,67 @@
ret = lyb_parse_metadata(lybctx, snode, &meta);
LY_CHECK_GOTO(ret, cleanup);
} else {
- ret = lyb_parse_attributes(lybctx, &attr);
+ ret = lyb_parse_attributes(lybctx->lybctx, &attr);
LY_CHECK_GOTO(ret, cleanup);
}
if (!snode) {
/* parse prefix */
- ret = lyb_read_string(&prefix, 1, lybctx);
+ ret = lyb_read_string(&prefix, 1, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
- /* parse namespace */
- ret = lyb_read_string(&ns, 1, lybctx);
+ /* parse module key */
+ ret = lyb_read_string(&module_key, 1, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* parse name */
- ret = lyb_read_string(&name, 1, lybctx);
+ ret = lyb_read_string(&name, 1, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* parse value prefixes */
- ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
+ ret = lyb_parse_opaq_prefixes(lybctx->lybctx, &val_prefs);
LY_CHECK_GOTO(ret, cleanup);
/* parse format */
- lyb_read((uint8_t *)&format, 1, lybctx);
+ lyb_read((uint8_t *)&format, 1, lybctx->lybctx);
/* parse value */
- ret = lyb_read_string(&value, 0, lybctx);
+ ret = lyb_read_string(&value, 0, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
dynamic = 1;
/* create node */
- ret = lyd_create_opaq(lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format, val_prefs, prefix,
- strlen(prefix), ns, &node);
+ ret = lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), &dynamic, 0, format, val_prefs, prefix,
+ ly_strlen(prefix), module_key, ly_strlen(module_key), &node);
LY_CHECK_GOTO(ret, cleanup);
/* process children */
- while (LYB_LAST_SUBTREE(lybctx).written) {
+ while (LYB_LAST_SUBTREE(lybctx->lybctx).written) {
ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
} else if (snode->nodetype & LYD_NODE_TERM) {
/* parse value */
- ret = lyb_read_string(&value, 0, lybctx);
+ ret = lyb_read_string(&value, 0, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
dynamic = 1;
/* create node */
- ret = lyd_create_term(snode, value, strlen(value), &dynamic, lydjson_resolve_prefix, NULL, LYD_JSON, &node);
+ ret = lyd_parser_create_term((struct lyd_ctx*)lybctx, snode, value, ly_strlen(value), &dynamic, 0,
+ lydjson_resolve_prefix, NULL, LYD_JSON, &node);
if (dynamic) {
free(value);
dynamic = 0;
}
value = NULL;
- if (ret == LY_EINCOMPLETE) {
- if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
- ly_set_add(&lybctx->unres_node_type, node, LY_SET_OPT_USEASLIST);
- }
- ret = LY_SUCCESS;
- } else if (ret) {
- goto cleanup;
- }
+ LY_CHECK_GOTO(ret, cleanup);
} else if (snode->nodetype & LYD_NODE_INNER) {
/* create node */
ret = lyd_create_inner(snode, &node);
LY_CHECK_GOTO(ret, cleanup);
/* process children */
- while (LYB_LAST_SUBTREE(lybctx).written) {
+ while (LYB_LAST_SUBTREE(lybctx->lybctx).written) {
ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -831,19 +800,19 @@
if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
/* rememeber the RPC/action/notification */
- lybctx->op_ntf = node;
+ lybctx->op_node = node;
}
} else if (snode->nodetype & LYD_NODE_ANY) {
/* parse value type */
- lyb_read((uint8_t *)&value_type, sizeof value_type, lybctx);
+ lyb_read((uint8_t *)&value_type, sizeof value_type, lybctx->lybctx);
if (value_type == LYD_ANYDATA_DATATREE) {
/* invalid situation */
- LOGINT(lybctx->ctx);
+ LOGINT(ctx);
goto cleanup;
}
/* read anydata content */
- ret = lyb_read_string(&value, 0, lybctx);
+ ret = lyb_read_string(&value, 0, lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
dynamic = 1;
@@ -852,7 +821,7 @@
prev_lo = ly_log_options(0);
/* try to parse LYB into a data tree */
- if (lyd_parse_data_mem((struct ly_ctx *)lybctx->ctx, value, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
+ if (lyd_parse_data_mem(ctx, value, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
/* successfully parsed */
free(value);
value = (char *)tree;
@@ -902,20 +871,20 @@
stop_subtree:
/* end the subtree */
- ret = lyb_read_stop_subtree(lybctx);
+ ret = lyb_read_stop_subtree(lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
cleanup:
free(prefix);
- free(ns);
+ free(module_key);
free(name);
if (dynamic) {
free(value);
}
- ly_free_val_prefs(lybctx->ctx, val_prefs);
+ ly_free_val_prefs(ctx, val_prefs);
lyd_free_meta_siblings(meta);
- ly_free_attr_siblings(lybctx->ctx, attr);
+ ly_free_attr_siblings(ctx, attr);
lyd_free_tree(node);
return ret;
}
@@ -927,7 +896,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_data_models(struct lyd_lyb_ctx *lybctx)
+lyb_parse_data_models(struct lylyb_ctx *lybctx, uint32_t parse_options)
{
LY_ERR ret;
uint32_t count;
@@ -941,7 +910,7 @@
/* read modules */
for (u = 0; u < count; ++u) {
- ret = lyb_parse_model(lybctx, &lybctx->models[u]);
+ ret = lyb_parse_model(lybctx, parse_options, &lybctx->models[u]);
LY_CHECK_RET(ret);
LY_ARRAY_INCREMENT(lybctx->models);
}
@@ -957,7 +926,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_magic_number(struct lyd_lyb_ctx *lybctx)
+lyb_parse_magic_number(struct lylyb_ctx *lybctx)
{
char magic_byte = 0;
@@ -989,7 +958,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_header(struct lyd_lyb_ctx *lybctx)
+lyb_parse_header(struct lylyb_ctx *lybctx)
{
uint8_t byte = 0;
@@ -1005,198 +974,139 @@
return LY_SUCCESS;
}
-LY_ERR
-lyd_parse_lyb_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
- struct lyd_node **tree)
+/*
+ * @param[in] ctx libyang context for logging
+ * @param[in] parent Parent node where to connect the parsed data, required for reply where the reply data are connected with the request operation
+ * @param[in] in Input structure.
+ * @param[in] parse_options Options for parser, see @ref dataparseroptions.
+ * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
+ * @param[in] data_type Internal data parser flag to distnguish type of the data to parse (RPC/Reply/Notification/regular data].
+ * @param[out] tree_p Parsed data tree. Note that NULL can be a valid result.
+ * @param[out] op_p Optional pointer to the actual operation. Useful for action and inner notifications.
+ * @param[out] lydctx_p Data parser context to finish validation.
+ */
+static LY_ERR
+lyd_parse_lyb_(const struct ly_ctx *ctx, struct lyd_node_inner **parent, struct ly_in *in, int parse_options, int validate_options,
+ int data_type, struct lyd_node **tree_p, struct lyd_node **op_p, struct lyd_ctx **lydctx_p)
{
LY_ERR ret = LY_SUCCESS;
- struct lyd_lyb_ctx lybctx = {0};
+ struct lyd_lyb_ctx *lybctx;
+ struct lyd_node *tree = NULL;
assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
- *tree = NULL;
+ lybctx = calloc(1, sizeof *lybctx);
+ LY_CHECK_ERR_RET(!lybctx, LOGMEM(ctx), LY_EMEM);
+ lybctx->lybctx = calloc(1, sizeof *lybctx->lybctx);
+ LY_CHECK_ERR_RET(!lybctx->lybctx, LOGMEM(ctx), LY_EMEM);
- lybctx.in = in;
- lybctx.ctx = ctx;
- lybctx.parse_options = parse_options;
- lybctx.validate_options = validate_options;
+ lybctx->lybctx->in = in;
+ lybctx->lybctx->ctx = ctx;
+ lybctx->parse_options = parse_options;
+ lybctx->validate_options = validate_options;
+ lybctx->int_opts = data_type;
+ lybctx->free = lyd_lyb_ctx_free;
/* read magic number */
- ret = lyb_parse_magic_number(&lybctx);
+ ret = lyb_parse_magic_number(lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* read header */
- ret = lyb_parse_header(&lybctx);
+ ret = lyb_parse_header(lybctx->lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* read used models */
- ret = lyb_parse_data_models(&lybctx);
+ ret = lyb_parse_data_models(lybctx->lybctx, lybctx->parse_options);
LY_CHECK_GOTO(ret, cleanup);
/* read subtree(s) */
- while (lybctx.in->current[0]) {
- ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
+ while (lybctx->lybctx->in->current[0]) {
+ ret = lyb_parse_subtree_r(lybctx, parent ? *parent : NULL, &tree);
LY_CHECK_GOTO(ret, cleanup);
}
/* read the last zero, parsing finished */
- ly_in_skip(lybctx.in, 1);
+ ly_in_skip(lybctx->lybctx->in, 1);
- /* TODO validation */
+ if (data_type == LYD_INTOPT_RPC) {
+ /* make sure we have parsed some operation */
+ if (!lybctx->op_node) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ if (op_p) {
+ *op_p = lybctx->op_node;
+ }
+ assert(tree);
+ } else if (data_type == LYD_INTOPT_REPLY) {
+ struct lyd_node_inner *iter;
+
+ assert(parent);
+
+ if (op_p) {
+ *op_p = (struct lyd_node*)(*parent);
+ }
+ for (iter = *parent; iter->parent; iter = iter->parent);
+ tree = (struct lyd_node *)iter;
+ *parent = NULL;
+
+ } else if (data_type == LYD_INTOPT_NOTIF) {
+ /* make sure we have parsed some notification */
+ if (!lybctx->op_node) {
+ LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ if (op_p) {
+ *op_p = lybctx->op_node;
+ }
+ assert(tree);
+ }
cleanup:
- LY_ARRAY_FREE(lybctx.subtrees);
- LY_ARRAY_FREE(lybctx.models);
- ly_set_erase(&lybctx.unres_node_type, NULL);
- ly_set_erase(&lybctx.unres_meta_type, NULL);
- ly_set_erase(&lybctx.when_check, NULL);
-
- if (ret) {
- lyd_free_all(*tree);
- *tree = NULL;
+ if (ret || !lydctx_p) {
+ lyd_lyb_ctx_free((struct lyd_ctx *)lybctx);
+ if (ret) {
+ lyd_free_all(tree);
+ }
+ } else {
+ *lydctx_p = (struct lyd_ctx *)lybctx;
+ if (tree_p) {
+ *tree_p = tree;
+ }
}
return ret;
}
LY_ERR
-lyd_parse_lyb_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
+lyd_parse_lyb_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
+ struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
{
- LY_ERR ret = LY_SUCCESS;
- struct lyd_lyb_ctx lybctx = {0};
-
- lybctx.in = in;
- lybctx.ctx = ctx;
- lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
- lybctx.int_opts = LYD_INTOPT_RPC;
-
- *tree = NULL;
- if (op) {
- *op = NULL;
- }
-
- /* read magic number */
- ret = lyb_parse_magic_number(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read header */
- ret = lyb_parse_header(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read used models */
- ret = lyb_parse_data_models(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read subtree(s) */
- while (lybctx.in->current[0]) {
- ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* read the last zero, parsing finished */
- ly_in_skip(lybctx.in, 1);
-
- /* make sure we have parsed some operation */
- if (!lybctx.op_ntf) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
- ret = LY_EVALID;
- goto cleanup;
- }
-
- if (op) {
- *op = lybctx.op_ntf;
- }
- assert(*tree);
-
-cleanup:
- LY_ARRAY_FREE(lybctx.subtrees);
- LY_ARRAY_FREE(lybctx.models);
- assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
-
- if (ret) {
- lyd_free_all(*tree);
- *tree = NULL;
- }
- return ret;
+ return lyd_parse_lyb_(ctx, NULL, in, parse_options, validate_options, 0, tree_p, NULL, lydctx_p);
}
LY_ERR
-lyd_parse_lyb_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **ntf)
+lyd_parse_lyb_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
{
- LY_ERR ret = LY_SUCCESS;
- struct lyd_lyb_ctx lybctx = {0};
-
- lybctx.in = in;
- lybctx.ctx = ctx;
- lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
- lybctx.int_opts = LYD_INTOPT_NOTIF;
-
- *tree = NULL;
- if (ntf) {
- *ntf = NULL;
- }
-
- /* read magic number */
- ret = lyb_parse_magic_number(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read header */
- ret = lyb_parse_header(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read used models */
- ret = lyb_parse_data_models(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read subtree(s) */
- while (lybctx.in->current[0]) {
- ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* read the last zero, parsing finished */
- ly_in_skip(lybctx.in, 1);
-
- /* make sure we have parsed some notification */
- if (!lybctx.op_ntf) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
- ret = LY_EVALID;
- goto cleanup;
- }
-
- if (ntf) {
- *ntf = lybctx.op_ntf;
- }
- assert(*tree);
-
-cleanup:
- LY_ARRAY_FREE(lybctx.subtrees);
- LY_ARRAY_FREE(lybctx.models);
- assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
-
- if (ret) {
- lyd_free_all(*tree);
- *tree = NULL;
- }
- return ret;
+ return lyd_parse_lyb_(ctx, NULL, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LYD_INTOPT_RPC, tree_p, op_p, NULL);
}
LY_ERR
-lyd_parse_lyb_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
+lyd_parse_lyb_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
{
- LY_ERR ret = LY_SUCCESS;
- struct lyd_lyb_ctx lybctx = {0};
- struct lyd_node *iter, *req_op, *rep_op = NULL;
+ return lyd_parse_lyb_(ctx, NULL, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LYD_INTOPT_NOTIF, tree_p, ntf_p, NULL);
+}
- lybctx.in = in;
- lybctx.ctx = LYD_NODE_CTX(request);
- lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
- lybctx.int_opts = LYD_INTOPT_REPLY;
-
- *tree = NULL;
- if (op) {
- *op = NULL;
- }
+LY_ERR
+lyd_parse_lyb_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
+{
+ LY_ERR ret;
+ struct lyd_node *req_op, *rep_op = NULL;
+ const struct ly_ctx *ctx = LYD_NODE_CTX(request);
/* find request OP */
LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
@@ -1207,52 +1117,16 @@
}
if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
- ret = LY_EINVAL;
- goto cleanup;
+ return LY_EINVAL;
}
/* duplicate request OP with parents */
- ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_RET(lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op));
- /* read magic number */
- ret = lyb_parse_magic_number(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
+ ret = lyd_parse_lyb_(ctx, (struct lyd_node_inner **)&rep_op, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LYD_INTOPT_REPLY, tree_p, op_p, NULL);
- /* read header */
- ret = lyb_parse_header(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read used models */
- ret = lyb_parse_data_models(&lybctx);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* read subtree(s) */
- while (lybctx.in->current[0]) {
- ret = lyb_parse_subtree_r(&lybctx, (struct lyd_node_inner *)rep_op, NULL);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* read the last zero, parsing finished */
- ly_in_skip(lybctx.in, 1);
-
- if (op) {
- *op = rep_op;
- }
- for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
- *tree = iter;
- rep_op = NULL;
-
-cleanup:
lyd_free_all(rep_op);
- LY_ARRAY_FREE(lybctx.subtrees);
- LY_ARRAY_FREE(lybctx.models);
- assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
- if (ret) {
- lyd_free_all(*tree);
- *tree = NULL;
- }
return ret;
}
@@ -1260,7 +1134,7 @@
lyd_lyb_data_length(const char *data)
{
LY_ERR ret = LY_SUCCESS;
- struct lyd_lyb_ctx lybctx = {0};
+ struct lylyb_ctx *lybctx;
int count, i;
size_t len;
uint8_t buf[LYB_SIZE_MAX];
@@ -1269,53 +1143,56 @@
return -1;
}
- ret = ly_in_new_memory(data, &lybctx.in);
+ lybctx = calloc(1, sizeof *lybctx);
+ LY_CHECK_ERR_RET(!lybctx, LOGMEM(NULL), LY_EMEM);
+ ret = ly_in_new_memory(data, &lybctx->in);
LY_CHECK_GOTO(ret, cleanup);
/* read magic number */
- ret = lyb_parse_magic_number(&lybctx);
+ ret = lyb_parse_magic_number(lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* read header */
- ret = lyb_parse_header(&lybctx);
+ ret = lyb_parse_header(lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* read model count */
- lyb_read_number(&count, sizeof count, 2, &lybctx);
+ lyb_read_number(&count, sizeof count, 2, lybctx);
/* read all models */
for (i = 0; i < count; ++i) {
/* module name length */
len = 0;
- lyb_read_number(&len, sizeof len, 2, &lybctx);
+ lyb_read_number(&len, sizeof len, 2, lybctx);
/* model name */
- lyb_read(buf, len, &lybctx);
+ lyb_read(buf, len, lybctx);
/* revision */
- lyb_read(buf, 2, &lybctx);
+ lyb_read(buf, 2, lybctx);
}
- while (lybctx.in->current[0]) {
+ while (lybctx->in->current[0]) {
/* register a new subtree */
- ret = lyb_read_start_subtree(&lybctx);
+ ret = lyb_read_start_subtree(lybctx);
LY_CHECK_GOTO(ret, cleanup);
/* skip it */
- lyb_skip_subtree(&lybctx);
+ lyb_skip_subtree(lybctx);
/* subtree finished */
- ret = lyb_read_stop_subtree(&lybctx);
+ ret = lyb_read_stop_subtree(lybctx);
LY_CHECK_GOTO(ret, cleanup);
}
/* read the last zero, parsing finished */
- ly_in_skip(lybctx.in, 1);
+ ly_in_skip(lybctx->in, 1);
cleanup:
- count = lybctx.in->current - lybctx.in->start;
+ count = lybctx->in->current - lybctx->in->start;
- ly_in_free(lybctx.in, 0);
- LY_ARRAY_FREE(lybctx.subtrees);
+ ly_in_free(lybctx->in, 0);
+ lylyb_ctx_free(lybctx);
+
return ret ? -1 : count;
}
diff --git a/src/parser_xml.c b/src/parser_xml.c
index a3c8acf..ffca41f 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -31,21 +31,37 @@
/**
* @brief Internal context for XML YANG data parser.
+ *
+ * Note that the structure maps to the lyd_ctx which is common for all the data parsers
*/
struct lyd_xml_ctx {
- struct lyxml_ctx *xmlctx; /**< XML context */
+ uint32_t parse_options; /**< various @ref dataparseroptions. */
+ uint32_t validate_options; /**< various @ref datavalidationoptions. */
+ uint32_t int_opts; /**< internal data parser options */
+ uint32_t path_len; /**< used bytes in the path buffer */
+ char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
+ struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
+ struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
+ struct ly_set when_check; /**< set of nodes with "when" conditions */
+ struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
- uint32_t options; /**< various @ref dataparseroptions. */
- uint32_t int_opts; /**< internal data parser options */
- uint32_t path_len; /**< used bytes in the path buffer */
-#define LYD_PARSER_BUFSIZE 4078
- char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
- struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
- struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
- struct ly_set when_check; /**< set of nodes with "when" conditions */
- struct lyd_node *op_ntf; /**< if an RPC/action/notification is being parsed, store the pointer to it */
+ /* callbacks */
+ lyd_ctx_free_clb free; /* destructor */
+ ly_resolve_prefix_clb resolve_prefix;
+
+ struct lyxml_ctx *xmlctx; /**< XML context */
};
+void
+lyd_xml_ctx_free(struct lyd_ctx *lydctx)
+{
+ struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
+
+ lyd_ctx_free(lydctx);
+ lyxml_ctx_free(ctx->xmlctx);
+ free(ctx);
+}
+
/**
* @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
* in the values to the schema via XML namespaces.
@@ -65,14 +81,14 @@
}
static LY_ERR
-lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *unres_meta_type,
- struct lyd_meta **meta)
+lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
{
LY_ERR ret = LY_EVALID;
const struct lyxml_ns *ns;
struct lys_module *mod;
const char *name;
size_t name_len;
+ struct lyxml_ctx *xmlctx = lydctx->xmlctx;
*meta = NULL;
@@ -80,7 +96,7 @@
if (!xmlctx->prefix_len) {
/* in XML, all attributes must be prefixed
* TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
- if (strict) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
xmlctx->name_len, xmlctx->name);
goto cleanup;
@@ -104,7 +120,7 @@
mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
if (!mod) {
/* module is not implemented or not present in the schema */
- if (strict) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
"Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
@@ -121,15 +137,9 @@
assert(xmlctx->status == LYXML_ATTR_CONTENT);
/* create metadata */
- ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
- lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
- if (ret == LY_EINCOMPLETE) {
- if (unres_meta_type) {
- ly_set_add(unres_meta_type, *meta, LY_SET_OPT_USEASLIST);
- }
- } else if (ret) {
- goto cleanup;
- }
+ ret = lyd_parser_create_meta((struct lyd_ctx*)lydctx, NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len,
+ &xmlctx->dynamic, 0, lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
+ LY_CHECK_GOTO(ret, cleanup);
/* next attribute */
LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
@@ -146,12 +156,12 @@
}
static LY_ERR
-lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
+lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
{
LY_ERR ret = LY_SUCCESS;
const struct lyxml_ns *ns;
struct ly_prefix *val_prefs;
- struct ly_attr *attr2;
+ struct lyd_attr *attr2;
const char *name, *prefix;
size_t name_len, prefix_len;
@@ -189,8 +199,9 @@
LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
/* attr2 is always changed to the created attribute */
- ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
- &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
+ ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
+ &xmlctx->dynamic, 0, LYD_XML, val_prefs, prefix, prefix_len,
+ ns ? ns->uri : NULL, ns ? strlen(ns->uri) : 0);
LY_CHECK_GOTO(ret, cleanup);
if (!*attr) {
@@ -307,7 +318,7 @@
}
static LY_ERR
-lydxml_data_check_schema(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
+lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
{
LY_ERR ret = LY_SUCCESS;
enum LYXML_PARSER_STATUS prev_status;
@@ -315,40 +326,7 @@
size_t pprefix_len, pname_len;
struct lyxml_ctx *xmlctx = lydctx->xmlctx;
- if ((lydctx->options & LYD_PARSE_NO_STATE) && ((*snode)->flags & LYS_CONFIG_R)) {
- LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INNODE, "state", (*snode)->name);
- return LY_EVALID;
- }
-
- if ((*snode)->nodetype & (LYS_RPC | LYS_ACTION)) {
- if (lydctx->int_opts & LYD_INTOPT_RPC) {
- if (lydctx->op_ntf) {
- LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
- lys_nodetype2str((*snode)->nodetype), (*snode)->name,
- lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
- return LY_EVALID;
- }
- } else {
- LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
- lys_nodetype2str((*snode)->nodetype), (*snode)->name);
- return LY_EVALID;
- }
- } else if ((*snode)->nodetype == LYS_NOTIF) {
- if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
- if (lydctx->op_ntf) {
- LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
- lys_nodetype2str((*snode)->nodetype), (*snode)->name,
- lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
- return LY_EVALID;
- }
- } else {
- LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
- lys_nodetype2str((*snode)->nodetype), (*snode)->name);
- return LY_EVALID;
- }
- }
-
- if ((lydctx->options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
+ if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
/* backup parser */
prev_status = xmlctx->status;
pprefix = xmlctx->prefix;
@@ -416,7 +394,7 @@
const struct ly_ctx *ctx;
const struct lyxml_ns *ns;
struct lyd_meta *meta = NULL, *m;
- struct ly_attr *attr = NULL, *a;
+ struct lyd_attr *attr = NULL, *a;
const struct lysc_node *snode;
struct lys_module *mod;
uint32_t prev_opts;
@@ -446,13 +424,13 @@
}
mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
if (!mod) {
- if (lydctx->options & LYD_PARSE_STRICT) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
ns->uri);
ret = LY_EVALID;
goto cleanup;
}
- if (!(lydctx->options & LYD_PARSE_OPAQ)) {
+ if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
/* skip element with children */
LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
continue;
@@ -467,29 +445,30 @@
if (mod && (!parent || parent->schema)) {
snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
if (!snode) {
- if (lydctx->options & LYD_PARSE_STRICT) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
name_len, name, mod->name);
ret = LY_EVALID;
goto cleanup;
- } else if (!(lydctx->options & LYD_PARSE_OPAQ)) {
+ } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
/* skip element with children */
LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
continue;
}
} else {
/* check that schema node is valid and can be used */
- LY_CHECK_GOTO(ret = lydxml_data_check_schema(lydctx, &snode), cleanup);
+ LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), cleanup);
+ LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), cleanup);
}
}
/* create metadata/attributes */
if (xmlctx->status == LYXML_ATTRIBUTE) {
if (snode) {
- ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_PARSE_STRICT, &lydctx->unres_meta_type, &meta);
+ ret = lydxml_metadata(lydctx, snode, &meta);
LY_CHECK_GOTO(ret, cleanup);
} else {
- assert(lydctx->options & LYD_PARSE_OPAQ);
+ assert(lydctx->parse_options & LYD_PARSE_OPAQ);
ret = lydxml_attrs(xmlctx, &attr);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -497,7 +476,7 @@
assert(xmlctx->status == LYXML_ELEM_CONTENT);
if (!snode) {
- assert(lydctx->options & LYD_PARSE_OPAQ);
+ assert(lydctx->parse_options & LYD_PARSE_OPAQ);
if (xmlctx->ws_only) {
/* ignore WS-only value */
@@ -510,8 +489,8 @@
}
/* create node */
- ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
- val_prefs, prefix, prefix_len, ns->uri, &cur);
+ ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, 0, LYD_XML,
+ val_prefs, prefix, prefix_len, ns->uri, strlen(ns->uri), &cur);
LY_CHECK_GOTO(ret, cleanup);
/* parser next */
@@ -524,21 +503,14 @@
}
} else if (snode->nodetype & LYD_NODE_TERM) {
/* create node */
- ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
- xmlctx, LYD_XML, &cur);
- if (ret == LY_EINCOMPLETE) {
- if (!(lydctx->options & LYD_PARSE_ONLY)) {
- ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
- }
- } else if (ret) {
- goto cleanup;
- }
+ LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx*)lydctx, snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, 0,
+ lydxml_resolve_prefix, xmlctx, LYD_XML, &cur), cleanup);
if (parent && (cur->schema->flags & LYS_KEY)) {
/* check the key order, the anchor must never be a key */
anchor = lyd_insert_get_next_anchor(parent->child, cur);
if (anchor && (anchor->schema->flags & LYS_KEY)) {
- if (lydctx->options & LYD_PARSE_STRICT) {
+ if (lydctx->parse_options & LYD_PARSE_STRICT) {
LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
cur->schema->name);
ret = LY_EVALID;
@@ -586,21 +558,20 @@
LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
}
- if (!(lydctx->options & LYD_PARSE_ONLY)) {
+ if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
/* new node validation, autodelete CANNOT occur, all nodes are new */
ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL, NULL);
LY_CHECK_GOTO(ret, cleanup);
/* add any missing default children */
- ret = lyd_new_implicit_r(cur, lyd_node_children_p(cur), NULL, NULL, &lydctx->unres_node_type,
- &lydctx->when_check, (lydctx->options & LYD_VALIDATE_NO_STATE)
- ? LYD_IMPLICIT_NO_STATE : 0, NULL);
+ ret = lyd_new_implicit_r(cur, lyd_node_children_p(cur), NULL, NULL, &lydctx->unres_node_type, &lydctx->when_check,
+ (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
/* rememeber the RPC/action/notification */
- lydctx->op_ntf = cur;
+ lydctx->op_node = cur;
}
} else if (snode->nodetype & LYD_NODE_ANY) {
if (!xmlctx->ws_only) {
@@ -615,12 +586,12 @@
LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
/* parse any data tree with correct options */
- prev_opts = lydctx->options;
- lydctx->options &= ~LYD_PARSE_STRICT;
- lydctx->options |= LYD_PARSE_OPAQ;
+ prev_opts = lydctx->parse_options;
+ lydctx->parse_options &= ~LYD_PARSE_STRICT;
+ lydctx->parse_options |= LYD_PARSE_OPAQ;
anchor = NULL;
ret = lydxml_data_r(lydctx, NULL, &anchor);
- lydctx->options = prev_opts;
+ lydctx->parse_options = prev_opts;
LY_CHECK_GOTO(ret, cleanup);
/* create node */
@@ -631,7 +602,7 @@
/* add/correct flags */
if (snode) {
- lyd_parse_set_data_flags(cur, &lydctx->when_check, &meta, lydctx->options);
+ lyd_parse_set_data_flags(cur, &lydctx->when_check, &meta, lydctx->parse_options);
}
/* add metadata/attributes */
@@ -677,73 +648,37 @@
}
LY_ERR
-lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options, struct lyd_node **tree)
+lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options, struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
{
LY_ERR ret = LY_SUCCESS;
- struct lyd_xml_ctx lydctx = {0};
- uint32_t i = 0;
- const struct lys_module *mod;
- struct lyd_node *first, *next, **first2;
+ struct lyd_xml_ctx *lydctx;
assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
- /* init context and tree */
- LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
- lydctx.options = parse_options;
- *tree = NULL;
+ /* init context */
+ lydctx = calloc(1, sizeof *lydctx);
+ LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
+ lydctx->parse_options = parse_options;
+ lydctx->validate_options = validate_options;
+ lydctx->free = lyd_xml_ctx_free;
+ lydctx->resolve_prefix = lydxml_resolve_prefix;
/* parse XML data */
- LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
-
- if (!(parse_options & LYD_PARSE_ONLY)) {
- next = *tree;
- while (1) {
- if (validate_options & LYD_VALIDATE_PRESENT) {
- mod = lyd_data_next_module(&next, &first);
- } else {
- mod = lyd_mod_next_module(next, NULL, ctx, &i, &first);
- }
- if (!mod) {
- break;
- }
- if (first == *tree) {
- /* make sure first2 changes are carried to tree */
- first2 = tree;
- } else {
- first2 = &first;
- }
-
- /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
- LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod, NULL), cleanup);
-
- /* add all top-level defaults for this module */
- ret = lyd_new_implicit_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
- validate_options & LYD_VALIDATE_NO_STATE ? LYD_IMPLICIT_NO_STATE : 0, NULL);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* finish incompletely validated terminal values/attributes and when conditions */
- ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
- lydxml_resolve_prefix, lydctx.xmlctx, NULL);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* perform final validation that assumes the data tree is final */
- LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, validate_options, 0), cleanup);
- }
- }
+ LY_CHECK_GOTO(ret = lydxml_data_r(lydctx, NULL, tree_p), cleanup);
cleanup:
/* there should be no unresolved types stored */
- assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
- && !lydctx.when_check.count));
+ assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count
+ && !lydctx->when_check.count));
- ly_set_erase(&lydctx.unres_node_type, NULL);
- ly_set_erase(&lydctx.unres_meta_type, NULL);
- ly_set_erase(&lydctx.when_check, NULL);
- lyxml_ctx_free(lydctx.xmlctx);
if (ret) {
- lyd_free_all(*tree);
- *tree = NULL;
+ lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
+ lyd_free_all(*tree_p);
+ *tree_p = NULL;
+ } else {
+ *lydctx_p = (struct lyd_ctx *)lydctx;
}
return ret;
}
@@ -753,7 +688,7 @@
{
LY_ERR ret = LY_SUCCESS;
const struct lyxml_ns *ns = NULL;
- struct ly_attr *attr = NULL;
+ struct lyd_attr *attr = NULL;
const char *prefix;
size_t prefix_len;
@@ -795,7 +730,8 @@
LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
/* create node */
- ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, NULL, prefix, prefix_len, uri, envp);
+ ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, 0, LYD_XML, NULL, prefix, prefix_len,
+ uri, strlen(uri), envp);
LY_CHECK_GOTO(ret, cleanup);
/* assign atributes */
@@ -808,20 +744,17 @@
}
LY_ERR
-lyd_parse_xml_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
+lyd_parse_xml_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_xml_ctx lydctx = {0};
struct lyd_node *rpc_e = NULL, *act_e = NULL;
+ struct lyd_node *tree = NULL;
/* init */
LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
- lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
+ lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lydctx.int_opts = LYD_INTOPT_RPC;
- *tree = NULL;
- if (op) {
- *op = NULL;
- }
/* parse "rpc", if any */
LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
@@ -832,10 +765,10 @@
}
/* parse the rest of data normally */
- LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
+ LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, &tree), cleanup);
/* make sure we have parsed some operation */
- if (!lydctx.op_ntf) {
+ if (!lydctx.op_node) {
LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
ret = LY_EVALID;
goto cleanup;
@@ -849,9 +782,9 @@
lydctx.xmlctx->name_len, lydctx.xmlctx->name);
ret = LY_EVALID;
goto cleanup;
- } else if (lydctx.op_ntf->schema->nodetype != LYS_ACTION) {
- LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
- lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
+ } else if (lydctx.op_node->schema->nodetype != LYS_ACTION) {
+ LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
+ lys_nodetype2str(lydctx.op_node->schema->nodetype));
ret = LY_EVALID;
goto cleanup;
}
@@ -864,28 +797,35 @@
lydctx.xmlctx->name_len, lydctx.xmlctx->name);
ret = LY_EVALID;
goto cleanup;
- } else if (!act_e && (lydctx.op_ntf->schema->nodetype != LYS_RPC)) {
- LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
- lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
+ } else if (!act_e && (lydctx.op_node->schema->nodetype != LYS_RPC)) {
+ LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
+ lys_nodetype2str(lydctx.op_node->schema->nodetype));
ret = LY_EVALID;
goto cleanup;
}
LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
}
- if (op) {
- *op = lydctx.op_ntf;
+ if (op_p) {
+ *op_p = lydctx.op_node;
}
- assert(*tree);
+ assert(tree);
+ if (tree_p) {
+ *tree_p = tree;
+ }
if (act_e) {
/* connect to the action */
- lyd_insert_node(act_e, NULL, *tree);
- *tree = act_e;
+ lyd_insert_node(act_e, NULL, *tree_p);
+ if (tree_p) {
+ *tree_p = act_e;
+ }
}
if (rpc_e) {
/* connect to the rpc */
- lyd_insert_node(rpc_e, NULL, *tree);
- *tree = rpc_e;
+ lyd_insert_node(rpc_e, NULL, *tree_p);
+ if (tree_p) {
+ *tree_p = rpc_e;
+ }
}
cleanup:
@@ -893,10 +833,9 @@
assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
lyxml_ctx_free(lydctx.xmlctx);
if (ret) {
- lyd_free_all(*tree);
+ lyd_free_all(tree);
lyd_free_tree(act_e);
lyd_free_tree(rpc_e);
- *tree = NULL;
}
return ret;
}
@@ -906,7 +845,7 @@
{
LY_ERR ret = LY_SUCCESS;
const struct lyxml_ns *ns = NULL;
- struct ly_attr *attr = NULL;
+ struct lyd_attr *attr = NULL;
struct lyd_node *et;
const char *prefix;
size_t prefix_len;
@@ -961,8 +900,8 @@
}*/
/* create node */
- ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML, NULL,
- prefix, prefix_len, ns->uri, &et);
+ ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, 0, LYD_XML, NULL,
+ prefix, prefix_len, ns->uri, strlen(ns->uri), &et);
LY_CHECK_GOTO(ret, cleanup);
/* assign atributes */
@@ -992,29 +931,26 @@
}
LY_ERR
-lyd_parse_xml_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **ntf)
+lyd_parse_xml_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_xml_ctx lydctx = {0};
struct lyd_node *ntf_e = NULL;
+ struct lyd_node *tree = NULL;
/* init */
LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
- lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
+ lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lydctx.int_opts = LYD_INTOPT_NOTIF;
- *tree = NULL;
- if (ntf) {
- *ntf = NULL;
- }
/* parse "notification" and "eventTime", if present */
LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
/* parse the rest of data normally */
- LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
+ LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, &tree), cleanup);
/* make sure we have parsed some notification */
- if (!lydctx.op_ntf) {
+ if (!lydctx.op_node) {
LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
ret = LY_EVALID;
goto cleanup;
@@ -1032,14 +968,19 @@
LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
}
- if (ntf) {
- *ntf = lydctx.op_ntf;
+ if (ntf_p) {
+ *ntf_p = lydctx.op_node;
}
- assert(*tree);
+ assert(tree);
+ if (tree_p) {
+ *tree_p = tree;
+ }
if (ntf_e) {
/* connect to the notification */
- lyd_insert_node(ntf_e, NULL, *tree);
- *tree = ntf_e;
+ lyd_insert_node(ntf_e, NULL, *tree_p);
+ if (tree_p) {
+ *tree_p = ntf_e;
+ }
}
cleanup:
@@ -1047,15 +988,14 @@
assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
lyxml_ctx_free(lydctx.xmlctx);
if (ret) {
- lyd_free_all(*tree);
+ lyd_free_all(tree);
lyd_free_tree(ntf_e);
- *tree = NULL;
}
return ret;
}
LY_ERR
-lyd_parse_xml_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
+lyd_parse_xml_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_xml_ctx lydctx = {0};
@@ -1063,12 +1003,8 @@
/* init */
LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), in, &lydctx.xmlctx), cleanup);
- lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
+ lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lydctx.int_opts = LYD_INTOPT_REPLY;
- *tree = NULL;
- if (op) {
- *op = NULL;
- }
/* find request OP */
LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
@@ -1105,15 +1041,19 @@
LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
}
- if (op) {
- *op = rep_op;
+ if (op_p) {
+ *op_p = rep_op;
}
for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
- *tree = iter;
+ if (tree_p) {
+ *tree_p = iter;
+ }
if (rpcr_e) {
/* connect to the operation */
- lyd_insert_node(rpcr_e, NULL, *tree);
- *tree = rpcr_e;
+ lyd_insert_node(rpcr_e, NULL, *tree_p);
+ if (tree_p) {
+ *tree_p = rpcr_e;
+ }
}
cleanup:
diff --git a/src/path.c b/src/path.c
index 3a299ae..5f30e94 100644
--- a/src/path.c
+++ b/src/path.c
@@ -364,7 +364,7 @@
static LY_ERR
ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx,
- uint8_t lref, ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
+ uint8_t lref, ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format,
const struct lys_module **mod, const char **name, size_t *name_len)
{
const char *ptr;
@@ -423,7 +423,7 @@
LY_ERR
ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
- ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format,
struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
{
struct ly_path_predicate *p;
@@ -574,7 +574,7 @@
*/
static LY_ERR
ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
- const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
+ const struct lyxp_expr *expr, uint16_t *tok_idx, ly_resolve_prefix_clb resolve_prefix,
void *prefix_data, LYD_FORMAT format)
{
const struct lysc_node *key, *node, *node2;
@@ -694,7 +694,7 @@
LY_ERR
ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
- ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path)
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path)
{
LY_ERR ret = LY_SUCCESS;
uint16_t tok_idx = 0;
diff --git a/src/path.h b/src/path.h
index 80085a6..9faa0e1 100644
--- a/src/path.h
+++ b/src/path.h
@@ -160,7 +160,7 @@
*/
LY_ERR ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
- ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path);
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path);
/**
* @brief Compile predicate into ly_path_predicate structure. Only simple predicates (not leafref) are supported.
@@ -180,7 +180,7 @@
*/
LY_ERR ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
- ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format,
struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type);
/**
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 2b64a20..e6e4e36 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -57,7 +57,7 @@
*/
static const char *
ly_type_print_canonical(const struct lyd_value *value, LYD_FORMAT UNUSED(format),
- ly_clb_get_prefix UNUSED(get_prefix), void *UNUSED(printer), int *dynamic)
+ ly_get_prefix_clb UNUSED(get_prefix), void *UNUSED(printer), int *dynamic)
{
*dynamic = 0;
return (char*)value->canonical_cache;
@@ -161,7 +161,7 @@
}
API struct lyd_value_prefix *
-ly_type_get_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len, ly_clb_resolve_prefix resolve_prefix,
+ly_type_get_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len, ly_resolve_prefix_clb resolve_prefix,
void *parser)
{
LY_ERR ret;
@@ -524,7 +524,7 @@
*/
static LY_ERR
ly_type_store_int(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -599,7 +599,7 @@
*/
static LY_ERR
ly_type_store_uint(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -673,7 +673,7 @@
*/
static LY_ERR
ly_type_store_decimal64(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -757,7 +757,7 @@
*/
static LY_ERR
ly_type_store_binary(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -867,7 +867,7 @@
*/
static LY_ERR
ly_type_store_string(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -911,7 +911,7 @@
*/
static LY_ERR
ly_type_store_bits(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -1100,7 +1100,7 @@
*/
static LY_ERR
ly_type_store_enum(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -1180,7 +1180,7 @@
*/
static LY_ERR
ly_type_store_boolean(const struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -1240,7 +1240,7 @@
*/
static LY_ERR
ly_type_store_empty(const struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -1305,7 +1305,7 @@
*/
static LY_ERR
ly_type_store_identityref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT UNUSED(format),
+ ly_resolve_prefix_clb resolve_prefix, void *parser, LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -1426,7 +1426,7 @@
* Implementation of the ly_type_print_clb.
*/
static const char *
-ly_type_print_identityref(const struct lyd_value *value, LYD_FORMAT UNUSED(format), ly_clb_get_prefix get_prefix, void *printer, int *dynamic)
+ly_type_print_identityref(const struct lyd_value *value, LYD_FORMAT UNUSED(format), ly_get_prefix_clb get_prefix, void *printer, int *dynamic)
{
char *result = NULL;
@@ -1453,7 +1453,7 @@
* @brief Helper function for ly_type_store_instanceid_parse_predicate_value() to provide prefix mapping for the
* validation callbacks for the values used in instance-identifier predicates.
*
- * Implementation of the ly_clb_resolve_prefix.
+ * Implementation of the ly_resolve_prefix_clb.
*/
static const struct lys_module *
ly_type_stored_prefixes_clb(const struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
@@ -1476,7 +1476,7 @@
*/
static LY_ERR
ly_type_store_instanceid(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
+ ly_resolve_prefix_clb resolve_prefix, void *parser, LYD_FORMAT format,
const void *context_node, const struct lyd_node *tree, struct lyd_value *storage,
const char **canonized, struct ly_err_item **err)
{
@@ -1490,6 +1490,7 @@
struct lyxp_expr *exp = NULL;
const struct lysc_node *ctx_scnode;
int erc = 0;
+ int prefix_opt = 0;
/* init */
*err = NULL;
@@ -1504,6 +1505,17 @@
goto cleanup;
}
+ switch (format) {
+ case LYD_SCHEMA:
+ case LYD_XML:
+ prefix_opt = LY_PATH_PREFIX_MANDATORY;
+ break;
+ case LYD_JSON:
+ case LYD_LYB:
+ prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
+ break;
+ }
+
if (!(options & LY_TYPE_OPTS_SCHEMA) && (options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
/* the second run in data tree, the first one ended with LY_EINCOMPLETE, but we have prepared the target structure */
if (ly_path_eval(storage->target, tree, NULL)) {
@@ -1528,7 +1540,7 @@
/* parse the value */
ret = ly_path_parse(ctx, ctx_scnode, value, value_len, LY_PATH_BEGIN_ABSOLUTE, LY_PATH_LREF_FALSE,
- LY_PATH_PREFIX_MANDATORY, LY_PATH_PRED_SIMPLE, &exp);
+ prefix_opt, LY_PATH_PRED_SIMPLE, &exp);
if (ret) {
erc = asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - syntax error.", (int)value_len, value);
goto error;
@@ -1670,7 +1682,7 @@
* Implementation of the ly_type_print_clb.
*/
static const char *
-ly_type_print_instanceid(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix, void *printer,
+ly_type_print_instanceid(const struct lyd_value *value, LYD_FORMAT format, ly_get_prefix_clb get_prefix, void *printer,
int *dynamic)
{
LY_ARRAY_COUNT_TYPE u, v;
@@ -1882,7 +1894,7 @@
*/
static LY_ERR
ly_type_store_leafref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
+ ly_resolve_prefix_clb resolve_prefix, void *parser, LYD_FORMAT format,
const void *context_node, const struct lyd_node *tree,
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -1990,7 +2002,7 @@
* Implementation of the ly_type_print_clb.
*/
static const char *
-ly_type_print_leafref(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix, void *printer, int *dynamic)
+ly_type_print_leafref(const struct lyd_value *value, LYD_FORMAT format, ly_get_prefix_clb get_prefix, void *printer, int *dynamic)
{
return value->realtype->plugin->print(value, format, get_prefix, printer, dynamic);
}
@@ -2023,13 +2035,62 @@
}
/**
+ * @brief Answer if the type is suitable for the parser's hit (if any) in the specified format
+ */
+LY_ERR
+type_check_parser_hint(LYD_FORMAT format, int hint, LY_DATA_TYPE type)
+{
+ if (format == LYD_JSON && hint) {
+ switch (type) {
+ case LY_TYPE_UINT8:
+ case LY_TYPE_UINT16:
+ case LY_TYPE_UINT32:
+ case LY_TYPE_INT8:
+ case LY_TYPE_INT16:
+ case LY_TYPE_INT32:
+ if (hint != LY_TYPE_OPTS_ISNUMBER) {
+ return LY_ENOT;
+ }
+ break;
+ case LY_TYPE_STRING:
+ case LY_TYPE_UINT64:
+ case LY_TYPE_INT64:
+ case LY_TYPE_DEC64:
+ case LY_TYPE_ENUM:
+ case LY_TYPE_BITS:
+ case LY_TYPE_BINARY:
+ case LY_TYPE_IDENT:
+ case LY_TYPE_INST:
+ if (hint != LY_TYPE_OPTS_ISSTRING) {
+ return LY_ENOT;
+ }
+ break;
+ case LY_TYPE_BOOL:
+ if (hint != LY_TYPE_OPTS_ISBOOLEAN) {
+ return LY_ENOT;
+ }
+ break;
+ case LY_TYPE_EMPTY:
+ if (hint != LY_TYPE_OPTS_ISEMPTY) {
+ return LY_ENOT;
+ }
+ break;
+ default:
+ LOGINT_RET(NULL);
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
* @brief Validate, canonize and store value of the YANG built-in union type.
*
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
ly_type_store_union(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
+ ly_resolve_prefix_clb resolve_prefix, void *parser, LYD_FORMAT format,
const void *context_node, const struct lyd_node *tree,
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
{
@@ -2070,11 +2131,19 @@
/* store prefixes for later use */
subvalue->prefixes = ly_type_get_prefixes(ctx, value, value_len, resolve_prefix, parser);
+ /* remember the hint options */
+ subvalue->parser_hint = options & LY_TYPE_PARSER_HINTS_MASK;
+
search_subtype:
/* use the first usable sybtype to store the value */
LY_ARRAY_FOR(type_u->types, u) {
subvalue->value->realtype = type_u->types[u];
+ if (type_check_parser_hint(format, subvalue->parser_hint, subvalue->value->realtype->basetype)) {
+ /* not a suitable type */
+ continue;
+ }
+
/* turn logging off */
prev_lo = ly_log_options(0);
ret = type_u->types[u]->plugin->store(ctx, type_u->types[u], value, value_len, options & ~LY_TYPE_OPTS_DYNAMIC,
@@ -2154,7 +2223,7 @@
* Implementation of the ly_type_print_clb.
*/
static const char *
-ly_type_print_union(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix, void *printer, int *dynamic)
+ly_type_print_union(const struct lyd_value *value, LYD_FORMAT format, ly_get_prefix_clb get_prefix, void *printer, int *dynamic)
{
return value->subvalue->value->realtype->plugin->print(value->subvalue->value, format, get_prefix, printer, dynamic);
}
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 62d2d38..eaf449f 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -155,10 +155,19 @@
can (e.g. store the canonical/auxiliary value if it is requested) and in the case of need to use
data trees (checking require-instance), it returns LY_EINCOMPLETE.
Caller is supposed to call such validation callback again later with complete data trees. */
-#define LY_TYPE_OPTS_SECOND_CALL 0x20 /**< Flag for the second call of the callback when the first call returns LY_EINCOMPLETE,
+#define LY_TYPE_OPTS_SECOND_CALL 0x20 /**< Flag for the second call of the callback when the first call returns LY_EINCOMPLETE,
other options should be the same as for the first call. **!!** Note that this second call
can occur even if the first call succeeded, in which case the plugin should immediately
return LY_SUCCESS. */
+#define LY_TYPE_OPTS_ISSTRING LYD_NODE_OPAQ_ISSTRING /**< Hint flag from the parser in case the source format provides some additional information
+ about the type of the data. The flag is expected to be used in combination with the format information. */
+#define LY_TYPE_OPTS_ISNUMBER LYD_NODE_OPAQ_ISNUMBER /**< Hint flag from the parser in case the source format provides some additional information
+ about the type of the data. The flag is expected to be used in combination with the format information. */
+#define LY_TYPE_OPTS_ISBOOLEAN LYD_NODE_OPAQ_ISBOOLEAN /**< Hint flag from the parser in case the source format provides some additional information
+ about the type of the data. The flag is expected to be used in combination with the format information. */
+#define LY_TYPE_OPTS_ISEMPTY LYD_NODE_OPAQ_ISEMPTY /**< Hint flag from the parser in case the source format provides some additional information
+ about the type of the data. The flag is expected to be used in combination with the format information. */
+#define LY_TYPE_PARSER_HINTS_MASK (LY_TYPE_OPTS_ISSTRING | LY_TYPE_OPTS_ISNUMBER | LY_TYPE_OPTS_ISBOOLEAN | LY_TYPE_OPTS_ISEMPTY)
/** @} plugintypeopts */
@@ -200,7 +209,7 @@
* @return LY_ERR value if an error occurred and the value could not be canonized following the type's rules.
*/
typedef LY_ERR (*ly_type_store_clb)(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
- int options, ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
+ int options, ly_resolve_prefix_clb resolve_prefix, void *parser, LYD_FORMAT format,
const void *context_node, const struct lyd_node *tree,
struct lyd_value *storage, const char **canonized, struct ly_err_item **err);
@@ -234,7 +243,7 @@
* can be responsible for freeing allocated memory.
* @return NULL in case of error.
*/
-typedef const char *(*ly_type_print_clb)(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix,
+typedef const char *(*ly_type_print_clb)(const struct lyd_value *value, LYD_FORMAT format, ly_get_prefix_clb get_prefix,
void *printer, int *dynamic);
/**
@@ -391,7 +400,7 @@
* @return Created [sized array](@ref sizedarrays) of prefix mappings, NULL in case of error.
*/
struct lyd_value_prefix *ly_type_get_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len,
- ly_clb_resolve_prefix get_prefix, void *parser);
+ ly_resolve_prefix_clb get_prefix, void *parser);
/** @} types */
diff --git a/src/printer_json.c b/src/printer_json.c
index 057bf6e..705d2eb 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -20,7 +20,7 @@
/**
* @brief JSON mapping of YANG modules to prefixes in values.
*
- * Implementation of ly_clb_get_prefix.
+ * Implementation of ly_get_prefix_clb.
*/
const char *
json_print_get_prefix(const struct lys_module *mod, void *UNUSED(private))
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 1b89e39..9331876 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -223,7 +223,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_write(struct ly_out *out, const uint8_t *buf, size_t count, struct lyd_lyb_ctx *lybctx)
+lyb_write(struct ly_out *out, const uint8_t *buf, size_t count, struct lylyb_ctx *lybctx)
{
LY_ARRAY_COUNT_TYPE u;
struct lyd_lyb_subtree *full, *iter;
@@ -307,7 +307,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_write_stop_subtree(struct ly_out *out, struct lyd_lyb_ctx *lybctx)
+lyb_write_stop_subtree(struct ly_out *out, struct lylyb_ctx *lybctx)
{
ssize_t r;
uint8_t meta_buf[LYB_META_BYTES];
@@ -334,7 +334,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_write_start_subtree(struct ly_out *out, struct lyd_lyb_ctx *lybctx)
+lyb_write_start_subtree(struct ly_out *out, struct lylyb_ctx *lybctx)
{
ssize_t r;
LY_ARRAY_COUNT_TYPE u;
@@ -381,7 +381,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_write_number(uint64_t num, size_t bytes, struct ly_out *out, struct lyd_lyb_ctx *lybctx)
+lyb_write_number(uint64_t num, size_t bytes, struct ly_out *out, struct lylyb_ctx *lybctx)
{
/* correct byte order */
num = htole64(num);
@@ -400,7 +400,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_write_string(const char *str, size_t str_len, int with_length, struct ly_out *out, struct lyd_lyb_ctx *lybctx)
+lyb_write_string(const char *str, size_t str_len, int with_length, struct ly_out *out, struct lylyb_ctx *lybctx)
{
if (!str) {
str = "";
@@ -432,7 +432,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_model(struct ly_out *out, const struct lys_module *mod, struct lyd_lyb_ctx *lybctx)
+lyb_print_model(struct ly_out *out, const struct lys_module *mod, struct lylyb_ctx *lybctx)
{
int r;
uint16_t revision;
@@ -477,7 +477,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_data_models(struct ly_out *out, const struct lyd_node *root, struct lyd_lyb_ctx *lybctx)
+lyb_print_data_models(struct ly_out *out, const struct lyd_node *root, struct lylyb_ctx *lybctx)
{
struct ly_set *set;
LY_ARRAY_COUNT_TYPE u;
@@ -577,7 +577,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_opaq_prefixes(struct ly_out *out, const struct ly_prefix *prefs, struct lyd_lyb_ctx *lybctx)
+lyb_print_opaq_prefixes(struct ly_out *out, const struct ly_prefix *prefs, struct lylyb_ctx *lybctx)
{
uint8_t count;
LY_ARRAY_COUNT_TYPE u;
@@ -595,10 +595,10 @@
/* write all the prefixes */
LY_ARRAY_FOR(prefs, u) {
/* prefix */
- LY_CHECK_RET(lyb_write_string(prefs[u].pref, 0, 1, out, lybctx));
+ LY_CHECK_RET(lyb_write_string(prefs[u].id, 0, 1, out, lybctx));
/* namespace */
- LY_CHECK_RET(lyb_write_string(prefs[u].ns, 0, 1, out, lybctx));
+ LY_CHECK_RET(lyb_write_string(prefs[u].module_name, 0, 1, out, lybctx));
}
return LY_SUCCESS;
@@ -613,13 +613,13 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_opaq(struct lyd_node_opaq *opaq, struct ly_out *out, struct lyd_lyb_ctx *lybctx)
+lyb_print_opaq(struct lyd_node_opaq *opaq, struct ly_out *out, struct lylyb_ctx *lybctx)
{
/* prefix */
- LY_CHECK_RET(lyb_write_string(opaq->prefix.pref, 0, 1, out, lybctx));
+ LY_CHECK_RET(lyb_write_string(opaq->prefix.id, 0, 1, out, lybctx));
- /* namespace */
- LY_CHECK_RET(lyb_write_string(opaq->prefix.ns, 0, 1, out, lybctx));
+ /* module reference */
+ LY_CHECK_RET(lyb_write_string(opaq->prefix.module_name, 0, 1, out, lybctx));
/* name */
LY_CHECK_RET(lyb_write_string(opaq->name, 0, 1, out, lybctx));
@@ -645,7 +645,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_anydata(struct lyd_node_any *anydata, struct ly_out *out, struct lyd_lyb_ctx *lybctx)
+lyb_print_anydata(struct lyd_node_any *anydata, struct ly_out *out, struct lylyb_ctx *lybctx)
{
LY_ERR ret = LY_SUCCESS;
LYD_ANYDATA_VALUETYPE value_type;
@@ -698,7 +698,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_term(struct lyd_node_term *term, struct ly_out *out, struct lyd_lyb_ctx *lybctx)
+lyb_print_term(struct lyd_node_term *term, struct ly_out *out, struct lylyb_ctx *lybctx)
{
LY_ERR ret;
int dynamic;
@@ -749,47 +749,47 @@
}
for (iter = node->meta; iter; iter = iter->next) {
if (count == UINT8_MAX) {
- LOGERR(lybctx->ctx, LY_EINT, "Maximum supported number of data node metadata is %u.", UINT8_MAX);
+ LOGERR(lybctx->lybctx->ctx, LY_EINT, "Maximum supported number of data node metadata is %u.", UINT8_MAX);
return LY_EINT;
}
++count;
}
/* write number of metadata on 1 byte */
- LY_CHECK_RET(lyb_write(out, &count, 1, lybctx));
+ LY_CHECK_RET(lyb_write(out, &count, 1, lybctx->lybctx));
if (wd_mod) {
/* write the "default" metadata */
- LY_CHECK_RET(lyb_write_start_subtree(out, lybctx));
- LY_CHECK_RET(lyb_print_model(out, wd_mod, lybctx));
- LY_CHECK_RET(lyb_write_string("default", 0, 1, out, lybctx));
- LY_CHECK_RET(lyb_write_string("true", 0, 0, out, lybctx));
- LY_CHECK_RET(lyb_write_stop_subtree(out, lybctx));
+ LY_CHECK_RET(lyb_write_start_subtree(out, lybctx->lybctx));
+ LY_CHECK_RET(lyb_print_model(out, wd_mod, lybctx->lybctx));
+ LY_CHECK_RET(lyb_write_string("default", 0, 1, out, lybctx->lybctx));
+ LY_CHECK_RET(lyb_write_string("true", 0, 0, out, lybctx->lybctx));
+ LY_CHECK_RET(lyb_write_stop_subtree(out, lybctx->lybctx));
}
/* write all the node metadata */
LY_LIST_FOR(node->meta, iter) {
/* each metadata is a subtree */
- LY_CHECK_RET(lyb_write_start_subtree(out, lybctx));
+ LY_CHECK_RET(lyb_write_start_subtree(out, lybctx->lybctx));
/* model */
- LY_CHECK_RET(lyb_print_model(out, iter->annotation->module, lybctx));
+ LY_CHECK_RET(lyb_print_model(out, iter->annotation->module, lybctx->lybctx));
/* annotation name with length */
- LY_CHECK_RET(lyb_write_string(iter->name, 0, 1, out, lybctx));
+ LY_CHECK_RET(lyb_write_string(iter->name, 0, 1, out, lybctx->lybctx));
/* get the value */
str = lyd_meta2str(iter, &dynamic);
/* metadata value */
- ret = lyb_write_string(str, 0, 0, out, lybctx);
+ ret = lyb_write_string(str, 0, 0, out, lybctx->lybctx);
if (dynamic) {
free((char *)str);
}
LY_CHECK_RET(ret);
/* finish metadata subtree */
- LY_CHECK_RET(lyb_write_stop_subtree(out, lybctx));
+ LY_CHECK_RET(lyb_write_stop_subtree(out, lybctx->lybctx));
}
return LY_SUCCESS;
@@ -804,7 +804,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_attributes(struct ly_out *out, const struct lyd_node_opaq *node, struct lyd_lyb_ctx *lybctx)
+lyb_print_attributes(struct ly_out *out, const struct lyd_node_opaq *node, struct lylyb_ctx *lybctx)
{
uint8_t count = 0;
struct ly_attr *iter;
@@ -826,10 +826,10 @@
LY_CHECK_RET(lyb_write_start_subtree(out, lybctx));
/* prefix */
- LY_CHECK_RET(lyb_write_string(iter->prefix.pref, 0, 1, out, lybctx));
+ LY_CHECK_RET(lyb_write_string(iter->prefix.id, 0, 1, out, lybctx));
/* namespace */
- LY_CHECK_RET(lyb_write_string(iter->prefix.ns, 0, 1, out, lybctx));
+ LY_CHECK_RET(lyb_write_string(iter->prefix.module_name, 0, 1, out, lybctx));
/* name */
LY_CHECK_RET(lyb_write_string(iter->name, 0, 1, out, lybctx));
@@ -860,7 +860,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_print_schema_hash(struct ly_out *out, struct lysc_node *schema, struct hash_table **sibling_ht, struct lyd_lyb_ctx *lybctx)
+lyb_print_schema_hash(struct ly_out *out, struct lysc_node *schema, struct hash_table **sibling_ht, struct lylyb_ctx *lybctx)
{
LY_ARRAY_COUNT_TYPE u;
uint32_t i;
@@ -941,36 +941,36 @@
struct hash_table *child_ht = NULL;
/* register a new subtree */
- LY_CHECK_RET(lyb_write_start_subtree(out, lybctx));
+ LY_CHECK_RET(lyb_write_start_subtree(out, lybctx->lybctx));
/* write model info first */
if (!node->schema && !((struct lyd_node_opaq *)node)->parent) {
- LY_CHECK_RET(lyb_print_model(out, NULL, lybctx));
+ LY_CHECK_RET(lyb_print_model(out, NULL, lybctx->lybctx));
} else if (node->schema && !lysc_data_parent(node->schema)) {
- LY_CHECK_RET(lyb_print_model(out, node->schema->module, lybctx));
+ LY_CHECK_RET(lyb_print_model(out, node->schema->module, lybctx->lybctx));
}
/* write schema hash */
- LY_CHECK_RET(lyb_print_schema_hash(out, (struct lysc_node *)node->schema, sibling_ht, lybctx));
+ LY_CHECK_RET(lyb_print_schema_hash(out, (struct lysc_node *)node->schema, sibling_ht, lybctx->lybctx));
/* write any metadata/attributes */
if (node->schema) {
LY_CHECK_RET(lyb_print_metadata(out, node, lybctx));
} else {
- LY_CHECK_RET(lyb_print_attributes(out, (struct lyd_node_opaq *)node, lybctx));
+ LY_CHECK_RET(lyb_print_attributes(out, (struct lyd_node_opaq *)node, lybctx->lybctx));
}
/* write node content */
if (!node->schema) {
- LY_CHECK_RET(lyb_print_opaq((struct lyd_node_opaq *)node, out, lybctx));
+ LY_CHECK_RET(lyb_print_opaq((struct lyd_node_opaq *)node, out, lybctx->lybctx));
} else if (node->schema->nodetype & LYD_NODE_INNER) {
/* nothing to write */
} else if (node->schema->nodetype & LYD_NODE_TERM) {
- LY_CHECK_RET(lyb_print_term((struct lyd_node_term *)node, out, lybctx));
+ LY_CHECK_RET(lyb_print_term((struct lyd_node_term *)node, out, lybctx->lybctx));
} else if (node->schema->nodetype & LYD_NODE_ANY) {
- LY_CHECK_RET(lyb_print_anydata((struct lyd_node_any *)node, out, lybctx));
+ LY_CHECK_RET(lyb_print_anydata((struct lyd_node_any *)node, out, lybctx->lybctx));
} else {
- LOGINT_RET(lybctx->ctx);
+ LOGINT_RET(lybctx->lybctx->ctx);
}
/* recursively write all the descendants */
@@ -979,7 +979,7 @@
}
/* finish this subtree */
- LY_CHECK_RET(lyb_write_stop_subtree(out, lybctx));
+ LY_CHECK_RET(lyb_write_stop_subtree(out, lybctx->lybctx));
return LY_SUCCESS;
}
@@ -989,17 +989,22 @@
{
LY_ERR ret = LY_SUCCESS;
uint8_t zero = 0;
- LY_ARRAY_COUNT_TYPE u;
struct hash_table *top_sibling_ht = NULL;
const struct lys_module *prev_mod = NULL;
- struct lyd_lyb_ctx lybctx = {0};
+ struct lyd_lyb_ctx *lybctx;
+ const struct ly_ctx *ctx = LYD_NODE_CTX(root);
- lybctx.print_options = options;
+ lybctx = calloc(1, sizeof *lybctx);
+ LY_CHECK_ERR_RET(!lybctx, LOGMEM(ctx), LY_EMEM);
+ lybctx->lybctx = calloc(1, sizeof *lybctx->lybctx);
+ LY_CHECK_ERR_RET(!lybctx, LOGMEM(ctx), LY_EMEM);
+
+ lybctx->print_options = options;
if (root) {
- lybctx.ctx = LYD_NODE_CTX(root);
+ lybctx->lybctx->ctx = ctx;
if (root->schema && lysc_data_parent(root->schema)) {
- LOGERR(lybctx.ctx, LY_EINVAL, "LYB printer supports only printing top-level nodes.");
+ LOGERR(lybctx->lybctx->ctx, LY_EINVAL, "LYB printer supports only printing top-level nodes.");
return LY_EINVAL;
}
}
@@ -1011,7 +1016,7 @@
LY_CHECK_GOTO(ret = lyb_print_header(out), cleanup);
/* all used models */
- LY_CHECK_GOTO(ret = lyb_print_data_models(out, root, &lybctx), cleanup);
+ LY_CHECK_GOTO(ret = lyb_print_data_models(out, root, lybctx->lybctx), cleanup);
LY_LIST_FOR(root, root) {
/* do not reuse sibling hash tables from different modules */
@@ -1020,7 +1025,7 @@
prev_mod = root->schema ? root->schema->module : NULL;
}
- LY_CHECK_GOTO(ret = lyb_print_subtree(out, root, &top_sibling_ht, &lybctx), cleanup);
+ LY_CHECK_GOTO(ret = lyb_print_subtree(out, root, &top_sibling_ht, lybctx), cleanup);
if (!(options & LYD_PRINT_WITHSIBLINGS)) {
break;
@@ -1028,14 +1033,9 @@
}
/* ending zero byte */
- LY_CHECK_GOTO(ret = lyb_write(out, &zero, sizeof zero, &lybctx), cleanup);
+ LY_CHECK_GOTO(ret = lyb_write(out, &zero, sizeof zero, lybctx->lybctx), cleanup);
cleanup:
- LY_ARRAY_FREE(lybctx.subtrees);
- LY_ARRAY_FOR(lybctx.sib_hts, u) {
- lyht_free(lybctx.sib_hts[u].ht);
- }
- LY_ARRAY_FREE(lybctx.sib_hts);
-
+ lyd_lyb_ctx_free((struct lyd_ctx *)lybctx);
return ret;
}
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 71e53c0..3a94406 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -50,6 +50,7 @@
#define LEVEL_DEC if (LEVEL) {LEVEL--;} /**< decrease indentation level */
#define LYXML_PREFIX_REQUIRED 0x01 /**< The prefix is not just a suggestion but a requirement. */
+#define LYXML_PREFIX_DEFAULT 0x02 /**< The namespace is required to be a default (without prefix) */
/**
* @brief Print a namespace if not already printed.
@@ -107,10 +108,35 @@
return ctx->prefix.objs[i];
}
+static const char*
+xml_print_ns_opaq(struct xmlpr_ctx *ctx, LYD_FORMAT format, const struct ly_prefix *prefix, int prefix_opts)
+{
+
+ switch (format) {
+ case LYD_XML:
+ return xml_print_ns(ctx, prefix->module_ns, (prefix_opts & LYXML_PREFIX_DEFAULT) ? NULL : prefix->id, prefix_opts);
+ break;
+ case LYD_JSON:
+ if (prefix->module_name) {
+ const struct lys_module *mod = ly_ctx_get_module_latest(ctx->ctx, prefix->module_name);
+ if (mod) {
+ return xml_print_ns(ctx, mod->ns, (prefix_opts & LYXML_PREFIX_DEFAULT) ? NULL : prefix->id, prefix_opts);
+ }
+ }
+ break;
+ case LYD_SCHEMA:
+ case LYD_LYB:
+ /* cannot be created */
+ LOGINT(ctx->ctx);
+ }
+
+ return NULL;
+}
+
/**
* @brief XML mapping of YANG modules to prefixes in values.
*
- * Implementation of ly_clb_get_prefix
+ * Implementation of ly_get_prefix_clb
*/
static const char *
xml_print_get_prefix(const struct lys_module *mod, void *private)
@@ -237,24 +263,15 @@
LY_LIST_FOR(node->attr, attr) {
pref = NULL;
- if (attr->prefix.pref) {
+ if (attr->prefix.id) {
/* print attribute namespace */
- switch (attr->format) {
- case LYD_XML:
- pref = xml_print_ns(ctx, attr->prefix.ns, attr->prefix.pref, 0);
- break;
- case LYD_SCHEMA:
- case LYD_LYB:
- /* cannot be created */
- LOGINT(node->ctx);
- return LY_EINT;
- }
+ pref = xml_print_ns_opaq(ctx, attr->format, &attr->prefix, 0);
}
/* print namespaces connected with the value's prefixes */
if (attr->val_prefs) {
LY_ARRAY_FOR(attr->val_prefs, u) {
- xml_print_ns(ctx, attr->val_prefs[u].ns, attr->val_prefs[u].pref, LYXML_PREFIX_REQUIRED);
+ xml_print_ns_opaq(ctx, attr->format, &attr->val_prefs[u], LYXML_PREFIX_REQUIRED);
}
}
@@ -272,16 +289,7 @@
ly_print(ctx->out, "%*s<%s", INDENT, node->name);
/* print default namespace */
- switch (node->format) {
- case LYD_XML:
- xml_print_ns(ctx, node->prefix.ns, NULL, 0);
- break;
- case LYD_SCHEMA:
- case LYD_LYB:
- /* cannot be created */
- LOGINT(node->ctx);
- return LY_EINT;
- }
+ xml_print_ns_opaq(ctx, node->format, &node->prefix, LYXML_PREFIX_DEFAULT);
/* print attributes */
LY_CHECK_RET(xml_print_attr(ctx, node));
@@ -457,7 +465,7 @@
/* print namespaces connected with the value's prefixes */
if (node->val_prefs) {
LY_ARRAY_FOR(node->val_prefs, u) {
- xml_print_ns(ctx, node->val_prefs[u].ns, node->val_prefs[u].pref, LYXML_PREFIX_REQUIRED);
+ xml_print_ns_opaq(ctx, node->format, &node->val_prefs[u], LYXML_PREFIX_REQUIRED);
}
}
diff --git a/src/tree_data.c b/src/tree_data.c
index 5ca3f4a..a5572d7 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -55,14 +55,14 @@
struct lyd_node **match);
LY_ERR
-lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
- ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree)
+lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second, int value_hint,
+ ly_resolve_prefix_clb get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree)
{
LY_ERR ret = LY_SUCCESS;
struct ly_err_item *err = NULL;
struct ly_ctx *ctx;
struct lysc_type *type;
- int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
+ int options = value_hint | LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
(dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
assert(node);
@@ -96,7 +96,7 @@
/* similar to lyd_value_parse except can be used just to store the value, hence also does not support a second call */
LY_ERR
lyd_value_store(struct lyd_value *val, const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
- ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format)
+ ly_resolve_prefix_clb get_prefix, void *parser, LYD_FORMAT format)
{
LY_ERR ret = LY_SUCCESS;
struct ly_err_item *err = NULL;
@@ -128,13 +128,13 @@
LY_ERR
lyd_value_parse_meta(const struct ly_ctx *ctx, struct lyd_meta *meta, const char *value, size_t value_len, int *dynamic,
- int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+ int second, int value_hint, ly_resolve_prefix_clb get_prefix, void *parser, LYD_FORMAT format,
const struct lysc_node *ctx_snode, const struct lyd_node *tree)
{
LY_ERR ret = LY_SUCCESS;
struct ly_err_item *err = NULL;
struct lyext_metadata *ant;
- int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
+ int options = value_hint | LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
(dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
assert(ctx && meta && ((tree && meta->parent) || ctx_snode));
@@ -163,7 +163,7 @@
LY_ERR
_lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
- ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format)
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format)
{
LY_ERR rc = LY_SUCCESS;
struct ly_err_item *err = NULL;
@@ -309,10 +309,8 @@
if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
format = LYD_XML;
-#if 0
} else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
format = LYD_JSON;
-#endif
} else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
format = LYD_LYB;
} /* else still unknown */
@@ -325,6 +323,9 @@
lyd_parse_data(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, int parse_options, int validate_options,
struct lyd_node **tree)
{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_ctx *lydctx = NULL;
+
LY_CHECK_ARG_RET(ctx, ctx, in, tree, LY_EINVAL);
LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
@@ -332,26 +333,73 @@
format = lyd_parse_get_format(in, format);
LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
+ /* init */
+ *tree = NULL;
+
/* remember input position */
in->func_start = in->current;
switch (format) {
case LYD_XML:
- return lyd_parse_xml_data(ctx, in, parse_options, validate_options, tree);
-#if 0
+ LY_CHECK_RET(lyd_parse_xml_data(ctx, in, parse_options, validate_options, tree, &lydctx));
+ break;
case LYD_JSON:
- return lyd_parse_json_data(ctx, in, parse_options, validate_options, tree);
-#endif
+ LY_CHECK_RET(lyd_parse_json_data(ctx, in, parse_options, validate_options, tree, &lydctx));
+ break;
case LYD_LYB:
- return lyd_parse_lyb_data(ctx, in, parse_options, validate_options, tree);
+ LY_CHECK_RET(lyd_parse_lyb_data(ctx, in, parse_options, validate_options, tree, &lydctx));
+ break;
case LYD_SCHEMA:
LOGINT_RET(ctx);
}
- /* TODO move here the top-level validation from parser_xml.c's lyd_parse_xml_data() and make
- * it common for all the lyd_parse_*_data() functions */
+ if (!(parse_options & LYD_PARSE_ONLY)) {
+ uint32_t i = 0;
+ const struct lys_module *mod;
+ struct lyd_node *first, *next, **first2;
- LOGINT_RET(ctx);
+ next = *tree;
+ while (1) {
+ if (validate_options & LYD_VALIDATE_PRESENT) {
+ mod = lyd_data_next_module(&next, &first);
+ } else {
+ mod = lyd_mod_next_module(next, NULL, ctx, &i, &first);
+ }
+ if (!mod) {
+ break;
+ }
+ if (first == *tree) {
+ /* make sure first2 changes are carried to tree */
+ first2 = tree;
+ } else {
+ first2 = &first;
+ }
+
+ /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
+ LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod, NULL), cleanup);
+
+ /* add all top-level defaults for this module */
+ ret = lyd_new_implicit_r(NULL, first2, NULL, mod, &lydctx->unres_node_type, &lydctx->when_check,
+ (validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* finish incompletely validated terminal values/attributes and when conditions */
+ ret = lyd_validate_unres(tree, &lydctx->when_check, &lydctx->unres_node_type, &lydctx->unres_meta_type, LYD_XML,
+ lydctx->resolve_prefix, lydctx->data_ctx, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* perform final validation that assumes the data tree is final */
+ LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, validate_options, 0), cleanup);
+ }
+ }
+
+cleanup:
+ lydctx->free((struct lyd_ctx *)lydctx);
+ if (ret) {
+ lyd_free_all(*tree);
+ *tree = NULL;
+ }
+ return ret;
}
API LY_ERR
@@ -404,16 +452,20 @@
format = lyd_parse_get_format(in, format);
LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
+ /* init */
+ *tree = NULL;
+ if (op) {
+ *op = NULL;
+ }
+
/* remember input position */
in->func_start = in->current;
switch (format) {
case LYD_XML:
return lyd_parse_xml_rpc(ctx, in, tree, op);
-#if 0
case LYD_JSON:
return lyd_parse_json_rpc(ctx, in, tree, op);
-#endif
case LYD_LYB:
return lyd_parse_lyb_rpc(ctx, in, tree, op);
case LYD_SCHEMA:
@@ -428,21 +480,27 @@
struct lyd_node **op)
{
LY_CHECK_ARG_RET(NULL, request, LY_EINVAL);
- LY_CHECK_ARG_RET(LYD_NODE_CTX(request), in, tree, LY_EINVAL);
+ LY_CHECK_ARG_RET(LYD_NODE_CTX(request), in, tree || op, LY_EINVAL);
format = lyd_parse_get_format(in, format);
LY_CHECK_ARG_RET(LYD_NODE_CTX(request), format, LY_EINVAL);
+ /* init */
+ if (tree) {
+ *tree = NULL;
+ }
+ if (op) {
+ *op = NULL;
+ }
+
/* remember input position */
in->func_start = in->current;
switch (format) {
case LYD_XML:
return lyd_parse_xml_reply(request, in, tree, op);
-#if 0
case LYD_JSON:
return lyd_parse_json_reply(request, in, tree, op);
-#endif
case LYD_LYB:
return lyd_parse_lyb_reply(request, in, tree, op);
case LYD_SCHEMA:
@@ -455,21 +513,27 @@
API LY_ERR
lyd_parse_notif(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **ntf)
{
- LY_CHECK_ARG_RET(ctx, ctx, in, tree, LY_EINVAL);
+ LY_CHECK_ARG_RET(ctx, ctx, in, tree || ntf, LY_EINVAL);
format = lyd_parse_get_format(in, format);
LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
+ /* init */
+ if (tree) {
+ *tree = NULL;
+ }
+ if (ntf) {
+ *ntf = NULL;
+ }
+
/* remember input position */
in->func_start = in->current;
switch (format) {
case LYD_XML:
return lyd_parse_xml_notif(ctx, in, tree, ntf);
-#if 0
case LYD_JSON:
return lyd_parse_json_notif(ctx, in, tree, ntf);
-#endif
case LYD_LYB:
return lyd_parse_lyb_notif(ctx, in, tree, ntf);
case LYD_SCHEMA:
@@ -480,8 +544,8 @@
}
LY_ERR
-lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
- ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
+lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic, int value_hint,
+ ly_resolve_prefix_clb get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
{
LY_ERR ret;
struct lyd_node_term *term;
@@ -495,7 +559,7 @@
term->prev = (struct lyd_node *)term;
term->flags = LYD_NEW;
- ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
+ ret = lyd_value_parse(term, value, value_len, dynamic, 0, value_hint, get_prefix, prefix_data, format, NULL);
if (ret && (ret != LY_EINCOMPLETE)) {
free(term);
return ret;
@@ -630,7 +694,8 @@
any->prev = (struct lyd_node *)any;
any->flags = LYD_NEW;
- any->value.xml = value;
+ /* TODO: convert XML/JSON strings into a opaq data tree */
+ any->value.str = value;
any->value_type = value_type;
lyd_hash((struct lyd_node *)any);
@@ -640,12 +705,12 @@
LY_ERR
lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
- int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
- const char *ns, struct lyd_node **node)
+ int *dynamic, int value_hint, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
+ const char *module_key, size_t module_key_len, struct lyd_node **node)
{
struct lyd_node_opaq *opaq;
- assert(ctx && name && name_len && ns);
+ assert(ctx && name && name_len);
if (!value_len) {
value = "";
@@ -659,9 +724,12 @@
opaq->name = lydict_insert(ctx, name, name_len);
opaq->format = format;
if (pref_len) {
- opaq->prefix.pref = lydict_insert(ctx, prefix, pref_len);
+ opaq->prefix.id = lydict_insert(ctx, prefix, pref_len);
}
- opaq->prefix.ns = lydict_insert(ctx, ns, 0);
+ if (module_key_len) {
+ opaq->prefix.module_ns = lydict_insert(ctx, module_key, module_key_len);
+ }
+
opaq->val_prefs = val_prefs;
if (dynamic && *dynamic) {
opaq->value = lydict_insert_zc(ctx, (char *)value);
@@ -669,6 +737,7 @@
} else {
opaq->value = lydict_insert(ctx, value, value_len);
}
+ opaq->hint = value_hint;
opaq->ctx = ctx;
*node = (struct lyd_node *)opaq;
@@ -731,7 +800,7 @@
for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
key_val = va_arg(ap, const char *);
- rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
+ rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, 0, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
rc = LY_SUCCESS;
lyd_insert_node(ret, NULL, key);
@@ -808,7 +877,7 @@
schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, 0);
LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), LY_ENOTFOUND);
- rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret);
+ rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, 0, lydjson_resolve_prefix, NULL, LYD_JSON, &ret);
LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), rc);
if (parent) {
lyd_insert_node(parent, NULL, ret);
@@ -952,7 +1021,7 @@
val_str = "";
}
- LY_CHECK_RET(lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL,
+ LY_CHECK_RET(lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL, 0,
lydjson_resolve_prefix, NULL, LYD_JSON, parent->schema));
if (meta) {
@@ -976,8 +1045,8 @@
value = "";
}
- LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LYD_JSON, NULL, NULL, 0,
- module_name, &ret));
+ LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, 0,
+ LYD_JSON, NULL, NULL, 0, module_name, strlen(module_name), &ret));
if (parent) {
lyd_insert_node(parent, NULL, ret);
}
@@ -990,9 +1059,9 @@
API LY_ERR
lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str,
- struct ly_attr **attr)
+ struct lyd_attr **attr)
{
- struct ly_attr *ret = NULL;
+ struct lyd_attr *ret = NULL;
const struct ly_ctx *ctx;
const char *prefix, *tmp;
size_t pref_len, name_len;
@@ -1013,8 +1082,8 @@
val_str = "";
}
- LY_CHECK_RET(ly_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LYD_JSON, NULL,
- prefix, pref_len, module_name));
+ LY_CHECK_RET(lyd_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, 0, LYD_JSON, NULL,
+ prefix, pref_len, module_name, module_name ? strlen(module_name) : 0));
if (attr) {
*attr = ret;
@@ -1117,7 +1186,7 @@
/* parse the new value into a new meta structure */
LY_CHECK_GOTO(ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str,
- strlen(val_str), NULL, lydjson_resolve_prefix, NULL, LYD_JSON, NULL), cleanup);
+ strlen(val_str), NULL, 0, lydjson_resolve_prefix, NULL, LYD_JSON, NULL), cleanup);
/* compare original and new value */
if (lyd_compare_meta(meta, m2)) {
@@ -1238,8 +1307,9 @@
if (!(schema->flags & LYS_KEYLESS)) {
if ((options & LYD_NEWOPT_OPAQ) && (p[path_idx].pred_type == LY_PATH_PREDTYPE_NONE)) {
/* creating opaque list without keys */
- LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL,
- LYD_JSON, NULL, NULL, 0, schema->module->name, &node), cleanup);
+ LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, 0,
+ LYD_JSON, NULL, NULL, 0, schema->module->name, strlen(schema->module->name), &node),
+ cleanup);
} else {
assert(p[path_idx].pred_type == LY_PATH_PREDTYPE_LIST);
LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, &node), cleanup);
@@ -1256,8 +1326,9 @@
case LYS_LEAFLIST:
if ((options & LYD_NEWOPT_OPAQ) && (p[path_idx].pred_type == LY_PATH_PREDTYPE_NONE)) {
/* creating opaque leaf-list without value */
- LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL,
- LYD_JSON, NULL, NULL, 0, schema->module->name, &node), cleanup);
+ LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, 0,
+ LYD_JSON, NULL, NULL, 0, schema->module->name, strlen(schema->module->name), &node),
+ cleanup);
} else {
assert(p[path_idx].pred_type == LY_PATH_PREDTYPE_LEAFLIST);
LY_CHECK_GOTO(ret = lyd_create_term2(schema, &p[path_idx].predicates[0].value, &node), cleanup);
@@ -1274,12 +1345,13 @@
r = lys_value_validate(NULL, schema, value, strlen(value));
}
if (!r) {
- LY_CHECK_GOTO(ret = lyd_create_term(schema, value, strlen(value), NULL, lydjson_resolve_prefix, NULL,
+ LY_CHECK_GOTO(ret = lyd_create_term(schema, value, strlen(value), NULL, 0, lydjson_resolve_prefix, NULL,
LYD_JSON, &node), cleanup);
} else {
/* creating opaque leaf without value */
- LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL,
- LYD_JSON, NULL, NULL, 0, schema->module->name, &node), cleanup);
+ LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, 0,
+ LYD_JSON, NULL, NULL, 0, schema->module->name, strlen(schema->module->name), &node),
+ cleanup);
}
break;
case LYS_ANYDATA:
@@ -2030,8 +2102,37 @@
}
LY_ERR
+lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta)
+{
+ struct lyd_meta *last, *iter;
+
+ assert(parent);
+ assert(meta);
+
+ for (iter = meta; iter; iter = iter->next) {
+ iter->parent = parent;
+ }
+
+ /* insert as the last attribute */
+ if (parent->meta) {
+ for (last = parent->meta; last->next; last = last->next);
+ last->next = meta;
+ } else {
+ parent->meta = meta;
+ }
+
+ /* remove default flags from NP containers */
+ while (parent && (parent->schema->nodetype == LYS_CONTAINER) && (parent->flags & LYD_DEFAULT)) {
+ parent->flags &= ~LYD_DEFAULT;
+ parent = (struct lyd_node *)parent->parent;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
- size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix resolve_prefix,
+ size_t name_len, const char *value, size_t value_len, int *dynamic, int value_hint, ly_resolve_prefix_clb resolve_prefix,
void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
{
LY_ERR ret;
@@ -2060,7 +2161,7 @@
LY_CHECK_ERR_RET(!mt, LOGMEM(mod->ctx), LY_EMEM);
mt->parent = parent;
mt->annotation = ant;
- ret = lyd_value_parse_meta(mod->ctx, mt, value, value_len, dynamic, 0, resolve_prefix, prefix_data, format, ctx_snode, NULL);
+ ret = lyd_value_parse_meta(mod->ctx, mt, value, value_len, dynamic, 0, value_hint, resolve_prefix, prefix_data, format, ctx_snode, NULL);
if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
free(mt);
return ret;
@@ -2069,23 +2170,12 @@
/* insert as the last attribute */
if (parent) {
- if (parent->meta) {
- for (last = parent->meta; last->next; last = last->next);
- last->next = mt;
- } else {
- parent->meta = mt;
- }
+ LY_CHECK_RET(lyd_insert_meta(parent, mt))
} else if (*meta) {
for (last = *meta; last->next; last = last->next);
last->next = mt;
}
- /* remove default flags from NP containers */
- while (parent && (parent->schema->nodetype == LYS_CONTAINER) && (parent->flags & LYD_DEFAULT)) {
- parent->flags &= ~LYD_DEFAULT;
- parent = (struct lyd_node *)parent->parent;
- }
-
if (meta) {
*meta = mt;
}
@@ -2093,16 +2183,15 @@
}
LY_ERR
-ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
- size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
- struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns)
+lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct ly_ctx *ctx, const char *name,
+ size_t name_len, const char *value, size_t value_len, int *dynamic, int value_hint, LYD_FORMAT format,
+ struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *module_key, size_t module_key_len)
{
- struct ly_attr *at, *last;
+ struct lyd_attr *at, *last;
struct lyd_node_opaq *opaq;
assert(ctx && (parent || attr) && (!parent || !parent->schema));
assert(name && name_len);
- assert((prefix_len && ns) || (!prefix_len && !ns));
if (!value_len) {
value = "";
@@ -2119,11 +2208,14 @@
at->value = lydict_insert(ctx, value, value_len);
}
+ at->hint = value_hint;
at->format = format;
at->val_prefs = val_prefs;
- if (ns) {
- at->prefix.pref = lydict_insert(ctx, prefix, prefix_len);
- at->prefix.ns = lydict_insert(ctx, ns, 0);
+ if (prefix_len) {
+ at->prefix.id = lydict_insert(ctx, prefix, prefix_len);
+ }
+ if (module_key_len) {
+ at->prefix.module_ns = lydict_insert(ctx, module_key, module_key_len);
}
/* insert as the last attribute */
@@ -2187,7 +2279,7 @@
if (!node1->schema) {
opaq1 = (struct lyd_node_opaq *)node1;
opaq2 = (struct lyd_node_opaq *)node2;
- if ((opaq1->name != opaq2->name) || (opaq1->prefix.ns != opaq2->prefix.ns) || (opaq1->format != opaq2->format)) {
+ if ((opaq1->name != opaq2->name) || (opaq1->format != opaq2->format) || (opaq1->prefix.module_ns != opaq2->prefix.module_ns)) {
return LY_ENOT;
}
switch (opaq1->format) {
@@ -2196,6 +2288,12 @@
return LY_ENOT;
}
break;
+ case LYD_JSON:
+ /* prefixes in JSON are unique, so it is not necessary to canonize the values */
+ if (strcmp(opaq1->value, opaq2->value)) {
+ return LY_ENOT;
+ }
+ break;
case LYD_SCHEMA:
case LYD_LYB:
/* not allowed */
@@ -2438,17 +2536,15 @@
}
opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
opaq->format = orig->format;
- if (orig->prefix.pref) {
- opaq->prefix.pref = lydict_insert(LYD_NODE_CTX(node), orig->prefix.pref, 0);
+ if (orig->prefix.id) {
+ opaq->prefix.id = lydict_insert(LYD_NODE_CTX(node), orig->prefix.id, 0);
}
- if (orig->prefix.ns) {
- opaq->prefix.ns = lydict_insert(LYD_NODE_CTX(node), orig->prefix.ns, 0);
- }
+ opaq->prefix.module_ns = lydict_insert(LYD_NODE_CTX(node), orig->prefix.module_ns, 0);
if (orig->val_prefs) {
LY_ARRAY_CREATE_GOTO(LYD_NODE_CTX(node), opaq->val_prefs, LY_ARRAY_COUNT(orig->val_prefs), ret, error);
LY_ARRAY_FOR(orig->val_prefs, u) {
- opaq->val_prefs[u].pref = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].pref, 0);
- opaq->val_prefs[u].ns = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].ns, 0);
+ opaq->val_prefs[u].id = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].id, 0);
+ opaq->val_prefs[u].module_ns = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].module_ns, 0);
LY_ARRAY_INCREMENT(opaq->val_prefs);
}
}
@@ -2954,22 +3050,23 @@
iter_print:
/* print prefix and name */
mod = NULL;
- if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
+ if (iter->schema && (!iter->parent || iter->schema->module != iter->parent->schema->module)) {
mod = iter->schema->module;
}
/* realloc string */
- len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
+ len = 1 + (mod ? strlen(mod->name) + 1 : 0) + (iter->schema ? strlen(iter->schema->name) : strlen(((struct lyd_node_opaq*)iter)->name));
rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
if (rc != LY_SUCCESS) {
break;
}
/* print next node */
- bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
+ bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "",
+ iter->schema ? iter->schema->name : ((struct lyd_node_opaq*)iter)->name);
/* do not always print the last (first) predicate */
- if (bufused || (pathtype == LYD_PATH_LOG)) {
+ if (iter->schema && (bufused || (pathtype == LYD_PATH_LOG))) {
switch (iter->schema->nodetype) {
case LYS_LIST:
if (iter->schema->flags & LYS_KEYLESS) {
@@ -3216,7 +3313,7 @@
/* create a data node and find the instance */
if (schema->nodetype == LYS_LEAFLIST) {
/* target used attributes: schema, hash, value */
- rc = lyd_create_term(schema, key_or_value, val_len, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &target);
+ rc = lyd_create_term(schema, key_or_value, val_len, NULL, 0, lydjson_resolve_prefix, NULL, LYD_JSON, &target);
LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), rc);
} else {
/* target used attributes: schema, hash, child (all keys) */
diff --git a/src/tree_data.h b/src/tree_data.h
index 58f5aeb..4aa13f5 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -194,6 +194,7 @@
} *prefixes; /**< list of mappings between prefix in canonized value to a YANG schema ([sized array](@ref sizedarrays)) */
struct lyd_value *value; /**< representation of the value according to the selected union's subtype (stored as lyd_value::realpath
here, in subvalue structure */
+ int parser_hint; /**< Hint options from the parser */
} *subvalue; /**< data to represent data with multiple types (union). Original value is stored in the main
lyd_value:canonical_cache while the lyd_value_subvalue::value contains representation according to the
one of the union's type. The lyd_value_subvalue:prefixes provides (possible) mappings from prefixes
@@ -238,23 +239,31 @@
/**
* @brief Generic prefix and namespace mapping, meaning depends on the format.
+ *
+ * The union is used as a reference to the data's module and according to the format, it can be used as a key for
+ * ly_ctx_get_module_implemented_ns() or ly_ctx_get_module_implemented(). While the module reference is always present,
+ * the id member can be omitted in case it is not present in the source data as a reference to the default namespace.
*/
struct ly_prefix {
- const char *pref;
- const char *ns;
+ const char *id; /**< identifier used in the qualified name of the item to reference data node namespace */
+ union {
+ const char *module_ns; /**< namespace of the module where the data are supposed to belongs to, used for LYD_XML format. */
+ const char *module_name; /**< name of the module where the data are supposed to belongs to, used for LYD_JSON format. */
+ };
};
/**
* @brief Generic attribute structure.
*/
-struct ly_attr {
+struct lyd_attr {
struct lyd_node_opaq *parent; /**< data node where the attribute is placed */
- struct ly_attr *next;
+ struct lyd_attr *next;
struct ly_prefix *val_prefs; /**< list of prefixes in the value ([sized array](@ref sizedarrays)) */
const char *name;
const char *value;
LYD_FORMAT format;
+ int hint; /**< additional information about from the data source, see the [hints list](@ref lydopaqhints) */
struct ly_prefix prefix; /**< name prefix, it is stored because they are a real pain to generate properly */
};
@@ -293,6 +302,37 @@
/** @} */
/**
+ * @brief Callback provided by the data/schema parsers to type plugins to resolve (format-specific) mapping between prefixes used
+ * in the value strings to the YANG schemas.
+ *
+ * Reverse function to ly_get_prefix_clb.
+ *
+ * XML uses XML namespaces, JSON uses schema names as prefixes, YIN/YANG uses prefixes of the imports.
+ *
+ * @param[in] ctx libyang context to find the schema.
+ * @param[in] prefix Prefix found in the value string
+ * @param[in] prefix_len Length of the @p prefix.
+ * @param[in] private Internal data needed by the callback.
+ * @return Pointer to the YANG schema identified by the provided prefix or NULL if no mapping found.
+ */
+typedef const struct lys_module *(*ly_resolve_prefix_clb)(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len,
+ void *private);
+
+/**
+ * @brief Callback provided by the data/schema printers to type plugins to resolve (format-specific) mapping between YANG module of a data object
+ * to prefixes used in the value strings.
+ *
+ * Reverse function to ly_resolve_prefix_clb.
+ *
+ * XML uses XML namespaces, JSON uses schema names as prefixes, YIN/YANG uses prefixes of the imports.
+ *
+ * @param[in] mod YANG module of the object.
+ * @param[in] private Internal data needed by the callback.
+ * @return String representing prefix for the object of the given YANG module @p mod.
+ */
+typedef const char *(*ly_get_prefix_clb)(const struct lys_module *mod, void *private);
+
+/**
* @brief Generic structure for a data node.
*/
struct lyd_node {
@@ -401,6 +441,23 @@
};
/**
+ * @defgroup lydopaqhints Opaq data node hints.
+ *
+ * Additional information about the opaq nodes from their source. The flags are stored in lyd_node_opaq::hint
+ * and they can have a slightly different meaning for the specific lyd_node_opaq::format.
+ * @{
+ */
+#define LYD_NODE_OPAQ_ISLIST 0x001 /**< LYD_JSON: node is expected to be a list or leaf-list */
+#define LYD_NODE_OPAQ_ISENVELOPE 0x002 /**< LYD_JSON, LYD_XML: RPC/Action/Notification envelope out of the YANG schemas */
+
+#define LYD_NODE_OPAQ_ISSTRING 0x100 /**< LYD_JSON: value is expected to be string as defined in JSON encoding. */
+#define LYD_NODE_OPAQ_ISNUMBER 0x200 /**< LYD_JSON: value is expected to be number as defined in JSON encoding. */
+#define LYD_NODE_OPAQ_ISBOOLEAN 0x400 /**< LYD_JSON: value is expected to be boolean as defined in JSON encoding. */
+#define LYD_NODE_OPAQ_ISEMPTY 0x800 /**< LYD_JSON: value is expected to be empty as defined in JSON encoding. */
+
+/** @} lydopaqhints */
+
+/**
* @brief Data node structure for unparsed (opaque) nodes.
*/
struct lyd_node_opaq {
@@ -410,7 +467,7 @@
struct lyd_node *parent; /**< pointer to the parent node (NULL in case of root node) */
struct lyd_node *next; /**< pointer to the next sibling node (NULL if there is no one) */
struct lyd_node *prev; /**< pointer to the previous sibling node (last sibling if there is none) */
- struct ly_attr *attr;
+ struct lyd_attr *attr;
#ifdef LY_ENABLED_LYD_PRIV
void *priv; /**< private user data, not used by libyang */
@@ -422,6 +479,7 @@
struct ly_prefix prefix; /**< name prefix */
struct ly_prefix *val_prefs; /**< list of prefixes in the value ([sized array](@ref sizedarrays)) */
const char *value; /**< original value */
+ int hint; /**< additional information about from the data source, see the [hints list](@ref lydopaqhints) */
const struct ly_ctx *ctx; /**< libyang context */
};
@@ -580,7 +638,7 @@
* @return LY_ERR value.
*/
LY_ERR lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str,
- struct ly_attr **attr);
+ struct lyd_attr **attr);
/**
* @defgroup pathoptions Data path creation options
@@ -845,7 +903,7 @@
* @param[in] ctx Context where the attributes were created.
* @param[in] attr Attribute to free.
*/
-void ly_free_attr_single(const struct ly_ctx *ctx, struct ly_attr *attr);
+void ly_free_attr_single(const struct ly_ctx *ctx, struct lyd_attr *attr);
/**
* @brief Free the attribute with any following attributes.
@@ -853,7 +911,7 @@
* @param[in] ctx Context where the attributes were created.
* @param[in] attr First attribute to free.
*/
-void ly_free_attr_siblings(const struct ly_ctx *ctx, struct ly_attr *attr);
+void ly_free_attr_siblings(const struct ly_ctx *ctx, struct lyd_attr *attr);
/**
* @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 7cd1283..519ce06 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -78,9 +78,9 @@
}
static void
-ly_free_attr(const struct ly_ctx *ctx, struct ly_attr *attr, int siblings)
+ly_free_attr(const struct ly_ctx *ctx, struct lyd_attr *attr, int siblings)
{
- struct ly_attr *iter;
+ struct lyd_attr *iter;
LY_ARRAY_COUNT_TYPE u;
LY_CHECK_ARG_RET(NULL, ctx, );
@@ -116,26 +116,26 @@
iter = iter->next;
LY_ARRAY_FOR(attr->val_prefs, u) {
- FREE_STRING(ctx, attr->val_prefs[u].pref);
- FREE_STRING(ctx, attr->val_prefs[u].ns);
+ FREE_STRING(ctx, attr->val_prefs[u].id);
+ FREE_STRING(ctx, attr->val_prefs[u].module_ns);
}
LY_ARRAY_FREE(attr->val_prefs);
FREE_STRING(ctx, attr->name);
FREE_STRING(ctx, attr->value);
- FREE_STRING(ctx, attr->prefix.pref);
- FREE_STRING(ctx, attr->prefix.ns);
+ FREE_STRING(ctx, attr->prefix.id);
+ FREE_STRING(ctx, attr->prefix.module_ns);
free(attr);
}
}
API void
-ly_free_attr_single(const struct ly_ctx *ctx, struct ly_attr *attr)
+ly_free_attr_single(const struct ly_ctx *ctx, struct lyd_attr *attr)
{
ly_free_attr(ctx, attr, 0);
}
API void
-ly_free_attr_siblings(const struct ly_ctx *ctx, struct ly_attr *attr)
+ly_free_attr_siblings(const struct ly_ctx *ctx, struct lyd_attr *attr)
{
ly_free_attr(ctx, attr, 1);
}
@@ -146,8 +146,8 @@
LY_ARRAY_COUNT_TYPE u;
LY_ARRAY_FOR(val_prefs, u) {
- FREE_STRING(ctx, val_prefs[u].pref);
- FREE_STRING(ctx, val_prefs[u].ns);
+ FREE_STRING(ctx, val_prefs[u].id);
+ FREE_STRING(ctx, val_prefs[u].module_ns);
}
LY_ARRAY_FREE(val_prefs);
}
@@ -176,8 +176,8 @@
}
FREE_STRING(LYD_NODE_CTX(opaq), opaq->name);
- FREE_STRING(LYD_NODE_CTX(opaq), opaq->prefix.pref);
- FREE_STRING(LYD_NODE_CTX(opaq), opaq->prefix.ns);
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->prefix.id);
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->prefix.module_ns);
ly_free_val_prefs(LYD_NODE_CTX(opaq), opaq->val_prefs);
FREE_STRING(LYD_NODE_CTX(opaq), opaq->value);
} else if (node->schema->nodetype & LYD_NODE_INNER) {
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 0e8a17b..3dce35c 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -188,7 +188,7 @@
key = lyd_node_children(node, 0);
while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
if (!key || (key->schema != skey)) {
- LOGVAL(node->schema->module->ctx, LY_VLOG_LYD, node, LY_VCODE_NOKEY, skey->name);
+ LOGVAL(LYD_NODE_CTX(node), LY_VLOG_LYD, node, LY_VCODE_NOKEY, skey->name);
return LY_EVALID;
}
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index eb934ca..7911fe0 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -94,6 +94,7 @@
* @param[in] value String value to be parsed.
* @param[in] value_len Length of @p value, must be set correctly.
* @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
+ * @param[in] value_hint [Hint options](@ref lydvalueparseopts) from the parser regarding the value type.
* @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
* @param[in] prefix_data User data for @p get_prefix.
* @param[in] format Input format of @p value.
@@ -102,8 +103,8 @@
* @return LY_EINCOMPLETE in case data tree is needed to finish the validation.
* @return LY_ERR value if an error occurred.
*/
-LY_ERR lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
- ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node);
+LY_ERR lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic, int value_hint,
+ ly_resolve_prefix_clb get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node);
/**
* @brief Create a term (leaf/leaf-list) node from a parsed value by duplicating it.
@@ -169,18 +170,20 @@
* @param[in] value String value to be parsed.
* @param[in] value_len Length of @p value, must be set correctly.
* @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
+ * @param[in] value_hint [Value hint](@ref lydvalueparseopts) from the parser regarding the value type.
* @param[in] format Input format of @p value and @p ns.
* @param[in] val_prefs Possible value prefixes, array is spent.
* @param[in] prefix Element prefix.
* @param[in] pref_len Length of @p prefix, must be set correctly.
- * @param[in] ns Node namespace, meaning depends on @p format.
+ * @param[in] module_key Mandatory key to reference module, can be namespace or name.
+ * @param[in] module_key_len Length of @p module_key, must be set correctly.
* @param[out] node Created node.
* @return LY_SUCCESS on success.
* @return LY_ERR value if an error occurred.
*/
LY_ERR lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
- int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
- const char *ns, struct lyd_node **node);
+ int *dynamic, int value_hint, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
+ const char *module_key, size_t module_key_len, struct lyd_node **node);
/**
* @brief Check the existence and create any non-existing implicit siblings, recursively for the created nodes.
@@ -229,6 +232,7 @@
* @param[in] value String value to be parsed.
* @param[in] value_len Length of @p value, must be set correctly.
* @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
+ * @param[in] value_hint [Value hint](@ref lydvalueparseopts) from the parser regarding the value type.
* @param[in] resolve_prefix Parser-specific getter to resolve prefixes used in the @p value string.
* @param[in] prefix_data User data for @p get_prefix.
* @param[in] format Input format of @p value.
@@ -238,8 +242,17 @@
* @return LY_ERR value if an error occurred.
*/
LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
- size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix resolve_prefix,
- void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode);
+ size_t name_len, const char *value, size_t value_len, int *dynamic, int value_hint,
+ ly_resolve_prefix_clb resolve_prefix, void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode);
+
+/**
+ * @brief Insert a metadata (last) into a parent
+ *
+ * @param[in] parent Parent of the metadata.
+ * @param[in] meta Metadata (list) to be added into the @p parent.
+ * @return LY_SUCCESS on success.
+ */
+LY_ERR lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta);
/**
* @brief Create and insert a generic attribute (last) into a parent.
@@ -252,17 +265,32 @@
* @param[in] value String value to be parsed.
* @param[in] value_len Length of @p value, must be set correctly.
* @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
+ * @param[in] value_hint [Value hint](@ref lydvalueparseopts) from the parser regarding the value type.
* @param[in] format Input format of @p value and @p ns.
* @param[in] val_prefs Possible value prefixes, array is spent.
* @param[in] prefix Attribute prefix.
* @param[in] prefix_len Attribute prefix length.
- * @param[in] ns Attribute namespace, meaning depends on @p format.
+ * @param[in] module_key Mandatory key to reference module, can be namespace or name.
+ * @param[in] module_key_len Length of @p module_key, must be set correctly.
* @return LY_SUCCESS on success.
* @return LY_ERR value if an error occurred.
*/
-LY_ERR ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
- size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
- struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns);
+LY_ERR lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct ly_ctx *ctx, const char *name,
+ size_t name_len, const char *value, size_t value_len, int *dynamic, int value_hint, LYD_FORMAT format,
+ struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *module_key, size_t module_key_len);
+
+/**
+ * @defgroup lydvalueparseopts Hint options for type plugin callbacks from the data parsers.
+ *
+ * Options applicable to ly_value_parse()
+ * @{
+ */
+#define LYD_VALUE_PARSE_ISSTRING LY_TYPE_OPTS_ISSTRING /**< The input value is supposed to be a string. */
+#define LYD_VALUE_PARSE_ISNUMBER LY_TYPE_OPTS_ISNUMBER /**< The input value is supposed to be a number. */
+#define LYD_VALUE_PARSE_ISBOOLEAN LY_TYPE_OPTS_ISBOOLEAN /**< The input value is supposed to be a boolean. */
+#define LYD_VALUE_PARSE_ISEMPTY LY_TYPE_OPTS_ISEMPTY /**< The input value is supposed to be empty type. */
+
+/** @} lydvalueparseopts */
/**
* @brief Validate, canonize and store the given @p value into the node according to the node's type's rules.
@@ -272,6 +300,7 @@
* @param[in] value_len Length of the give @p value, must be set correctly.
* @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
* @param[in] second Flag for the second call after returning LY_EINCOMPLETE
+ * @param[in] value_hint [Value hint](@ref lydvalueparseopts) from the parser.
* @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
* @param[in] parser Parser's data for @p get_prefix
* @param[in] format Input format of @p value.
@@ -282,12 +311,12 @@
* @return LY_EINCOMPLETE in case the @p trees is not provided and it was needed to finish the validation.
* @return LY_ERR value if an error occurred.
*/
-LY_ERR lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
- ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree);
+LY_ERR lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second, int value_hint,
+ ly_resolve_prefix_clb get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree);
/* similar to lyd_value_parse except can be used just to store the value, hence does also not support a second call */
LY_ERR lyd_value_store(struct lyd_value *val, const struct lysc_node *schema, const char *value, size_t value_len,
- int *dynamic, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format);
+ int *dynamic, ly_resolve_prefix_clb get_prefix, void *parser, LYD_FORMAT format);
/**
* @brief Validate, canonize and store the given @p value into the metadata according to the annotation type's rules.
@@ -298,6 +327,7 @@
* @param[in] value_len Length of the give @p value, must be set correctly.
* @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
* @param[in] second Flag for the second call after returning LY_EINCOMPLETE
+ * @param[in] value_hint [Value hint](@ref lydvalueparseopts) from the parser.
* @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
* @param[in] parser Parser's data for @p get_prefix
* @param[in] format Input format of the data.
@@ -310,8 +340,8 @@
* @return LY_ERR value if an error occurred.
*/
LY_ERR lyd_value_parse_meta(const struct ly_ctx *ctx, struct lyd_meta *meta, const char *value, size_t value_len,
- int *dynamic, int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
- const struct lysc_node *ctx_snode, const struct lyd_node *tree);
+ int *dynamic, int second, int value_hint, ly_resolve_prefix_clb get_prefix, void *parser,
+ LYD_FORMAT format, const struct lysc_node *ctx_snode, const struct lyd_node *tree);
/* generic function lys_value_validate */
LY_ERR _lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
@@ -324,11 +354,12 @@
* @param[in] in Input structure.
* @param[in] parse_options Options for parser, see @ref dataparseroptions.
* @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
- * @param[out] tree Parsed data tree. Note that NULL can be a valid result.
+ * @param[out] tree_p Parsed data tree. Note that NULL can be a valid result.
+ * @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
- struct lyd_node **tree);
+ struct lyd_node **tree_p, struct lyd_ctx **lydctx_p);
/**
* @brief Parse XML string as YANG RPC/action invocation.
@@ -339,11 +370,11 @@
*
* @param[in] ctx libyang context.
* @param[in] in Input structure.
- * @param[out] tree Parsed full RPC/action tree.
- * @param[out] op Optional pointer to the actual operation. Useful mainly for action.
+ * @param[out] tree_p Parsed full RPC/action tree.
+ * @param[out] op_p Optional pointer to the actual operation. Useful mainly for action.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_xml_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op);
+LY_ERR lyd_parse_xml_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p);
/**
* @brief Parse XML string as YANG notification.
@@ -353,11 +384,11 @@
*
* @param[in] ctx libyang context.
* @param[in] in Input structure.
- * @param[out] tree Parsed full notification tree.
- * @param[out] op Optional pointer to the actual notification. Useful mainly for nested notifications.
+ * @param[out] tree_p Parsed full notification tree.
+ * @param[out] op_p Optional pointer to the actual notification. Useful mainly for nested notifications.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_xml_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **ntf);
+LY_ERR lyd_parse_xml_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p);
/**
* @brief Parse XML string as YANG RPC/action reply.
@@ -367,11 +398,67 @@
*
* @param[in] request Data tree of the RPC/action request.
* @param[in] in Input structure.
- * @param[out] tree Parsed full reply tree. It always includes duplicated operation and parents of the @p request.
- * @param[out] op Optional pointer to the reply operation. Useful mainly for action.
+ * @param[out] tree_p Parsed full reply tree. It always includes duplicated operation and parents of the @p request.
+ * @param[out] op_p Optional pointer to the reply operation. Useful mainly for action.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_xml_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op);
+LY_ERR lyd_parse_xml_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p);
+
+/**
+ * @brief Parse JSON string as YANG data tree.
+ *
+ * @param[in] ctx libyang context
+ * @param[in] in Input structure.
+ * @param[in] parse_options Options for parser, see @ref dataparseroptions.
+ * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
+ * @param[out] tree_p Parsed data tree. Note that NULL can be a valid result.
+ * @param[out] lydctx_p Data parser context to finish validation.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_json_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
+ struct lyd_node **tree_p, struct lyd_ctx **lydctx_p);
+
+/**
+ * @brief Parse JSON string as YANG notification.
+ *
+ * Optional top-level "notification" envelope object, if present, is [checked](https://tools.ietf.org/html/rfc5277#page-25)
+ * and parsed. Specifically the child "eventTime" member and its value.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] in Input structure.
+ * @param[out] tree_p Parsed full notification tree.
+ * @param[out] ntf_p Optional pointer to the actual notification. Useful mainly for nested notifications.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_json_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p);
+
+/**
+ * @brief Parse JSON string as YANG RPC/action invocation.
+ *
+ * Optional top-level "rpc" envelope object, if present is is [checked](https://tools.ietf.org/html/rfc6241#section-4.1) and the parser
+ * goes inside for the content, which is an RPC data or "action" envelope objects. The "action" envelope object is
+ * also [checked](https://tools.ietf.org/html/rfc7950#section-7.15.2) and then an action data is expected as a content of this envelope.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] in Input structure.
+ * @param[out] tree_p Parsed full RPC/action tree.
+ * @param[out] op_p Optional pointer to the actual operation. Useful mainly for action.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_json_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p);
+
+/**
+ * @brief Parse JSON string as YANG RPC/action reply.
+ *
+ * Optional "rpc-reply" envelope object, if present, is [checked](https://tools.ietf.org/html/rfc6241#section-4.2).
+ *
+ * @param[in] request Data tree of the RPC/action request.
+ * @param[in] in Input structure.
+ * @param[out] tree_p Parsed full reply tree. It always includes duplicated operation and parents of the @p request.
+ * @param[out] op_p Optional pointer to the reply operation. Useful mainly for action.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_json_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p);
/**
* @brief Parse binary data as YANG data tree.
@@ -380,44 +467,45 @@
* @param[in] in Input structure.
* @param[in] parse_options Options for parser, see @ref dataparseroptions.
* @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
- * @param[out] tree Parsed data tree. Note that NULL can be a valid result.
+ * @param[out] tree_p Parsed data tree. Note that NULL can be a valid result.
+ * @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_lyb_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
- struct lyd_node **tree);
+ struct lyd_node **tree_p, struct lyd_ctx **lydctx_p);
/**
* @brief Parse binary data as YANG RPC/action invocation.
*
* @param[in] ctx libyang context.
* @param[in] in Input structure.
- * @param[out] tree Parsed full RPC/action tree.
- * @param[out] op Optional pointer to the actual operation. Useful mainly for action.
+ * @param[out] tree_p Parsed full RPC/action tree.
+ * @param[out] op_p Optional pointer to the actual operation. Useful mainly for action.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op);
+LY_ERR lyd_parse_lyb_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p);
/**
* @brief Parse binary data as YANG notification.
*
* @param[in] ctx libyang context.
* @param[in] in Input structure.
- * @param[out] tree Parsed full notification tree.
- * @param[out] op Optional pointer to the actual notification. Useful mainly for nested notifications.
+ * @param[out] tree_p Parsed full notification tree.
+ * @param[out] ntf_p Optional pointer to the actual notification. Useful mainly for nested notifications.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **ntf);
+LY_ERR lyd_parse_lyb_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p);
/**
* @brief Parse binary data as YANG RPC/action reply.
*
* @param[in] request Data tree of the RPC/action request.
* @param[in] in Input structure.
- * @param[out] tree Parsed full reply tree. It always includes duplicated operation and parents of the @p request.
- * @param[out] op Optional pointer to the reply operation. Useful mainly for action.
+ * @param[out] tree_p Parsed full reply tree. It always includes duplicated operation and parents of the @p request.
+ * @param[out] op_p Optional pointer to the reply operation. Useful mainly for action.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op);
+LY_ERR lyd_parse_lyb_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p);
/**
* @defgroup datahash Data nodes hash manipulation
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 0dd45b2..5b8c1a4 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -1637,7 +1637,7 @@
/**
* @brief Schema mapping of YANG modules to prefixes in values.
*
- * Implementation of ly_clb_get_prefix. Inverse function to lys_resolve_prefix.
+ * Implementation of ly_get_prefix_clb. Inverse function to lys_resolve_prefix.
*
* In this case the @p mod is searched in the list of imports and the import's prefix
* (not the module's itself) prefix is returned.
@@ -1664,7 +1664,7 @@
/**
* @brief Schema mapping of prefix in values to YANG modules (imports).
*
- * Implementation of ly_clb_resolve_prefix. Inverse function to lys_get_prefix().
+ * Implementation of ly_resolve_prefix_clb. Inverse function to lys_get_prefix().
*
* In this case the @p prefix is searched in the list of imports' prefixes (not the prefixes of the imported modules themselves).
*/
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index db11a38..f6c7958 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -222,7 +222,7 @@
/**
* @brief Schema mapping of YANG modules to prefixes in values.
*
- * Implementation of ly_clb_get_prefix. Inverse function to lys_resolve_prefix.
+ * Implementation of ly_get_prefix_clb. Inverse function to lys_resolve_prefix.
*
* In this case the @p mod is searched in the list of imports and the import's prefix
* (not the module's itself) prefix is returned.
@@ -232,7 +232,7 @@
/**
* @brief Schema mapping of prefix in values to YANG modules (imports).
*
- * Implementation of ly_clb_resolve_prefix. Inverse function to lys_get_prefix().
+ * Implementation of ly_resolve_prefix_clb. Inverse function to lys_get_prefix().
*
* In this case the @p prefix is searched in the list of imports' prefixes (not the prefixes of the imported modules themselves).
*/
diff --git a/src/validation.c b/src/validation.c
index 9c39173..65c64e7 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -111,7 +111,7 @@
LY_ERR
lyd_validate_unres(struct lyd_node **tree, struct ly_set *node_when, struct ly_set *node_types, struct ly_set *meta_types,
- LYD_FORMAT format, ly_clb_resolve_prefix get_prefix_clb, void *parser_data, struct lyd_node **diff)
+ LYD_FORMAT format, ly_resolve_prefix_clb get_prefix_clb, void *parser_data, struct lyd_node **diff)
{
LY_ERR ret = LY_SUCCESS;
uint32_t i;
@@ -172,7 +172,7 @@
struct lyd_node_term *node = (struct lyd_node_term *)node_types->objs[i];
/* validate and store the value of the node */
- ret = lyd_value_parse(node, node->value.original, strlen(node->value.original), 0, 1, get_prefix_clb,
+ ret = lyd_value_parse(node, node->value.original, strlen(node->value.original), 0, 1, 0, get_prefix_clb,
parser_data, format, *tree);
LY_CHECK_RET(ret);
@@ -191,7 +191,7 @@
/* validate and store the value of the metadata */
ret = lyd_value_parse_meta(meta->parent->schema->module->ctx, meta, meta->value.original,
- strlen(meta->value.original), 0, 1, get_prefix_clb, parser_data, format, NULL, *tree);
+ strlen(meta->value.original), 0, 1, 0, get_prefix_clb, parser_data, format, NULL, *tree);
LY_CHECK_RET(ret);
/* remove this attr from the set */
diff --git a/src/validation.h b/src/validation.h
index 41a47a5..8b23e6f 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -48,7 +48,7 @@
* @return LY_ERR value.
*/
LY_ERR lyd_validate_unres(struct lyd_node **tree, struct ly_set *node_when, struct ly_set *node_types, struct ly_set *meta_types,
- LYD_FORMAT format, ly_clb_resolve_prefix get_prefix_clb, void *parser_data, struct lyd_node **diff);
+ LYD_FORMAT format, ly_resolve_prefix_clb get_prefix_clb, void *parser_data, struct lyd_node **diff);
/**
* @brief Validate new siblings. Specifically, check duplicated instances, autodelete default values and cases.
diff --git a/src/xml.c b/src/xml.c
index d1ba184..a3645c1 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -1103,15 +1103,15 @@
/* check whether we do not already have this prefix stored */
LY_ARRAY_FOR(prefixes, u) {
- if (!ly_strncmp(prefixes[u].pref, start, len)) {
+ if (!ly_strncmp(prefixes[u].id, start, len)) {
p = &prefixes[u];
break;
}
}
if (!p) {
LY_ARRAY_NEW_GOTO(xmlctx->ctx, prefixes, p, ret, error);
- p->pref = lydict_insert(xmlctx->ctx, start, len);
- p->ns = lydict_insert(xmlctx->ctx, ns->uri, 0);
+ p->id = lydict_insert(xmlctx->ctx, start, len);
+ p->module_ns = lydict_insert(xmlctx->ctx, ns->uri, 0);
} /* else the prefix already present */
}
}
@@ -1124,7 +1124,8 @@
error:
LY_ARRAY_FOR(prefixes, u) {
- lydict_remove(xmlctx->ctx, prefixes[u].pref);
+ lydict_remove(xmlctx->ctx, prefixes[u].id);
+ lydict_remove(xmlctx->ctx, prefixes[u].module_ns);
}
LY_ARRAY_FREE(prefixes);
return ret;
@@ -1154,9 +1155,9 @@
if (prefs1) {
/* find module of the first prefix, if any */
LY_ARRAY_FOR(prefs1, u1) {
- len = strlen(prefs1[u1].pref);
- if (!strncmp(ptr1, prefs1[u1].pref, len) && (ptr1[len] == ':')) {
- ns1 = prefs1[u1].ns;
+ len = strlen(prefs1[u1].id);
+ if (!strncmp(ptr1, prefs1[u1].id, len) && (ptr1[len] == ':')) {
+ ns1 = prefs1[u1].module_ns;
break;
}
}
@@ -1164,9 +1165,9 @@
if (prefs2) {
/* find module of the second prefix, if any */
LY_ARRAY_FOR(prefs2, u2) {
- len = strlen(prefs2[u2].pref);
- if (!strncmp(ptr2, prefs2[u2].pref, len) && (ptr2[len] == ':')) {
- ns2 = prefs2[u2].ns;
+ len = strlen(prefs2[u2].id);
+ if (!strncmp(ptr2, prefs2[u2].id, len) && (ptr2[len] == ':')) {
+ ns2 = prefs2[u2].module_ns;
break;
}
}
@@ -1178,8 +1179,8 @@
}
/* skip prefixes in both values (':' is skipped as iter) */
- ptr1 += strlen(prefs1[u1].pref);
- ptr2 += strlen(prefs2[u2].pref);
+ ptr1 += strlen(prefs1[u1].id);
+ ptr2 += strlen(prefs2[u2].id);
}
++ptr1;
diff --git a/src/xml.h b/src/xml.h
index b89a283..fef0bb5 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -76,6 +76,10 @@
};
struct lyxml_ctx {
+ const struct ly_ctx *ctx;
+ uint64_t line; /* current line */
+ struct ly_in *in; /* input structure */
+
enum LYXML_PARSER_STATUS status; /* status providing information about the last parsed object, following attributes
are filled based on it */
union {
@@ -95,9 +99,6 @@
int dynamic; /* LYXML_ELEM_CONTENT, LYXML_ATTR_CONTENT - whether elem/attr value is dynamically allocated */
};
- const struct ly_ctx *ctx;
- uint64_t line; /* current line */
- struct ly_in *in; /* input structure */
struct ly_set elements; /* list of not-yet-closed elements */
struct ly_set ns; /* handled with LY_SET_OPT_USEASLIST */
};
diff --git a/tests/utests/CMakeLists.txt b/tests/utests/CMakeLists.txt
index 5180113..dcf1910 100644
--- a/tests/utests/CMakeLists.txt
+++ b/tests/utests/CMakeLists.txt
@@ -17,6 +17,7 @@
ly_add_utest(NAME new SOURCES data/test_new.c)
ly_add_utest(NAME parser_xml SOURCES data/test_parser_xml.c)
ly_add_utest(NAME printer_xml SOURCES data/test_printer_xml.c)
+ly_add_utest(NAME parser_json SOURCES data/test_parser_json.c)
ly_add_utest(NAME lyb SOURCES data/test_lyb.c)
ly_add_utest(NAME validation SOURCES data/test_validation.c)
ly_add_utest(NAME types SOURCES data/test_types.c)
diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c
index 21eb126..50a7740 100644
--- a/tests/utests/data/test_new.c
+++ b/tests/utests/data/test_new.c
@@ -196,14 +196,14 @@
opq = (struct lyd_node_opaq *)root;
assert_string_equal(opq->name, "node1");
assert_string_equal(opq->value, "");
- assert_string_equal(opq->prefix.ns, "my-module");
+ assert_string_equal(opq->prefix.module_name, "my-module");
assert_int_equal(lyd_new_opaq(root, NULL, "node2", "value", "my-module2", &node), LY_SUCCESS);
assert_null(node->schema);
opq = (struct lyd_node_opaq *)node;
assert_string_equal(opq->name, "node2");
assert_string_equal(opq->value, "value");
- assert_string_equal(opq->prefix.ns, "my-module2");
+ assert_string_equal(opq->prefix.module_name, "my-module2");
assert_ptr_equal(opq->parent, root);
lyd_free_tree(root);
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
new file mode 100644
index 0000000..7539dc7
--- /dev/null
+++ b/tests/utests/data/test_parser_json.c
@@ -0,0 +1,809 @@
+/*
+ * @file test_parser_xml.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from parser_xml.c
+ *
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "context.h"
+#include "parser.h"
+#include "parser_data.h"
+#include "printer.h"
+#include "printer_data.h"
+#include "tests/config.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+
+#define BUFSIZE 1024
+char logbuf[BUFSIZE] = {0};
+int store = -1; /* negative for infinite logging, positive for limited logging */
+
+struct ly_ctx *ctx; /* context for tests */
+
+/* set to 0 to printing error messages to stderr instead of checking them in code */
+#define ENABLE_LOGGER_CHECKING 1
+
+#if ENABLE_LOGGER_CHECKING
+static void
+logger(LY_LOG_LEVEL level, const char *msg, const char *path)
+{
+ (void) level; /* unused */
+ if (store) {
+ if (path && path[0]) {
+ snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
+ } else {
+ strncpy(logbuf, msg, BUFSIZE - 1);
+ }
+ if (store > 0) {
+ --store;
+ }
+ }
+}
+#endif
+
+static int
+setup(void **state)
+{
+ (void) state; /* unused */
+
+ const char *schema_a = "module a {namespace urn:tests:a;prefix a;yang-version 1.1; import ietf-yang-metadata {prefix md;}"
+ "md:annotation hint { type int8;}"
+ "list l1 { key \"a b c\"; leaf a {type string;} leaf b {type string;} leaf c {type int16;} leaf d {type string;}}"
+ "leaf foo { type string;}"
+ "container c {"
+ "leaf x {type string;}"
+ "action act { input { leaf al {type string;} } output { leaf al {type uint8;} } }"
+ "notification n1 { leaf nl {type string;} }"
+ "}"
+ "container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}"
+ "anydata any {config false;}"
+ "leaf-list ll1 { type uint8; }"
+ "leaf foo2 { type string; default \"default-val\"; }"
+ "leaf foo3 { type uint32; }"
+ "notification n2;}";
+ const struct lys_module *mod;
+
+#if ENABLE_LOGGER_CHECKING
+ ly_set_log_clb(logger, 1);
+#endif
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_DIR_MODULES_YANG, 0, &ctx));
+ assert_non_null(ly_ctx_load_module(ctx, "ietf-netconf-with-defaults", "2011-06-01"));
+ assert_non_null((mod = ly_ctx_load_module(ctx, "ietf-netconf", "2011-06-01")));
+ assert_int_equal(LY_SUCCESS, lys_feature_enable(mod, "writable-running"));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx, schema_a, LYS_IN_YANG, NULL));
+
+ return 0;
+}
+
+static int
+teardown(void **state)
+{
+#if ENABLE_LOGGER_CHECKING
+ if (*state) {
+ fprintf(stderr, "%s\n", logbuf);
+ }
+#else
+ (void) state; /* unused */
+#endif
+
+ ly_ctx_destroy(ctx, NULL);
+ ctx = NULL;
+
+ return 0;
+}
+
+void
+logbuf_clean(void)
+{
+ logbuf[0] = '\0';
+}
+
+#if ENABLE_LOGGER_CHECKING
+# define logbuf_assert(str) assert_string_equal(logbuf, str)
+#else
+# define logbuf_assert(str)
+#endif
+
+static void
+test_leaf(void **state)
+{
+ *state = test_leaf;
+
+ const char *data = "{\"a:foo\":\"foo value\"}";
+ struct lyd_node *tree;
+ struct lyd_node_term *leaf;
+
+ char *printed;
+ struct ly_out *out;
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&printed, 0, &out));
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+ assert_string_equal("foo", tree->schema->name);
+ leaf = (struct lyd_node_term*)tree;
+ assert_string_equal("foo value", leaf->value.original);
+
+ assert_int_equal(LYS_LEAF, tree->next->next->schema->nodetype);
+ assert_string_equal("foo2", tree->next->next->schema->name);
+ leaf = (struct lyd_node_term*)tree->next->next;
+ assert_string_equal("default-val", leaf->value.original);
+ assert_true(leaf->flags & LYD_DEFAULT);
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(printed, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* make foo2 explicit */
+ data = "{\"a:foo2\":\"default-val\"}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+ assert_string_equal("foo2", tree->schema->name);
+ leaf = (struct lyd_node_term*)tree;
+ assert_string_equal("default-val", leaf->value.original);
+ assert_false(leaf->flags & LYD_DEFAULT);
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(printed, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* parse foo2 but make it implicit */
+ data = "{\"a:foo2\" : \"default-val\", \"@a:foo2\" : { \"ietf-netconf-with-defaults:default\" : true }}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+ assert_string_equal("foo2", tree->schema->name);
+ leaf = (struct lyd_node_term*)tree;
+ assert_string_equal("default-val", leaf->value.original);
+ assert_true(leaf->flags & LYD_DEFAULT);
+
+ lyd_free_all(tree);
+
+ /* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
+ data = "{\"@a:foo\" : { \"a:hint\" : 1, \"a:hint\" : 2, \"x:xxx\" : { \"value\" : \"/x:no/x:yes\" }}, \"a:foo\" : \"xxx\"}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+ assert_string_equal("foo", tree->schema->name);
+ assert_non_null(tree->meta);
+ assert_string_equal("hint", tree->meta->name);
+ assert_int_equal(LY_TYPE_INT8, tree->meta->value.realtype->basetype);
+ assert_string_equal("1", tree->meta->value.original);
+ assert_int_equal(1, tree->meta->value.int8);
+ assert_ptr_equal(tree, tree->meta->parent);
+ assert_non_null(tree->meta->next);
+ assert_string_equal("hint", tree->meta->next->name);
+ assert_int_equal(LY_TYPE_INT8, tree->meta->next->value.realtype->basetype);
+ assert_string_equal("2", tree->meta->next->value.original);
+ assert_int_equal(2, tree->meta->next->value.int8);
+ assert_ptr_equal(tree, tree->meta->next->parent);
+ assert_null(tree->meta->next->next);
+
+ ly_out_free(out, NULL, 1);
+ lyd_free_all(tree);
+
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Unknown (or not implemented) YANG module \"x\" for metadata \"x:xxx\". /a:foo");
+
+ /* missing referenced metadata node */
+ data = "{\"@a:foo\" : { \"a:hint\" : 1 }}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Missing JSON data instance to be coupled with @a:foo metadata. /");
+
+ /* missing namespace for meatadata*/
+ data = "{\"a:foo\" : \"value\", \"@a:foo\" : { \"hint\" : 1 }}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Metadata in JSON must be namespace-qualified, missing prefix for \"hint\". /a:foo");
+
+ *state = NULL;
+}
+
+static void
+test_leaflist(void **state)
+{
+ *state = test_leaflist;
+
+ const char *data = "{ \"a:ll1\" : [10,11] }";
+ struct lyd_node *tree;
+ struct lyd_node_term *ll;
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LEAFLIST, tree->schema->nodetype);
+ assert_string_equal("ll1", tree->schema->name);
+ ll = (struct lyd_node_term*)tree;
+ assert_string_equal("10", ll->value.original);
+
+ assert_non_null(tree->next);
+ assert_int_equal(LYS_LEAFLIST, tree->next->schema->nodetype);
+ assert_string_equal("ll1", tree->next->schema->name);
+ ll = (struct lyd_node_term*)tree->next;
+ assert_string_equal("11", ll->value.original);
+
+ lyd_free_all(tree);
+
+ /* simple metadata */
+ data = "{ \"a:ll1\" : [10,11], \"@a:ll1\" : [null, {\"a:hint\" : 2}] }";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LEAFLIST, tree->schema->nodetype);
+ assert_string_equal("ll1", tree->schema->name);
+ ll = (struct lyd_node_term*)tree;
+ assert_string_equal("10", ll->value.original);
+ assert_null(ll->meta);
+
+ assert_non_null(tree->next);
+ assert_int_equal(LYS_LEAFLIST, tree->next->schema->nodetype);
+ assert_string_equal("ll1", tree->next->schema->name);
+ ll = (struct lyd_node_term*)tree->next;
+ assert_string_equal("11", ll->value.original);
+ assert_non_null(ll->meta);
+ assert_string_equal("2", ll->meta->value.original);
+ assert_null(ll->meta->next);
+
+ lyd_free_all(tree);
+
+ /* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
+ data = "{\"@a:ll1\" : [{\"a:hint\" : 1, \"x:xxx\" : { \"value\" : \"/x:no/x:yes\" }, \"a:hint\" : 10},null,{\"a:hint\" : 3}], \"a:ll1\" : [1,2,3]}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LEAFLIST, tree->schema->nodetype);
+ assert_string_equal("ll1", tree->schema->name);
+ ll = (struct lyd_node_term*)tree;
+ assert_string_equal("1", ll->value.original);
+ assert_non_null(ll->meta);
+ assert_string_equal("hint", ll->meta->name);
+ assert_int_equal(LY_TYPE_INT8, ll->meta->value.realtype->basetype);
+ assert_string_equal("1", ll->meta->value.original);
+ assert_int_equal(1, ll->meta->value.int8);
+ assert_ptr_equal(ll, ll->meta->parent);
+ assert_non_null(ll->meta->next);
+ assert_string_equal("hint", ll->meta->next->name);
+ assert_int_equal(LY_TYPE_INT8, ll->meta->next->value.realtype->basetype);
+ assert_string_equal("10", ll->meta->next->value.original);
+ assert_int_equal(10, ll->meta->next->value.int8);
+ assert_ptr_equal(ll, ll->meta->next->parent);
+ assert_null(ll->meta->next->next);
+
+ assert_non_null(tree->next);
+ assert_int_equal(LYS_LEAFLIST, tree->next->schema->nodetype);
+ assert_string_equal("ll1", tree->next->schema->name);
+ ll = (struct lyd_node_term*)tree->next;
+ assert_string_equal("2", ll->value.original);
+ assert_null(ll->meta);
+
+ assert_non_null(tree->next->next);
+ assert_int_equal(LYS_LEAFLIST, tree->next->next->schema->nodetype);
+ assert_string_equal("ll1", tree->next->next->schema->name);
+ ll = (struct lyd_node_term*)tree->next->next;
+ assert_string_equal("3", ll->value.original);
+ assert_non_null(ll->meta);
+ assert_string_equal("hint", ll->meta->name);
+ assert_int_equal(LY_TYPE_INT8, ll->meta->value.realtype->basetype);
+ assert_string_equal("3", ll->meta->value.original);
+ assert_int_equal(3, ll->meta->value.int8);
+ assert_ptr_equal(ll, ll->meta->parent);
+ assert_null(ll->meta->next);
+
+ lyd_free_all(tree);
+
+ /* missing referenced metadata node */
+ data = "{\"@a:ll1\":[{\"a:hint\":1}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Missing JSON data instance to be coupled with @a:ll1 metadata. /");
+
+ data = "{\"a:ll1\":[1],\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Missing JSON data instance no. 2 of a:ll1 to be coupled with metadata. /");
+
+ data = "{\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2},{\"a:hint\":3}],\"a:ll1\" : [1, 2]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Missing 3rd JSON data instance to be coupled with @a:ll1 metadata. /");
+
+ *state = NULL;
+}
+
+static void
+test_anydata(void **state)
+{
+ *state = test_anydata;
+
+ const char *data;
+ char *str;
+ struct lyd_node *tree;
+
+ struct ly_out *out;
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&str, 0, &out));
+
+ data = "{\"a:any\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_ANYDATA, tree->schema->nodetype);
+ assert_string_equal("any", tree->schema->name);
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+
+ lyd_free_all(tree);
+ ly_out_free(out, NULL, 1);
+
+ *state = NULL;
+}
+
+static void
+test_list(void **state)
+{
+ *state = test_list;
+
+ const char *data = "{ \"a:l1\" : [{ \"a\":\"one\",\"b\":\"one\",\"c\":1 }]} ";
+ struct lyd_node *tree, *iter;
+ struct lyd_node_inner *list;
+ struct lyd_node_term *leaf;
+
+ /* check hashes */
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LIST, tree->schema->nodetype);
+ assert_string_equal("l1", tree->schema->name);
+ list = (struct lyd_node_inner*)tree;
+ LY_LIST_FOR(list->child, iter) {
+ assert_int_not_equal(0, iter->hash);
+ }
+ lyd_free_all(tree);
+
+ /* missing keys */
+ data = "{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\"}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("List instance is missing its key \"a\". /a:l1[b='b'][c='1']");
+
+ data = "{ \"a:l1\": [ {\"a\" : \"a\"}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("List instance is missing its key \"b\". /a:l1[a='a']");
+
+ data = "{ \"a:l1\": [ {\"b\" : \"b\", \"a\" : \"a\"}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("List instance is missing its key \"c\". /a:l1[a='a'][b='b']");
+
+ /* key duplicate */
+ data = "{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\", \"a\" : \"a\", \"c\" : 1}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Duplicate instance of \"c\". /a:l1[a='a'][b='b'][c='1'][c='1']/c");
+
+ /* keys order, in contrast to XML, JSON accepts keys in any order even in strict mode */
+ logbuf_clean();
+ data = "{ \"a:l1\": [ {\"d\" : \"d\", \"a\" : \"a\", \"c\" : 1, \"b\" : \"b\"}]}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LIST, tree->schema->nodetype);
+ assert_string_equal("l1", tree->schema->name);
+ list = (struct lyd_node_inner*)tree;
+ assert_non_null(leaf = (struct lyd_node_term*)list->child);
+ assert_string_equal("a", leaf->schema->name);
+ assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
+ assert_string_equal("b", leaf->schema->name);
+ assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
+ assert_string_equal("c", leaf->schema->name);
+ assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
+ assert_string_equal("d", leaf->schema->name);
+ logbuf_assert("");
+ lyd_free_all(tree);
+
+ /* */
+ data = "{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\", \"a\" : \"a\"}]}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_LIST, tree->schema->nodetype);
+ assert_string_equal("l1", tree->schema->name);
+ list = (struct lyd_node_inner*)tree;
+ assert_non_null(leaf = (struct lyd_node_term*)list->child);
+ assert_string_equal("a", leaf->schema->name);
+ assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
+ assert_string_equal("b", leaf->schema->name);
+ assert_non_null(leaf = (struct lyd_node_term*)leaf->next);
+ assert_string_equal("c", leaf->schema->name);
+ logbuf_assert("");
+ lyd_free_all(tree);
+
+ data = "{\"a:cp\" : { \"@\" : { \"a:hint\" : 1 }}}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_CONTAINER, tree->schema->nodetype);
+ assert_string_equal("cp", tree->schema->name);
+ assert_non_null(tree->meta);
+ assert_string_equal("hint", tree->meta->name);
+ assert_string_equal("1", tree->meta->value.original);
+ assert_ptr_equal(tree, tree->meta->parent);
+ assert_null(tree->meta->next);
+ lyd_free_all(tree);
+
+ *state = NULL;
+}
+
+static void
+test_container(void **state)
+{
+ *state = test_container;
+
+ const char *data = " {\"a:c\" : {}}";
+ struct lyd_node *tree;
+ struct lyd_node_inner *cont;
+
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_CONTAINER, tree->schema->nodetype);
+ assert_string_equal("c", tree->schema->name);
+ cont = (struct lyd_node_inner*)tree;
+ assert_true(cont->flags & LYD_DEFAULT);
+ lyd_free_all(tree);
+
+ data = "{\"a:cp\" : {}}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_int_equal(LYS_CONTAINER, tree->schema->nodetype);
+ assert_string_equal("cp", tree->schema->name);
+ cont = (struct lyd_node_inner*)tree;
+ assert_false(cont->flags & LYD_DEFAULT);
+ lyd_free_all(tree);
+
+ *state = NULL;
+}
+
+static void
+test_opaq(void **state)
+{
+ *state = test_opaq;
+
+ const char *data;
+ char *str;
+ struct lyd_node *tree;
+
+ struct ly_out *out;
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&str, 0, &out));
+
+ /* invalid value, no flags */
+ data = "{\"a:foo3\":[null]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Invalid empty uint32 value. /a:foo3");
+ assert_null(tree);
+
+ /* opaq flag */
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "foo3");
+ assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* missing key, no flags */
+ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"d\":\"val_d\"}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("List instance is missing its key \"c\". /a:l1[a='val_a'][b='val_b']");
+ assert_null(tree);
+
+ /* opaq flag */
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "l1");
+ assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* invalid key, no flags */
+ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Invalid int16 value \"val_c\". /a:l1/c");
+ assert_null(tree);
+
+ /* opaq flag */
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "l1");
+ assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":{\"val\":\"val_c\"}}]}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "l1");
+ assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\"}]}";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "l1");
+ assert_string_equal(((struct lyd_node_opaq *)tree)->value, "");
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ ly_out_free(out, NULL, 1);
+
+ *state = NULL;
+}
+
+static void
+test_rpc(void **state)
+{
+ *state = test_rpc;
+
+ const char *data;
+ struct ly_in *in;
+ char *str;
+ struct lyd_node *tree, *op;
+ const struct lyd_node *node;
+
+ struct ly_out *out;
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&str, 0, &out));
+
+ data = "{\"ietf-netconf:rpc\":{\"edit-config\":{"
+ "\"target\":{\"running\":[null]},"
+ "\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}},"
+ "\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}"
+ "}}}";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_rpc(ctx, in, LYD_JSON, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+ assert_string_equal(op->schema->name, "edit-config");
+
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "rpc");
+ /* TODO support generic attributes in JSON ?
+ assert_non_null(((struct lyd_node_opaq *)tree)->attr);
+ */
+ node = lyd_node_children(tree, 0);
+ assert_string_equal(node->schema->name, "edit-config");
+ node = lyd_node_children(node, 0)->next;
+ assert_string_equal(node->schema->name, "config");
+
+ node = ((struct lyd_node_any *)node)->value.tree;
+ assert_non_null(node->schema);
+ assert_string_equal(node->schema->name, "cp");
+ node = lyd_node_children(node, 0);
+ /* z has no value */
+ assert_null(node->schema);
+ assert_string_equal(((struct lyd_node_opaq *)node)->name, "z");
+ node = node->parent->next;
+ /* l1 key c has invalid value so it is at the end */
+ assert_null(node->schema);
+ assert_string_equal(((struct lyd_node_opaq *)node)->name, "l1");
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+
+ ly_out_free(out, NULL, 1);
+
+ *state = NULL;
+}
+
+static void
+test_action(void **state)
+{
+ *state = test_action;
+
+ const char *data;
+ struct ly_in *in;
+ char *str;
+ struct lyd_node *tree, *op;
+ const struct lyd_node *node;
+
+ struct ly_out *out;
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&str, 0, &out));
+
+ data = "{\"ietf-netconf:rpc\":{\"yang:action\":{\"a:c\":{\"act\":{\"al\":\"value\"}}}}}";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_rpc(ctx, in, LYD_JSON, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+ assert_string_equal(op->schema->name, "act");
+
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "rpc");
+ assert_null(((struct lyd_node_opaq *)tree)->attr);
+ node = lyd_node_children(tree, 0);
+ assert_null(node->schema);
+ assert_string_equal(((struct lyd_node_opaq *)node)->name, "action");
+ assert_null(((struct lyd_node_opaq *)node)->attr);
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+
+ ly_out_free(out, NULL, 1);
+
+ *state = NULL;
+}
+
+static void
+test_notification(void **state)
+{
+ *state = test_notification;
+
+ const char *data;
+ struct ly_in *in;
+ char *str;
+ struct lyd_node *tree, *ntf;
+ const struct lyd_node *node;
+
+ struct ly_out *out;
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&str, 0, &out));
+
+ data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2037-07-08T00:01:00Z\",\"a:c\":{\"n1\":{\"nl\":\"value\"}}}}";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_notif(ctx, in, LYD_JSON, &tree, &ntf));
+ ly_in_free(in, 0);
+
+ assert_non_null(ntf);
+ assert_string_equal(ntf->schema->name, "n1");
+
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "notification");
+ assert_null(((struct lyd_node_opaq *)tree)->attr);
+ node = lyd_node_children(tree, 0);
+ assert_null(node->schema);
+ assert_string_equal(((struct lyd_node_opaq *)node)->name, "eventTime");
+ assert_string_equal(((struct lyd_node_opaq *)node)->value, "2037-07-08T00:01:00Z");
+ assert_null(((struct lyd_node_opaq *)node)->attr);
+ node = node->next;
+ assert_non_null(node->schema);
+ assert_string_equal(node->schema->name, "c");
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* top-level notif without envelope */
+ data = "{\"a:n2\":{}}";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_notif(ctx, in, LYD_JSON, &tree, &ntf));
+ ly_in_free(in, 0);
+
+ assert_non_null(ntf);
+ assert_string_equal(ntf->schema->name, "n2");
+
+ assert_non_null(tree);
+ assert_ptr_equal(ntf, tree);
+
+ lyd_print_tree(out, tree, LYD_JSON, 0);
+ assert_string_equal(str, data);
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+
+ ly_out_free(out, NULL, 1);
+
+ *state = NULL;
+}
+
+static void
+test_reply(void **state)
+{
+ *state = test_reply;
+
+ const char *data;
+ struct ly_in *in;
+ char *str;
+ struct lyd_node *request, *tree, *op;
+ const struct lyd_node *node;
+
+ struct ly_out *out;
+ assert_int_equal(LY_SUCCESS, ly_out_new_memory(&str, 0, &out));
+
+ data = "{\"a:c\":{\"act\":{\"al\":\"value\"}}}";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_rpc(ctx, in, LYD_JSON, &request, NULL));
+ ly_in_free(in, 0);
+
+ data = "{\"ietf-netconf:rpc-reply\":{\"a:al\":25}}";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_reply(request, in, LYD_JSON, &tree, &op));
+ ly_in_free(in, 0);
+ lyd_free_all(request);
+
+ assert_non_null(op);
+ assert_string_equal(op->schema->name, "act");
+ node = lyd_node_children(op, 0);
+ assert_non_null(node->schema);
+ assert_string_equal(node->schema->name, "al");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+
+ assert_non_null(tree);
+ assert_null(tree->schema);
+ assert_string_equal(((struct lyd_node_opaq *)tree)->name, "rpc-reply");
+ node = lyd_node_children(tree, 0);
+ assert_non_null(node->schema);
+ assert_string_equal(node->schema->name, "c");
+
+ /* TODO print only rpc-reply node and then output subtree */
+ lyd_print_tree(out, lyd_node_children(op, 0), LYD_JSON, 0);
+ assert_string_equal(str, "{\"a:al\":25}");
+ ly_out_reset(out);
+ lyd_print_tree(out, lyd_node_children(tree, 0), LYD_JSON, 0);
+ assert_string_equal(str, "{\"a:c\":{\"act\":{\"al\":25}}}");
+ ly_out_reset(out);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+
+ ly_out_free(out, NULL, 1);
+
+ *state = NULL;
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_leaf, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_leaflist, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_anydata, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_list, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_container, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_opaq, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_rpc, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_action, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_notification, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_reply, setup, teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c
index b7a6952..077c8b4 100644
--- a/tests/utests/data/test_parser_xml.c
+++ b/tests/utests/data/test_parser_xml.c
@@ -154,8 +154,8 @@
lyd_free_all(tree);
- /* parse foo2 but make it implicit */
- data = "<foo2 xmlns=\"urn:tests:a\" xmlns:wd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" wd:default=\"true\">default-val</foo2>";
+ /* parse foo2 but make it implicit, skip metadata xxx from missing schema */
+ data = "<foo2 xmlns=\"urn:tests:a\" xmlns:wd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" wd:default=\"true\" xmlns:x=\"urn:x\" x:xxx=\"false\">default-val</foo2>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_non_null(tree);
assert_int_equal(LYS_LEAF, tree->schema->nodetype);
@@ -387,8 +387,8 @@
/* opaq flag and fail */
assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, "<a xmlns=\"ns\"><b>x</b><c xml:id=\"D\">1</c></a>", LYD_XML,
LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
+ logbuf_assert("Unknown XML prefix \"xml\". Line number 1.");
assert_null(tree);
-
ly_out_free(out, NULL, 1);
*state = NULL;
diff --git a/tests/utests/data/test_types.c b/tests/utests/data/test_types.c
index 02ca2cf..cad0808 100644
--- a/tests/utests/data/test_types.c
+++ b/tests/utests/data/test_types.c
@@ -943,10 +943,10 @@
"<a:inst xmlns:a=\"urn:tests:types\">/a:list2[a:id='a'][a:value='a']/a:id</a:inst>", LY_SUCCESS, "");
/* key-predicate */
- data = "/types:list2[types:id='a'][types:value='b']/types:id";
+ data = "/types:list2[id='a'][value='b']/id";
assert_int_equal(LY_ENOTFOUND, lyd_value_validate(s->ctx, (const struct lyd_node_term*)tree->prev->prev, data, strlen(data),
tree, NULL));
- logbuf_assert("Invalid instance-identifier \"/types:list2[types:id='a'][types:value='b']/types:id\" value - instance not found. /");
+ logbuf_assert("Invalid instance-identifier \"/types:list2[id='a'][value='b']/id\" value - instance not found. /");
/* leaf-list-predicate */
data = "/types:leaflisttarget[.='c']";
assert_int_equal(LY_ENOTFOUND, lyd_value_validate(s->ctx, (const struct lyd_node_term*)tree->prev->prev, data, strlen(data),
diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c
index f223a6d..309cc71 100644
--- a/tests/utests/data/test_validation.c
+++ b/tests/utests/data/test_validation.c
@@ -1346,7 +1346,7 @@
"</cont>";
assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_NO_STATE, 0, &tree));
assert_null(tree);
- logbuf_assert("Invalid state data node \"cont2\" found. Line number 1.");
+ logbuf_assert("Invalid state data node \"cont2\" found. /h:cont/cont2");
assert_int_equal(LY_EVALID, lyd_parse_data_mem(ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT | LYD_VALIDATE_NO_STATE, &tree));
assert_null(tree);