data parser CHANGE unify API with schema parser and use input handler
diff --git a/src/context.c b/src/context.c
index 62f3de7..a0f432c 100644
--- a/src/context.c
+++ b/src/context.c
@@ -27,6 +27,7 @@
#include "common.h"
#include "hash_table.h"
+#include "parser_data.h"
#include "plugins_types.h"
#include "set.h"
#include "tree.h"
@@ -771,7 +772,7 @@
root_bis = 0;
}
- if (lyd_validate(&root, NULL, LYD_VALOPT_DATA_ONLY)) {
+ if (lyd_validate(&root, NULL, LYD_VALIDATE_PRESENT)) {
goto error;
}
diff --git a/src/libyang.h b/src/libyang.h
index 18c5de5..14eb110 100644
--- a/src/libyang.h
+++ b/src/libyang.h
@@ -25,6 +25,7 @@
#include "dict.h"
#include "log.h"
#include "parser.h"
+#include "parser_data.h"
#include "parser_schema.h"
#include "plugins_types.h"
#include "printer.h"
diff --git a/src/lyb.h b/src/lyb.h
index e5bf309..5e14a03 100644
--- a/src/lyb.h
+++ b/src/lyb.h
@@ -39,7 +39,13 @@
size_t byte_count; /**< printed/parsed bytes */
const struct ly_ctx *ctx;
- int options;
+ union {
+ struct {
+ int parse_options;
+ int validate_options;
+ };
+ int print_options;
+ };
/* LYB parser only */
const char *data;
diff --git a/src/parser_data.h b/src/parser_data.h
new file mode 100644
index 0000000..cf48c7d
--- /dev/null
+++ b/src/parser_data.h
@@ -0,0 +1,290 @@
+/**
+ * @file parser_data.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Data parsers for libyang
+ *
+ * Copyright (c) 2015-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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_PARSER_DATA_H_
+#define LY_PARSER_DATA_H_
+
+#include "tree_data.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ly_in;
+
+/**
+ * @addtogroup datatree
+ * @{
+ */
+
+/**
+ * @defgroup dataparseroptions Data parser options
+ *
+ * Various options to change the data tree parsers behavior.
+ *
+ * Default parser behavior:
+ * - complete input file is always parsed. In case of XML, even not well-formed XML document (multiple top-level
+ * elements) is parsed in its entirety,
+ * - parser silently ignores data without matching schema node definition,
+ * - list instances are checked whether they have all the keys, error is raised if not.
+ *
+ * Default parser validation behavior:
+ * - the provided data are expected to provide complete datastore content (both the configuration and state data)
+ * and performs data validation according to all YANG rules, specifics follow,
+ * - list instances are expected to have all the keys (it is not checked),
+ * - instantiated (status) obsolete data print a warning,
+ * - all types are fully resolved (leafref/instance-identifier targets, unions) and must be valid (lists have
+ * all the keys, leaf(-lists) correct values),
+ * - when statements on existing nodes are evaluated, if not satisfied, a validation error is raised,
+ * - if-feature statements are evaluated,
+ * - invalid multiple data instances/data from several cases cause a validation error,
+ * - default values are added.
+ * @{
+ */
+/* note: keep the lower 16bits free for use by LYD_VALIDATE_ flags. They are not supposed to be combined together,
+ * but since they are used (as a separate parameter) together in some functions, we want to keep them in a separated
+ * range to be able detect that the caller put wrong flags into the parser/validate options parameter. */
+#define LYD_PARSE_ONLY 0x010000 /**< Data will be only parsed and no validation will be performed. When statements
+ are kept unevaluated, union types may not be fully resolved, if-feature
+ statements are not checked, and default values are not added (only the ones
+ parsed are present). */
+#define LYD_PARSE_TRUSTED 0x020000 /**< Data are considered trusted so they will be parsed as validated. If the parsed
+ data are not valid, using this flag may lead to some unexpected behavior!
+ This flag can be used only with #LYD_OPT_PARSE_ONLY. */
+#define LYD_PARSE_STRICT 0x040000 /**< Instead of silently ignoring data without schema definition raise an error.
+ Do not combine with #LYD_OPT_OPAQ. */
+#define LYD_PARSE_OPAQ 0x080000 /**< Instead of silently ignoring data without definition, parse them into
+ an opaq node. Do not combine with #LYD_OPT_STRICT and use only for a generic
+ YANG data tree (opaq Notifications, RPCs or actions are not allowed). */
+#define LYD_PARSE_NO_STATE 0x100000 /**< Forbid state data in the parsed data. */
+
+#define LYD_PARSE_LYB_MOD_UPDATE 0x200000 /**< Only for LYB format, allow parsing data printed using a specific module
+ revision to be loaded even with a module with the same name but newer
+ revision. */
+/** @} dataparseroptions */
+
+
+/**
+ * @defgroup datavalidationoptions Data validation options
+ * @ingroup datatree
+ *
+ * Various options to change data validation behaviour, both for the parser and separate validation.
+ *
+ * Default separate validation behavior:
+ * - the provided data are expected to provide complete datastore content (both the configuration and state data)
+ * and performs data validation according to all YANG rules, specifics follow,
+ * - instantiated (status) obsolete data print a warning,
+ * - all types are fully resolved (leafref/instance-identifier targets, unions) and must be valid (lists have
+ * all the keys, leaf(-lists) correct values),
+ * - when statements on existing nodes are evaluated. Depending on the previous when state (from previous validation
+ * or parsing), the node is silently auto-deleted if the state changed from true to false, otherwise a validation error
+ * is raised if it evaluates to false,
+ * - if-feature statements are evaluated,
+ * - data from several cases behave based on their previous state (from previous validation or parsing). If there existed
+ * already a case and another one was added, the previous one is silently auto-deleted. Otherwise (if data from 2 or
+ * more cases were created) a validation error is raised,
+ * - default values are added.
+ *
+ * @{
+ */
+#define LYD_VALIDATE_NO_STATE 0x0001 /**< Consider state data not allowed and raise an error if they are found. */
+#define LYD_VALIDATE_PRESENT 0x0002 /**< Validate only modules whose data actually exist. */
+//#define LYD_VALIDATE_DIFF 0x0004 /**< Flag only for validation, store all the data node changes performed by the validation
+// in a diff structure. */
+//#define LYD_VALIDATE_DATA_TEMPLATE 0x0008 /**< Data represents YANG data template. */
+
+/** @} datavalidationoptions */
+
+/**
+ * @defgroup datavalidateop Operation to validate
+ * @ingroup datatree
+ *
+ * Operation provided to lyd_validate_op() to validate. The operation cannot be determined automatically since RPC/action and a reply to it
+ * share the common top level node referencing the RPC/action schema node and may not have any input/output children to use for distinction.
+ */
+typedef enum {
+ LYD_VALIDATE_OP_RPC = 1, /**< Validate RPC/action request (input parameters). */
+ LYD_VALIDATE_OP_REPLY, /**< Validate RPC/action reply (output parameters). */
+ LYD_VALIDATE_OP_NOTIF /**< Validate Notification operation. */
+} LYD_VALIDATE_OP;
+
+/** @} datavalidateop */
+
+/**
+ * @brief Parse (and validate) data from the input handler as a YANG data tree.
+ *
+ * @param[in] ctx Context to connect with the tree being built here.
+ * @param[in] in The input handle to provide the dumped data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed. Can be 0 to try to detect format from the input handler.
+ * @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 Resulting data tree built from the input data. Note that NULL can be a valid result as a representation of an empty YANG data tree.
+ * The returned data are expected to be freed using lyd_free_all().
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @reutnr LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LY_ERR 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);
+
+/**
+ * @brief Parse (and validate) input data as a YANG data tree.
+ *
+ * Wrapper around lyd_parse_data() hiding work with the input handler.
+ *
+ * @param[in] ctx Context to connect with the tree being built here.
+ * @param[in] data The input data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed. Can be 0 to try to detect format from the input handler.
+ * @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 Resulting data tree built from the input data. Note that NULL can be a valid result as a representation of an empty YANG data tree.
+ * The returned data are expected to be freed using lyd_free_all().
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @reutnr LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LY_ERR lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree);
+
+/**
+ * @brief Parse (and validate) input data as a YANG data tree.
+ *
+ * Wrapper around lyd_parse_data() hiding work with the input handler.
+ *
+ * @param[in] ctx Context to connect with the tree being built here.
+ * @param[in] fd File descriptor of a regular file (e.g. sockets are not supported) containing the input data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed. Can be 0 to try to detect format from the input handler.
+ * @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 Resulting data tree built from the input data. Note that NULL can be a valid result as a representation of an empty YANG data tree.
+ * The returned data are expected to be freed using lyd_free_all().
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @reutnr LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LY_ERR lyd_parse_data_fd(const struct ly_ctx *ctx, int fd, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree);
+
+/**
+ * @brief Parse (and validate) input data as a YANG data tree.
+ *
+ * Wrapper around lyd_parse_data() hiding work with the input handler.
+ *
+ * @param[in] ctx Context to connect with the tree being built here.
+ * @param[in] path Path to the file with the input data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed. Can be 0 to try to detect format from the input handler.
+ * @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 Resulting data tree built from the input data. Note that NULL can be a valid result as a representation of an empty YANG data tree.
+ * The returned data are expected to be freed using lyd_free_all().
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @reutnr LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LY_ERR lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree);
+
+/**
+ * @brief Parse (and validate) data from the input handler as a YANG RPC/action invocation.
+ *
+ * In case o LYD_XML @p format, the \<rpc\> envelope element is accepted if present. It is [checked](https://tools.ietf.org/html/rfc6241#section-4.1), an opaq
+ * data node (lyd_node_opaq) is created and all its XML attributes are parsed and inserted into the node. As a content of the enveloper, an RPC data or
+ * \<action\> envelope element is expected. The \<action\> envelope element is also [checked](https://tools.ietf.org/html/rfc7950#section-7.15.2) and parsed as
+ * the \<rpc\> envelope. Inside the \<action\> envelope, only an action data are expected.
+ *
+ * @param[in] ctx Context to connect with the tree being built here.
+ * @param[in] in The input handle to provide the dumped data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed.
+ * @param[out] tree Resulting full RPC/action tree built from the input data. The returned data are expected to be freed using lyd_free_all().
+ * In contrast to YANG data tree, result of parsing RPC/action cannot be NULL until an error occurs.
+ * @param[out] op Optional pointer to the actual operation node inside the full action @p tree, useful only for action.
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @reutnr LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LY_ERR lyd_parse_rpc(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **op);
+
+/**
+ * @brief Parse (and validate) data from the input handler as a YANG RPC/action reply.
+ *
+ * In case o LYD_XML @p format, the \<rpc-reply\> envelope element is accepted if present. It is [checked](https://tools.ietf.org/html/rfc6241#section-4.2), an opaq
+ * data node (lyd_node_opaq) is created and all its XML attributes are parsed and inserted into the node.
+ *
+ * The reply data are strictly expected to be related to the provided RPC/action @p request.
+ *
+ * @param[in] request The RPC/action tree (result of lyd_parse_rpc()) of the request for the reply being parsed.
+ * @param[in] in The input handle to provide the dumped data in the specified @p format to parse (and validate).
+ * @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.
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @reutnr LY_ERR value in case of error. Additional error information can be obtained from the request's context using ly_err* functions.
+ */
+LY_ERR lyd_parse_reply(const struct lyd_node *request, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **op);
+
+/**
+ * @brief Parse XML string as YANG notification.
+ *
+ * In case o LYD_XML @p format, the \<notification\> envelope element in combination with the child \<eventTime\> element are accepted if present. They are
+ * [checked](https://tools.ietf.org/html/rfc5277#page-25), opaq data nodes (lyd_node_opaq) are created and all their XML attributes are parsed and inserted into the nodes.
+ *
+ * @param[in] ctx Context to connect with the tree being built here.
+ * @param[in] in The input handle to provide the dumped data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed.
+ * @param[out] tree Resulting full Notification tree built from the input data. The returned data are expected to be freed using lyd_free_all().
+ * In contrast to YANG data tree, result of parsing Notification cannot be NULL until an error occurs.
+ * @param[out] ntf Optional pointer to the actual notification node inside the full Notification @p tree, useful for nested notifications.
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @reutnr LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+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);
+
+/**
+ * @brief Fully validate a data tree.
+ *
+ * @param[in,out] tree Data tree to recursively validate. May be changed by validation.
+ * @param[in] ctx libyang context. Can be NULL if @p tree is set.
+ * @param[in] val_opts Validation options (@ref datavalidationoptions).
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LY_ERR lyd_validate(struct lyd_node **tree, const struct ly_ctx *ctx, int val_opts);
+
+/**
+ * @brief Fully validate a data tree.
+ *
+ * @param[in,out] tree Data tree to recursively validate. May be changed by validation.
+ * @param[in] modules Array of modules to validate.
+ * @param[in] mod_count Number of @p modules.
+ * @param[in] val_opts Validation options (@ref datavalidationoptions).
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LY_ERR lyd_validate_modules(struct lyd_node **tree, const struct lys_module **modules, int mod_count, int val_opts);
+
+/**
+ * @brief Validate an RPC/action, notification, or RPC/action reply.
+ *
+ * @param[in,out] op_tree Operation tree with any parents. It can point to the operation itself or any of
+ * its parents, only the operation subtree is actually validated.
+ * @param[in] tree Tree to be used for validating references from the operation subtree.
+ * @param[in] op Operation to validate (@ref datavalidateop), the given @p op_tree must correspond to this value. Note that
+ * it isn't possible to detect the operation simply from the @p op_tree since RPC/action and their reply share the same
+ * RPC/action data node and in case one of the input and output do not define any data node children, it is not passible
+ * to get know what is here given for validation and if it is really valid.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LY_ERR lyd_validate_op(struct lyd_node *op_tree, const struct lyd_node *tree, LYD_VALIDATE_OP op);
+
+/** @} datatree */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LY_PARSER_DATA_H_ */
diff --git a/src/parser_internal.h b/src/parser_internal.h
index 9dc3c50..d90c504 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -19,6 +19,16 @@
#include "tree_schema_internal.h"
/**
+ * @brief Mask for checking LYD_PARSE_ options (@ref dataparseroptions)
+ */
+#define LYD_PARSE_OPTS_MASK 0xFFFF0000
+
+/**
+ * @brief Mask for checking LYD_VALIDATEP_ options (@ref datavalidationoptions)
+ */
+#define LYD_VALIDATE_OPTS_MASK 0x0000FFFF
+
+/**
* @brief Parser input structure specifying where the data are read.
*/
struct ly_in {
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 74ff62b..d9366f8 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -25,6 +25,8 @@
#include "context.h"
#include "dict.h"
#include "log.h"
+#include "parser_data.h"
+#include "parser_internal.h"
#include "set.h"
#include "tree.h"
#include "tree_data_internal.h"
@@ -272,7 +274,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->options & LYD_OPT_LYB_MOD_UPDATE) && !(*mod)) {
+ if ((lybctx->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))) {
@@ -293,7 +295,7 @@
}*/
if (!*mod || !(*mod)->implemented) {
- if (lybctx->options & LYD_OPT_STRICT) {
+ if (lybctx->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 : "");
@@ -571,7 +573,7 @@
{
LY_ERR ret = LY_SUCCESS;
- if ((lybctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
+ 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;
}
@@ -669,7 +671,7 @@
}
}
- if (!sibling && (lybctx->options & LYD_OPT_STRICT)) {
+ 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"
" from \"%s\".", mod->name);
@@ -748,7 +750,7 @@
LY_CHECK_GOTO(ret, cleanup);
}
- if (!snode && !(lybctx->options & LYD_OPT_OPAQ)) {
+ if (!snode && !(lybctx->parse_options & LYD_PARSE_OPAQ)) {
/* unknown data, skip them */
lyb_skip_subtree(lybctx);
goto stop_subtree;
@@ -812,7 +814,7 @@
}
value = NULL;
if (ret == LY_EINCOMPLETE) {
- if (!(lybctx->options & LYD_OPT_PARSE_ONLY)) {
+ if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
ly_set_add(&lybctx->unres_node_type, node, LY_SET_OPT_USEASLIST);
}
ret = LY_SUCCESS;
@@ -830,14 +832,14 @@
LY_CHECK_GOTO(ret, cleanup);
}
- if (!(lybctx->options & LYD_OPT_PARSE_ONLY)) {
+ if (!(lybctx->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);
LY_CHECK_GOTO(ret, cleanup);
/* add any missing default children */
ret = lyd_validate_defaults_r((struct lyd_node_inner *)node, lyd_node_children_p(node), NULL, NULL,
- &lybctx->unres_node_type, &lybctx->when_check, lybctx->options);
+ &lybctx->unres_node_type, &lybctx->when_check, lybctx->validate_options);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -867,15 +869,15 @@
prev_lo = ly_log_options(0);
/* try to parse LYB into a data tree */
- tree = lyd_parse_mem((struct ly_ctx *)lybctx->ctx, value, LYD_LYB,
- LYD_OPT_PARSE_ONLY | LYD_OPT_OPAQ | LYD_OPT_STRICT);
- ly_log_options(prev_lo);
- if (!ly_errcode(lybctx->ctx)) {
+ 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) {
/* successfully parsed */
free(value);
value = (char *)tree;
value_type = LYD_ANYDATA_DATATREE;
}
+
+ /* turn logging on again */
+ ly_log_options(prev_lo);
}
/* create node */
@@ -889,7 +891,7 @@
/* add/correct flags */
if (snode) {
- lyd_parse_set_data_flags(node, &lybctx->when_check, &meta, lybctx->options);
+ lyd_parse_set_data_flags(node, &lybctx->when_check, &meta, lybctx->parse_options);
}
/* add metadata/attributes */
@@ -1018,16 +1020,20 @@
}
LY_ERR
-lyd_parse_lyb_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree, int *parsed_bytes)
+lyd_parse_lyb_data(const struct ly_ctx *ctx, const char *data, int parse_options, int validate_options, struct lyd_node **tree, int *parsed_bytes)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_lyb_ctx lybctx = {0};
+ assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
+ assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
+
*tree = NULL;
lybctx.data = data;
lybctx.ctx = ctx;
- lybctx.options = options;
+ lybctx.parse_options = parse_options;
+ lybctx.validate_options = validate_options;
/* read magic number */
ret = lyb_parse_magic_number(&lybctx);
@@ -1071,14 +1077,14 @@
}
LY_ERR
-lyd_parse_lyb_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op, int *parsed_bytes)
+lyd_parse_lyb_rpc(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op, int *parsed_bytes)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_lyb_ctx lybctx = {0};
lybctx.data = data;
lybctx.ctx = ctx;
- lybctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
+ lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lybctx.int_opts = LYD_INTOPT_RPC;
*tree = NULL;
@@ -1136,14 +1142,14 @@
}
LY_ERR
-lyd_parse_lyb_notif(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf, int *parsed_bytes)
+lyd_parse_lyb_notif(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf, int *parsed_bytes)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_lyb_ctx lybctx = {0};
lybctx.data = data;
lybctx.ctx = ctx;
- lybctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
+ lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lybctx.int_opts = LYD_INTOPT_NOTIF;
*tree = NULL;
@@ -1201,7 +1207,7 @@
}
LY_ERR
-lyd_parse_lyb_reply(struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op,
+lyd_parse_lyb_reply(const struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op,
int *parsed_bytes)
{
LY_ERR ret = LY_SUCCESS;
@@ -1210,7 +1216,7 @@
lybctx.data = data;
lybctx.ctx = LYD_NODE_CTX(request);
- lybctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
+ lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lybctx.int_opts = LYD_INTOPT_REPLY;
*tree = NULL;
diff --git a/src/parser_xml.c b/src/parser_xml.c
index a50ee05..2aae751 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -20,6 +20,8 @@
#include "common.h"
#include "context.h"
#include "log.h"
+#include "parser_data.h"
+#include "parser_internal.h"
#include "set.h"
#include "tree.h"
#include "tree_data_internal.h"
@@ -313,7 +315,7 @@
size_t pprefix_len, pname_len;
struct lyxml_ctx *xmlctx = lydctx->xmlctx;
- if ((lydctx->options & LYD_OPT_NO_STATE) && ((*snode)->flags & LYS_CONFIG_R)) {
+ 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;
}
@@ -346,7 +348,7 @@
}
}
- if ((lydctx->options & LYD_OPT_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
+ if ((lydctx->options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
/* backup parser */
prev_status = xmlctx->status;
pprefix = xmlctx->prefix;
@@ -444,13 +446,13 @@
}
mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
if (!mod) {
- if (lydctx->options & LYD_OPT_STRICT) {
+ if (lydctx->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_OPT_OPAQ)) {
+ if (!(lydctx->options & LYD_PARSE_OPAQ)) {
/* skip element with children */
LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
continue;
@@ -465,12 +467,12 @@
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_OPT_STRICT) {
+ if (lydctx->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_OPT_OPAQ)) {
+ } else if (!(lydctx->options & LYD_PARSE_OPAQ)) {
/* skip element with children */
LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
continue;
@@ -484,10 +486,10 @@
/* create metadata/attributes */
if (xmlctx->status == LYXML_ATTRIBUTE) {
if (snode) {
- ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_OPT_STRICT, &lydctx->unres_meta_type, &meta);
+ ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_PARSE_STRICT, &lydctx->unres_meta_type, &meta);
LY_CHECK_GOTO(ret, cleanup);
} else {
- assert(lydctx->options & LYD_OPT_OPAQ);
+ assert(lydctx->options & LYD_PARSE_OPAQ);
ret = lydxml_attrs(xmlctx, &attr);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -495,7 +497,7 @@
assert(xmlctx->status == LYXML_ELEM_CONTENT);
if (!snode) {
- assert(lydctx->options & LYD_OPT_OPAQ);
+ assert(lydctx->options & LYD_PARSE_OPAQ);
if (xmlctx->ws_only) {
/* ignore WS-only value */
@@ -525,7 +527,7 @@
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_OPT_PARSE_ONLY)) {
+ if (!(lydctx->options & LYD_PARSE_ONLY)) {
ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
}
} else if (ret) {
@@ -536,7 +538,7 @@
/* check the key order, the anchor must always be the last child */
anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
if ((!anchor && parent->child) || (anchor && anchor->next)) {
- if (lydctx->options & LYD_OPT_STRICT) {
+ if (lydctx->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;
@@ -584,7 +586,7 @@
LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
}
- if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
+ if (!(lydctx->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);
LY_CHECK_GOTO(ret, cleanup);
@@ -616,8 +618,8 @@
/* parse any data tree with correct options */
prev_opts = lydctx->options;
- lydctx->options &= ~LYD_OPT_STRICT;
- lydctx->options |= LYD_OPT_OPAQ;
+ lydctx->options &= ~LYD_PARSE_STRICT;
+ lydctx->options |= LYD_PARSE_OPAQ;
anchor = NULL;
ret = lydxml_data_r(lydctx, NULL, &anchor);
lydctx->options = prev_opts;
@@ -674,7 +676,7 @@
}
LY_ERR
-lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
+lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int parse_options, int validate_options, struct lyd_node **tree)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_xml_ctx lydctx = {0};
@@ -682,18 +684,21 @@
const struct lys_module *mod;
struct lyd_node *first, *next, **first2;
+ 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, data, &lydctx.xmlctx), cleanup);
- lydctx.options = options;
+ lydctx.options = parse_options;
*tree = NULL;
/* parse XML data */
LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
- if (!(options & LYD_OPT_PARSE_ONLY)) {
+ if (!(parse_options & LYD_PARSE_ONLY)) {
next = *tree;
while (1) {
- if (options & LYD_VALOPT_DATA_ONLY) {
+ if (validate_options & LYD_VALIDATE_PRESENT) {
mod = lyd_data_next_module(&next, &first);
} else {
mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
@@ -712,8 +717,7 @@
LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod), cleanup);
/* add all top-level defaults for this module */
- ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
- options & LYD_VALOPT_MASK);
+ ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check, validate_options);
LY_CHECK_GOTO(ret, cleanup);
/* finish incompletely validated terminal values/attributes and when conditions */
@@ -722,13 +726,13 @@
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, options & LYD_VALOPT_MASK), cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, validate_options, 0), cleanup);
}
}
cleanup:
/* there should be no unresolved types stored */
- assert(!(options & LYD_OPT_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.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);
@@ -810,7 +814,7 @@
/* init */
LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
- lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
+ lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lydctx.int_opts = LYD_INTOPT_RPC;
*tree = NULL;
if (op) {
@@ -994,7 +998,7 @@
/* init */
LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
- lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
+ lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lydctx.int_opts = LYD_INTOPT_NOTIF;
*tree = NULL;
if (ntf) {
@@ -1057,7 +1061,7 @@
/* init */
LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), data, &lydctx.xmlctx), cleanup);
- lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
+ lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
lydctx.int_opts = LYD_INTOPT_REPLY;
*tree = NULL;
if (op) {
diff --git a/src/plugins_types.c b/src/plugins_types.c
index df43836..08d33b4 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -1652,7 +1652,7 @@
}
}
}
- } else { /* LYD_JSON */
+ } else if (format == LYD_JSON) {
/* only the first node or the node changing module is prefixed */
struct lys_module *mod = NULL;
LY_ARRAY_FOR(value->target, u) {
@@ -1704,6 +1704,10 @@
}
}
}
+ } else {
+ /* not supported format */
+ free(result);
+ return NULL;
}
*dynamic = 1;
diff --git a/src/printer.c b/src/printer.c
index be367d2..a4905c8 100644
--- a/src/printer.c
+++ b/src/printer.c
@@ -114,7 +114,7 @@
{
const struct lyd_node *next, *elem;
- if (options & LYDP_WD_TRIM) {
+ if (options & LYD_PRINT_WD_TRIM) {
/* do not print default nodes */
if (node->flags & LYD_DEFAULT) {
/* implicit default node/NP container with only default nodes */
@@ -125,7 +125,7 @@
return 0;
}
}
- } else if ((node->flags & LYD_DEFAULT) && !(options & LYDP_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
+ } else if ((node->flags & LYD_DEFAULT) && !(options & LYD_PRINT_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
/* LYDP_WD_EXPLICIT
* - print only if it contains status data in its subtree */
LYD_TREE_DFS_BEGIN(node, next, elem) {
@@ -137,7 +137,7 @@
LYD_TREE_DFS_END(node, next, elem)
}
return 0;
- } else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER) && !(options & LYDP_KEEPEMPTYCONT)) {
+ } else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER) && !(options & LYD_PRINT_KEEPEMPTYCONT)) {
/* avoid empty default containers */
LYD_TREE_DFS_BEGIN(node, next, elem) {
if (elem->schema->nodetype != LYS_CONTAINER) {
diff --git a/src/printer_data.h b/src/printer_data.h
index 31cfc71..31da54e 100644
--- a/src/printer_data.h
+++ b/src/printer_data.h
@@ -35,23 +35,23 @@
*
* @{
*/
-#define LYDP_WITHSIBLINGS 0x01 /**< Flag for printing also the (following) sibling nodes of the data node. */
-#define LYDP_FORMAT 0x02 /**< Flag for formatted output. */
-#define LYDP_KEEPEMPTYCONT 0x04 /**< Preserve empty non-presence containers */
-#define LYDP_WD_MASK 0xF0 /**< Mask for with-defaults modes */
-#define LYDP_WD_EXPLICIT 0x00 /**< Explicit mode - print only data explicitly being present in the data tree.
- Note that this is the default value when no WD option is specified. */
-#define LYDP_WD_TRIM 0x10 /**< Do not print the nodes with the value equal to their default value */
-#define LYDP_WD_ALL 0x20 /**< Include implicit default nodes */
-#define LYDP_WD_ALL_TAG 0x40 /**< Same as #LYDP_WD_ALL but also adds attribute 'default' with value 'true' to
- all nodes that has its default value. The 'default' attribute has namespace:
- urn:ietf:params:xml:ns:netconf:default:1.0 and thus the attributes are
- printed only when the ietf-netconf-with-defaults module is present in libyang
- context (but in that case this namespace is always printed). */
-#define LYDP_WD_IMPL_TAG 0x80 /**< Same as LYDP_WD_ALL_TAG but the attributes are added only to the nodes that
- are not explicitly present in the original data tree despite their
- value is equal to their default value. There is the same limitation regarding
- the presence of ietf-netconf-with-defaults module in libyang context. */
+#define LYD_PRINT_WITHSIBLINGS 0x01 /**< Flag for printing also the (following) sibling nodes of the data node. */
+#define LYD_PRINT_FORMAT 0x02 /**< Flag for formatted output. */
+#define LYD_PRINT_KEEPEMPTYCONT 0x04 /**< Preserve empty non-presence containers */
+#define LYD_PRINT_WD_MASK 0xF0 /**< Mask for with-defaults modes */
+#define LYD_PRINT_WD_EXPLICIT 0x00 /**< Explicit mode - print only data explicitly being present in the data tree.
+ Note that this is the default value when no WD option is specified. */
+#define LYD_PRINT_WD_TRIM 0x10 /**< Do not print the nodes with the value equal to their default value */
+#define LYD_PRINT_WD_ALL 0x20 /**< Include implicit default nodes */
+#define LYD_PRINT_WD_ALL_TAG 0x40 /**< Same as #LYDP_WD_ALL but also adds attribute 'default' with value 'true' to
+ all nodes that has its default value. The 'default' attribute has namespace:
+ urn:ietf:params:xml:ns:netconf:default:1.0 and thus the attributes are
+ printed only when the ietf-netconf-with-defaults module is present in libyang
+ context (but in that case this namespace is always printed). */
+#define LYD_PRINT_WD_IMPL_TAG 0x80 /**< Same as LYDP_WD_ALL_TAG but the attributes are added only to the nodes that
+ are not explicitly present in the original data tree despite their
+ value is equal to their default value. There is the same limitation regarding
+ the presence of ietf-netconf-with-defaults module in libyang context. */
/**
* @}
*/
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 411622b..dc03f61 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -27,6 +27,7 @@
#include "context.h"
#include "hash_table.h"
#include "log.h"
+#include "parser_data.h"
#include "printer.h"
#include "printer_data.h"
#include "printer_internal.h"
@@ -678,7 +679,7 @@
if (anydata->value_type == LYD_ANYDATA_DATATREE) {
/* print LYB data tree to memory */
LY_CHECK_GOTO(ret = ly_out_new_memory(&buf, 0, &out2), cleanup);
- LY_CHECK_GOTO(ret = lyb_print_data(out2, anydata->value.tree, LYDP_WITHSIBLINGS), cleanup);
+ LY_CHECK_GOTO(ret = lyb_print_data(out2, anydata->value.tree, LYD_PRINT_WITHSIBLINGS), cleanup);
len = lyd_lyb_data_length(buf);
assert(len != -1);
@@ -747,8 +748,8 @@
/* with-defaults */
if (node->schema->nodetype & LYD_NODE_TERM) {
- if (((node->flags & LYD_DEFAULT) && (lybctx->options & (LYDP_WD_ALL_TAG | LYDP_WD_IMPL_TAG))) ||
- ((lybctx->options & LYDP_WD_ALL_TAG) && ly_is_default(node))) {
+ if (((node->flags & LYD_DEFAULT) && (lybctx->print_options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG))) ||
+ ((lybctx->print_options & LYD_PRINT_WD_ALL_TAG) && ly_is_default(node))) {
/* we have implicit OR explicit default node, print attribute only if context include with-defaults schema */
wd_mod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
}
@@ -1005,7 +1006,7 @@
const struct lys_module *prev_mod = NULL;
struct lyd_lyb_ctx lybctx = {0};
- lybctx.options = options;
+ lybctx.print_options = options;
if (root) {
lybctx.ctx = LYD_NODE_CTX(root);
@@ -1033,7 +1034,7 @@
LY_CHECK_GOTO(ret = lyb_print_subtree(out, root, &top_sibling_ht, &lybctx), cleanup);
- if (!(options & LYDP_WITHSIBLINGS)) {
+ if (!(options & LYD_PRINT_WITHSIBLINGS)) {
break;
}
}
diff --git a/src/printer_xml.c b/src/printer_xml.c
index d143ba7..7191d84 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -22,6 +22,7 @@
#include "context.h"
#include "dict.h"
#include "log.h"
+#include "parser_data.h"
#include "plugins_types.h"
#include "printer.h"
#include "printer_data.h"
@@ -142,8 +143,8 @@
/* with-defaults */
if (node->schema->nodetype & LYD_NODE_TERM) {
- if (((node->flags & LYD_DEFAULT) && (ctx->options & (LYDP_WD_ALL_TAG | LYDP_WD_IMPL_TAG))) ||
- ((ctx->options & LYDP_WD_ALL_TAG) && ly_is_default(node))) {
+ if (((node->flags & LYD_DEFAULT) && (ctx->options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG))) ||
+ ((ctx->options & LYD_PRINT_WD_ALL_TAG) && ly_is_default(node))) {
/* we have implicit OR explicit default node, print attribute only if context include with-defaults schema */
mod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
if (mod) {
@@ -382,22 +383,22 @@
prev_lo = ly_log_options(0);
/* try to parse it into a data tree */
- iter = lyd_parse_mem((struct ly_ctx *)LYD_NODE_CTX(node), any->value.mem, LYD_LYB,
- LYD_OPT_PARSE_ONLY | LYD_OPT_OPAQ | LYD_OPT_STRICT);
- ly_log_options(prev_lo);
- if (!ly_errcode(LYD_NODE_CTX(node))) {
+ if (lyd_parse_data_mem((struct ly_ctx *)LYD_NODE_CTX(node), any->value.mem, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0, &iter) == LY_SUCCESS) {
/* successfully parsed */
free(any->value.mem);
any->value.tree = iter;
any->value_type = LYD_ANYDATA_DATATREE;
}
+
+ /* turn loggin on again */
+ ly_log_options(prev_lo);
}
switch (any->value_type) {
case LYD_ANYDATA_DATATREE:
/* close opening tag and print data */
prev_opts = ctx->options;
- ctx->options &= ~LYDP_WITHSIBLINGS;
+ ctx->options &= ~LYD_PRINT_WITHSIBLINGS;
LEVEL_INC;
ly_print(ctx->out, ">%s", LEVEL ? "\n" : "");
@@ -558,14 +559,14 @@
}
ctx.out = out;
- ctx.level = (options & LYDP_FORMAT ? 1 : 0);
+ ctx.level = (options & LYD_PRINT_FORMAT ? 1 : 0);
ctx.options = options;
ctx.ctx = LYD_NODE_CTX(root);
/* content */
LY_LIST_FOR(root, node) {
LY_CHECK_RET(xml_print_node(&ctx, node));
- if (!(options & LYDP_WITHSIBLINGS)) {
+ if (!(options & LYD_PRINT_WITHSIBLINGS)) {
break;
}
}
diff --git a/src/tree_data.c b/src/tree_data.c
index eceaebf..b558038 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -34,6 +34,8 @@
#include "dict.h"
#include "hash_table.h"
#include "log.h"
+#include "parser_data.h"
+#include "parser_internal.h"
#include "path.h"
#include "plugins_exts.h"
#include "plugins_exts_metadata.h"
@@ -280,98 +282,14 @@
return meta->value.realtype->plugin->print(&meta->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
}
-API struct lyd_node *
-lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
+static LYD_FORMAT
+lyd_parse_get_format(struct ly_in *in, LYD_FORMAT format)
{
- struct lyd_node *result = NULL;
-#if 0
- const char *yang_data_name = NULL;
-#endif
- LY_CHECK_ARG_RET(ctx, ctx, NULL);
-
- if ((options & LYD_OPT_PARSE_ONLY) && (options & LYD_VALOPT_MASK)) {
- LOGERR(ctx, LY_EINVAL, "Passing validation flags with LYD_OPT_PARSE_ONLY is not allowed.");
- return NULL;
- }
-
-#if 0
- if (options & LYD_OPT_RPCREPLY) {
- /* first item in trees is mandatory - the RPC/action request */
- LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
- if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
- LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
- lyd_parse_options_type2str(options));
- return NULL;
- }
- }
-
- if (options & LYD_OPT_DATA_TEMPLATE) {
- yang_data_name = va_arg(ap, const char *);
- }
-#endif
-
- if (!format) {
- /* TODO try to detect format from the content */
- }
-
- switch (format) {
- case LYD_XML:
- lyd_parse_xml_data(ctx, data, options, &result);
- break;
-#if 0
- case LYD_JSON:
- lyd_parse_json(ctx, data, options, trees, &result);
- break;
-#endif
- case LYD_LYB:
- lyd_parse_lyb_data(ctx, data, options, &result, NULL);
- break;
- case LYD_SCHEMA:
- LOGINT(ctx);
- break;
- }
-
- return result;
-}
-
-API struct lyd_node *
-lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
-{
- struct lyd_node *result;
- size_t length;
- char *addr;
-
- LY_CHECK_ARG_RET(ctx, ctx, NULL);
- if (fd < 0) {
- LOGARG(ctx, fd);
- return NULL;
- }
-
- LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
- result = lyd_parse_mem(ctx, addr ? addr : "", format, options);
- if (addr) {
- ly_munmap(addr, length);
- }
-
- return result;
-}
-
-API struct lyd_node *
-lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
-{
- int fd;
- struct lyd_node *result;
- size_t len;
-
- LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
-
- fd = open(path, O_RDONLY);
- LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
-
- if (!format) {
+ if (!format && in->type == LY_IN_FILEPATH) {
/* unknown format - try to detect it from filename's suffix */
- len = strlen(path);
+ const char *path = in->method.fpath.filepath;
+ size_t len = strlen(path);
/* ignore trailing whitespaces */
for (; len > 0 && isspace(path[len - 1]); len--);
@@ -381,16 +299,157 @@
#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;
-#endif
- } /* else still unknown, try later to detect it from the content */
+ } /* else still unknown */
}
- result = lyd_parse_fd(ctx, fd, format, options);
- close(fd);
+ return format;
+}
- return result;
+API LY_ERR
+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_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);
+
+ format = lyd_parse_get_format(in, format);
+ LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
+
+ LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
+
+ switch (format) {
+ case LYD_XML:
+ return lyd_parse_xml_data(ctx, in->current, parse_options, validate_options, tree);
+#if 0
+ case LYD_JSON:
+ return lyd_parse_json_data(ctx, in->current, parse_options, validate_options, tree);
+#endif
+ case LYD_LYB:
+ return lyd_parse_lyb_data(ctx, in->current, parse_options, validate_options, tree, NULL);
+ 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 */
+
+ LOGINT_RET(ctx);
+}
+
+API LY_ERR
+lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree)
+{
+ LY_ERR ret;
+ struct ly_in *in;
+
+ LY_CHECK_RET(ly_in_new_memory(data, &in));
+ ret = lyd_parse_data(ctx, in, format, parse_options, validate_options, tree);
+
+ ly_in_free(in, 0);
+ return ret;
+}
+
+API LY_ERR
+lyd_parse_data_fd(const struct ly_ctx *ctx, int fd, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree)
+{
+ LY_ERR ret;
+ struct ly_in *in;
+
+ LY_CHECK_RET(ly_in_new_fd(fd, &in));
+ ret = lyd_parse_data(ctx, in, format, parse_options, validate_options, tree);
+
+ ly_in_free(in, 0);
+ return ret;
+}
+
+API LY_ERR
+lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree)
+{
+ LY_ERR ret;
+ struct ly_in *in;
+
+ LY_CHECK_RET(ly_in_new_filepath(path, 0, &in));
+ ret = lyd_parse_data(ctx, in, format, parse_options, validate_options, tree);
+
+ ly_in_free(in, 0);
+ return ret;
+}
+
+
+API LY_ERR
+lyd_parse_rpc(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **op)
+{
+ LY_CHECK_ARG_RET(ctx, ctx, in, tree, LY_EINVAL);
+
+ format = lyd_parse_get_format(in, format);
+ LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
+
+ switch (format) {
+ case LYD_XML:
+ return lyd_parse_xml_rpc(ctx, in->current, tree, op);
+#if 0
+ case LYD_JSON:
+ return lyd_parse_json_rpc(ctx, in->current, tree, op);
+#endif
+ case LYD_LYB:
+ return lyd_parse_lyb_rpc(ctx, in->current, tree, op, NULL);
+ case LYD_SCHEMA:
+ LOGINT_RET(ctx);
+ }
+
+ LOGINT_RET(ctx);
+}
+
+API LY_ERR
+lyd_parse_reply(const struct lyd_node *request, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **op)
+{
+ LY_CHECK_ARG_RET(NULL, request, LY_EINVAL);
+ LY_CHECK_ARG_RET(LYD_NODE_CTX(request), in, tree, LY_EINVAL);
+
+ format = lyd_parse_get_format(in, format);
+ LY_CHECK_ARG_RET(LYD_NODE_CTX(request), format, LY_EINVAL);
+
+ switch (format) {
+ case LYD_XML:
+ return lyd_parse_xml_reply(request, in->current, tree, op);
+#if 0
+ case LYD_JSON:
+ return lyd_parse_json_reply(request, in->current, tree, op);
+#endif
+ case LYD_LYB:
+ return lyd_parse_lyb_reply(request, in->current, tree, op, NULL);
+ case LYD_SCHEMA:
+ LOGINT_RET(LYD_NODE_CTX(request));
+ }
+
+ LOGINT_RET(LYD_NODE_CTX(request));
+}
+
+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);
+
+ format = lyd_parse_get_format(in, format);
+ LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
+
+ switch (format) {
+ case LYD_XML:
+ return lyd_parse_xml_notif(ctx, in->current, tree, ntf);
+#if 0
+ case LYD_JSON:
+ return lyd_parse_json_notif(ctx, in->current, tree, ntf);
+#endif
+ case LYD_LYB:
+ return lyd_parse_lyb_notif(ctx, in->current, tree, ntf, NULL);
+ case LYD_SCHEMA:
+ LOGINT_RET(ctx);
+ }
+
+ LOGINT_RET(ctx);
}
LY_ERR
diff --git a/src/tree_data.h b/src/tree_data.h
index ff040f9..f891c45 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -433,89 +433,6 @@
};
/**
- * @defgroup dataparseroptions Data parser options
- * @ingroup datatree
- *
- * Various options to change the data tree parsers behavior.
- *
- * Default parser behavior:
- * - complete input file is always parsed. In case of XML, even not well-formed XML document (multiple top-level
- * elements) is parsed in its entirety,
- * - parser silently ignores data without matching schema node definition,
- * - list instances are checked whether they have all the keys, error is raised if not.
- *
- * Default parser validation behavior:
- * - the provided data are expected to provide complete datastore content (both the configuration and state data)
- * and performs data validation according to all YANG rules, specifics follow,
- * - list instances are expected to have all the keys (it is not checked),
- * - instantiated (status) obsolete data print a warning,
- * - all types are fully resolved (leafref/instance-identifier targets, unions) and must be valid (lists have
- * all the keys, leaf(-lists) correct values),
- * - when statements on existing nodes are evaluated, if not satisfied, a validation error is raised,
- * - if-feature statements are evaluated,
- * - invalid multiple data instances/data from several cases cause a validation error,
- * - default values are added.
- * @{
- */
-
-#define LYD_OPT_PARSE_ONLY 0x0001 /**< Data will be only parsed and no validation will be performed. When statements
- are kept unevaluated, union types may not be fully resolved, if-feature
- statements are not checked, and default values are not added (only the ones
- parsed are present). */
-#define LYD_OPT_TRUSTED 0x0002 /**< Data are considered trusted so they will be parsed as validated. If the parsed
- data are not valid, using this flag may lead to some unexpected behavior!
- This flag can be used only with #LYD_OPT_PARSE_ONLY. */
-#define LYD_OPT_STRICT 0x0004 /**< Instead of silently ignoring data without schema definition raise an error.
- Do not combine with #LYD_OPT_OPAQ. */
-#define LYD_OPT_OPAQ 0x0008 /**< Instead of silently ignoring data without definition, parse them into
- an opaq node. Do not combine with #LYD_OPT_STRICT. */
-#define LYD_OPT_NO_STATE 0x0010 /**< Forbid state data in the parsed data. */
-#define LYD_OPT_LYB_MOD_UPDATE 0x0020 /**< Only for LYB format, allow parsing data printed using a specific module
- revision to be loaded even with a module with the same name but newer
- revision. */
-
-#define LYD_OPT_MASK 0xFFFF /**< Mask for all the parser options. */
-
-/** @} dataparseroptions */
-
-/**
- * @defgroup datavalidationoptions Data validation options
- * @ingroup datatree
- *
- * Various options to change data validation behaviour, both for the parser and separate validation.
- *
- * Default separate validation behavior:
- * - the provided data are expected to provide complete datastore content (both the configuration and state data)
- * and performs data validation according to all YANG rules, specifics follow,
- * - instantiated (status) obsolete data print a warning,
- * - all types are fully resolved (leafref/instance-identifier targets, unions) and must be valid (lists have
- * all the keys, leaf(-lists) correct values),
- * - when statements on existing nodes are evaluated. Depending on the previous when state (from previous validation
- * or parsing), the node is silently auto-deleted if the state changed from true to false, otherwise a validation error
- * is raised if it evaluates to false,
- * - if-feature statements are evaluated,
- * - data from several cases behave based on their previous state (from previous validation or parsing). If there existed
- * already a case and another one was added, the previous one is silently auto-deleted. Otherwise (if data from 2 or
- * more cases were created) a validation error is raised,
- * - default values are added.
- *
- * @{
- */
-
-#define LYD_VALOPT_NO_STATE 0x00010000 /**< Consider state data not allowed and raise an error if they are found. */
-#define LYD_VALOPT_DATA_ONLY 0x00020000 /**< Validate only modules whose data actually exist. */
-#define LYD_VALOPT_INPUT 0x00040000 /**< Validate RPC/action request (input parameters). */
-#define LYD_VALOPT_OUTPUT 0x00080000 /**< Validate RPC/action reply (output parameters). */
-
-#define LYD_VALOPT_MASK 0xFFFF0000 /**< Mask for all the validation options. */
-
-/** @} datavalidationoptions */
-
-//#define LYD_OPT_VAL_DIFF 0x40000 /**< Flag only for validation, store all the data node changes performed by the validation
-// in a diff structure. */
-//#define LYD_OPT_DATA_TEMPLATE 0x1000000 /**< Data represents YANG data template. */
-
-/**
* @defgroup children_options Children traversal options.
* @ingroup datatree
*/
@@ -544,62 +461,6 @@
const struct lys_module *lyd_owner_module(const struct lyd_node *node);
/**
- * @brief Parse (and validate) data from memory.
- *
- * In case of LY_XML format, the data string is parsed completely. It means that when it contains
- * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
- * returned data node is a root of the first tree with other trees connected via the next pointer.
- * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
- *
- * @param[in] ctx Context to connect with the data tree being built here.
- * @param[in] data Serialized data in the specified format.
- * @param[in] format Format of the input data to be parsed.
- * @param[in] options Parser and validation options, see @ref parseroptions.
- * @return Pointer to the built data tree or NULL in case of empty \p data. To free the returned structure,
- * use lyd_free_all().
- * @return NULL in case of error. The error information can be then obtained using ly_err* functions.
- */
-struct lyd_node *lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options);
-
-/**
- * @brief Read (and validate) data from the given file descriptor.
- *
- * \note Current implementation supports only reading data from standard (disk) file, not from sockets, pipes, etc.
- *
- * In case of LY_XML format, the file content is parsed completely. It means that when it contains
- * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
- * returned data node is a root of the first tree with other trees connected via the next pointer.
- * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
- *
- * @param[in] ctx Context to connect with the data tree being built here.
- * @param[in] fd The standard file descriptor of the file containing the data tree in the specified format.
- * @param[in] format Format of the input data to be parsed.
- * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_PARSE_ONLY implicitly.
- * @return Pointer to the built data tree or NULL in case of empty file. To free the returned structure,
- * use lyd_free_all().
- * @return NULL in case of error. The error information can be then obtained using ly_err* functions.
- */
-struct lyd_node *lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options);
-
-/**
- * @brief Read (and validate) data from the given file path.
- *
- * In case of LY_XML format, the file content is parsed completely. It means that when it contains
- * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
- * returned data node is a root of the first tree with other trees connected via the next pointer.
- * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
- *
- * @param[in] ctx Context to connect with the data tree being built here.
- * @param[in] path Path to the file containing the data tree in the specified format.
- * @param[in] format Format of the input data to be parsed.
- * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_PARSE_ONLY implicitly.
- * @return Pointer to the built data tree or NULL in case of empty file. To free the returned structure,
- * use lyd_free_all().
- * @return NULL in case of error. The error information can be then obtained using ly_err* functions.
- */
-struct lyd_node *lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options);
-
-/**
* @brief Learn the length of LYB data.
*
* @param[in] data LYB data to examine.
@@ -609,44 +470,6 @@
int lyd_lyb_data_length(const char *data);
/**
- * @brief Fully validate a data tree.
- *
- * @param[in,out] tree Data tree to recursively validate. May be changed by validation.
- * @param[in] ctx libyang context. Can be NULL if @p tree is set.
- * @param[in] val_opts Validation options (@ref datavalidationoptions).
- * @return LY_SUCCESS on success.
- * @return LY_ERR error on error.
- */
-LY_ERR lyd_validate(struct lyd_node **tree, const struct ly_ctx *ctx, int val_opts);
-
-/**
- * @brief Fully validate a data tree.
- *
- * @param[in,out] tree Data tree to recursively validate. May be changed by validation.
- * @param[in] modules Array of modules to validate.
- * @param[in] mod_count Number of @p modules.
- * @param[in] val_opts Validation options (@ref datavalidationoptions).
- * @return LY_SUCCESS on success.
- * @return LY_ERR error on error.
- */
-LY_ERR lyd_validate_modules(struct lyd_node **tree, const struct lys_module **modules, int mod_count, int val_opts);
-
-/**
- * @brief Validate an RPC/action, notification, or RPC/action reply.
- *
- * @param[in,out] op_tree Operation tree with any parents. It can point to the operation itself or any of
- * its parents, only the operation subtree is actually validated.
- * @param[in] tree Tree to be used for validating references from the operation subtree.
- * @param[in] val_opts Specific validation option (@ref datavalidationoptions):
- * 0 - no validation option for validation notifications,
- * ::LYD_VALOPT_INPUT - for validating RPC/action request (input),
- * ::LYD_VALOPT_OUTPUT - for validatin RPC/action reply (output).
- * @return LY_SUCCESS on success.
- * @return LY_ERR error on error.
- */
-LY_ERR lyd_validate_op(struct lyd_node *op_tree, const struct lyd_node *tree, int val_opts);
-
-/**
* @brief Create a new inner node in the data tree.
*
* @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 36d540c..aa7fd63 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -22,6 +22,7 @@
#include "hash_table.h"
#include "log.h"
#include "lyb.h"
+#include "parser_data.h"
#include "set.h"
#include "tree.h"
#include "tree_data.h"
@@ -170,7 +171,7 @@
struct lyd_meta *meta2, *prev_meta = NULL;
if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
- if (options & LYD_OPT_TRUSTED) {
+ if (options & LYD_PARSE_TRUSTED) {
/* just set it to true */
node->flags |= LYD_WHEN_TRUE;
} else {
@@ -179,7 +180,7 @@
}
}
- if (options & LYD_OPT_TRUSTED) {
+ if (options & LYD_PARSE_TRUSTED) {
/* node is valid */
node->flags &= ~LYD_NEW;
}
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 4c91bf5..a2a3769 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -294,20 +294,19 @@
*
* @param[in] ctx libyang context
* @param[in] data Pointer to the XML data to parse.
- * @param[in] options @ref dataparseroptions
+ * @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.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree);
+LY_ERR lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int parse_options, int validate_options, struct lyd_node **tree);
/**
* @brief Parse XML string as YANG RPC/action invocation.
*
- * Optional \<rpc\> envelope element, if present, is [checked](https://tools.ietf.org/html/rfc6241#section-4.1) and all
- * its XML attributes parsed. In that case an RPC is expected to be parsed.
- *
- * Can be followed by optional \<action\> envelope element, which is also
- * [checked](https://tools.ietf.org/html/rfc7950#section-7.15.2) and then an action is expected to be parsed.
+ * Optional \<rpc\> envelope element is accepted if present. It is [checked](https://tools.ietf.org/html/rfc6241#section-4.1) and all
+ * its XML attributes are parsed. As a content of the enveloper, an RPC data or \<action\> envelope element is expected. The \<action\> envelope element 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] data Pointer to the XML data to parse.
@@ -350,12 +349,13 @@
*
* @param[in] ctx libyang context
* @param[in] data Pointer to the input data to parse.
- * @param[in] options @ref dataparseroptions
+ * @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] parsed_bytes Optional number of parsed bytes.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree, int *parsed_bytes);
+LY_ERR lyd_parse_lyb_data(const struct ly_ctx *ctx, const char *data, int parse_options, int validate_options, struct lyd_node **tree, int *parsed_bytes);
/**
* @brief Parse binary data as YANG RPC/action invocation.
@@ -367,7 +367,7 @@
* @param[out] parsed_bytes Optional number of parsed bytes.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op,
+LY_ERR lyd_parse_lyb_rpc(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op,
int *parsed_bytes);
/**
@@ -380,7 +380,7 @@
* @param[out] parsed_bytes Optional number of parsed bytes.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb_notif(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf,
+LY_ERR lyd_parse_lyb_notif(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf,
int *parsed_bytes);
/**
@@ -393,7 +393,7 @@
* @param[out] parsed_bytes Optional number of parsed bytes.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb_reply(struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op,
+LY_ERR lyd_parse_lyb_reply(const struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op,
int *parsed_bytes);
/**
diff --git a/src/validation.c b/src/validation.c
index 22919f0..f75dc04 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -22,6 +22,7 @@
#include "config.h"
#include "hash_table.h"
#include "log.h"
+#include "parser_data.h"
#include "plugins_types.h"
#include "set.h"
#include "tree.h"
@@ -739,17 +740,17 @@
static LY_ERR
lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lysc_node *sparent,
- const struct lysc_module *mod, int val_opts)
+ const struct lysc_module *mod, int val_opts, LYD_VALIDATE_OP op)
{
const struct lysc_node *snode = NULL;
struct lysc_node_list *slist;
int getnext_opts;
- getnext_opts = LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | (val_opts & LYD_VALOPT_OUTPUT ? LYS_GETNEXT_OUTPUT : 0);
+ getnext_opts = LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | (op == LYD_VALIDATE_OP_REPLY ? LYS_GETNEXT_OUTPUT : 0);
/* disabled nodes are skipped by lys_getnext */
while ((snode = lys_getnext(snode, sparent, mod, getnext_opts))) {
- if ((val_opts & LYD_VALOPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
+ if ((val_opts & LYD_VALIDATE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
continue;
}
@@ -775,7 +776,7 @@
if (snode->nodetype & (LYS_CHOICE | LYS_CASE)) {
/* go recursively for schema-only nodes */
- LY_CHECK_RET(lyd_validate_siblings_schema_r(first, snode, mod, val_opts));
+ LY_CHECK_RET(lyd_validate_siblings_schema_r(first, snode, mod, val_opts, op));
}
}
@@ -799,7 +800,7 @@
}
static LY_ERR
-lyd_validate_must(const struct lyd_node *node, int val_opts)
+lyd_validate_must(const struct lyd_node *node, LYD_VALIDATE_OP op)
{
struct lyxp_set xp_set;
struct lysc_must *musts;
@@ -828,9 +829,9 @@
break;
case LYS_RPC:
case LYS_ACTION:
- if (val_opts & LYD_VALOPT_INPUT) {
+ if (op == LYD_VALIDATE_OP_RPC) {
musts = ((struct lysc_action *)node->schema)->input.musts;
- } else if (val_opts & LYD_VALOPT_OUTPUT) {
+ } else if (op == LYD_VALIDATE_OP_REPLY) {
musts = ((struct lysc_action *)node->schema)->output.musts;
} else {
LOGINT(LYD_NODE_CTX(node));
@@ -871,7 +872,7 @@
}
LY_ERR
-lyd_validate_final_r(struct lyd_node *first, const struct lysc_node *sparent, const struct lys_module *mod, int val_opts)
+lyd_validate_final_r(struct lyd_node *first, const struct lysc_node *sparent, const struct lys_module *mod, int val_opts, LYD_VALIDATE_OP op)
{
struct lyd_node *next, *node;
const struct lysc_node *snode;
@@ -891,13 +892,13 @@
}
/* no state/input/output data */
- if ((val_opts & LYD_VALOPT_NO_STATE) && (node->schema->flags & LYS_CONFIG_R)) {
+ if ((val_opts & LYD_VALIDATE_NO_STATE) && (node->schema->flags & LYS_CONFIG_R)) {
LOGVAL(LYD_NODE_CTX(node), LY_VLOG_LYD, node, LY_VCODE_INNODE, "state", node->schema->name);
return LY_EVALID;
- } else if ((val_opts & LYD_VALOPT_INPUT) && (node->schema->flags & LYS_CONFIG_R)) {
+ } else if ((op == LYD_VALIDATE_OP_RPC) && (node->schema->flags & LYS_CONFIG_R)) {
LOGVAL(LYD_NODE_CTX(node), LY_VLOG_LYD, node, LY_VCODE_INNODE, "output", node->schema->name);
return LY_EVALID;
- } else if ((val_opts & LYD_VALOPT_OUTPUT) && (node->schema->flags & LYS_CONFIG_W)) {
+ } else if ((op == LYD_VALIDATE_OP_REPLY) && (node->schema->flags & LYS_CONFIG_W)) {
LOGVAL(LYD_NODE_CTX(node), LY_VLOG_LYD, node, LY_VCODE_INNODE, "input", node->schema->name);
return LY_EVALID;
}
@@ -912,17 +913,17 @@
}
/* node's musts */
- LY_CHECK_RET(lyd_validate_must(node, val_opts));
+ LY_CHECK_RET(lyd_validate_must(node, op));
/* node value including if-feature was checked by plugins */
}
/* validate schema-based restrictions */
- LY_CHECK_RET(lyd_validate_siblings_schema_r(first, sparent, mod ? mod->compiled : NULL, val_opts));
+ LY_CHECK_RET(lyd_validate_siblings_schema_r(first, sparent, mod ? mod->compiled : NULL, val_opts, op));
LY_LIST_FOR(first, node) {
/* validate all children recursively */
- LY_CHECK_RET(lyd_validate_final_r(lyd_node_children(node, 0), node->schema, NULL, val_opts));
+ LY_CHECK_RET(lyd_validate_final_r(lyd_node_children(node, 0), node->schema, NULL, val_opts, op));
/* set default for containers */
if ((node->schema->nodetype == LYS_CONTAINER) && !(node->schema->flags & LYS_PRESENCE)) {
@@ -957,7 +958,7 @@
}
while ((iter = lys_getnext(iter, sparent, mod ? mod->compiled : NULL, LYS_GETNEXT_WITHCHOICE))) {
- if ((val_opts & LYD_VALOPT_NO_STATE) && (iter->flags & LYS_CONFIG_R)) {
+ if ((val_opts & LYD_VALIDATE_NO_STATE) && (iter->flags & LYS_CONFIG_R)) {
continue;
}
@@ -1035,9 +1036,12 @@
return LY_SUCCESS;
}
+/**
+ * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
+ */
static LY_ERR
lyd_validate_subtree(struct lyd_node *root, struct ly_set *type_check, struct ly_set *type_meta_check,
- struct ly_set *when_check, int val_opts)
+ struct ly_set *when_check, int validate_options)
{
const struct lyd_meta *meta;
struct lyd_node *next, *node;
@@ -1059,7 +1063,7 @@
/* add nested defaults */
LY_CHECK_RET(lyd_validate_defaults_r(node, lyd_node_children_p((struct lyd_node *)node), NULL, NULL, type_check,
- when_check, val_opts));
+ when_check, validate_options));
}
if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
@@ -1086,14 +1090,9 @@
LY_CHECK_ARG_RET(NULL, tree, *tree || ctx || (modules && mod_count), LY_EINVAL);
- if (val_opts & ~LYD_VALOPT_MASK) {
- LOGERR(ctx, LY_EINVAL, "Some invalid flags passed to validation.");
- return LY_EINVAL;
- }
-
next = *tree;
while (1) {
- if (val_opts & LYD_VALOPT_DATA_ONLY) {
+ if (val_opts & LYD_VALIDATE_PRESENT) {
mod = lyd_data_next_module(&next, &first);
} else {
mod = lyd_mod_next_module(next, modules, mod_count, ctx, &i, &first);
@@ -1124,7 +1123,7 @@
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, val_opts), cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, val_opts, 0), cleanup);
}
cleanup:
@@ -1189,31 +1188,31 @@
}
API LY_ERR
-lyd_validate_op(struct lyd_node *op_tree, const struct lyd_node *tree, int val_opts)
+lyd_validate_op(struct lyd_node *op_tree, const struct lyd_node *tree, LYD_VALIDATE_OP op)
{
LY_ERR ret;
- struct lyd_node *tree_sibling, *op_node, *op, *op_parent;
+ struct lyd_node *tree_sibling, *op_subtree, *op_next, *op_node, *op_parent;
struct ly_set type_check = {0}, type_meta_check = {0}, when_check = {0};
LY_CHECK_ARG_RET(NULL, op_tree, !op_tree->parent, !tree || !tree->parent,
- !val_opts || (val_opts == LYD_VALOPT_INPUT) || (val_opts == LYD_VALOPT_OUTPUT), LY_EINVAL);
+ (op == LYD_VALIDATE_OP_NOTIF) || (op == LYD_VALIDATE_OP_RPC) || (op == LYD_VALIDATE_OP_REPLY), LY_EINVAL);
/* find the operation/notification */
- LYD_TREE_DFS_BEGIN(op_tree, op_node, op) {
- if ((val_opts & (LYD_VALOPT_INPUT | LYD_VALOPT_OUTPUT)) && (op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
+ LYD_TREE_DFS_BEGIN(op_tree, op_next, op_node) {
+ if ((op == LYD_VALIDATE_OP_RPC || op == LYD_VALIDATE_OP_REPLY) && (op_node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
break;
- } else if (!val_opts && (op->schema->nodetype == LYS_NOTIF)) {
+ } else if ((op == LYD_VALIDATE_OP_NOTIF) && (op_node->schema->nodetype == LYS_NOTIF)) {
break;
}
- LYD_TREE_DFS_END(op_tree, op_node, op);
+ LYD_TREE_DFS_END(op_tree, op_next, op_node);
}
- if (val_opts & (LYD_VALOPT_INPUT | LYD_VALOPT_OUTPUT)) {
- if (!(op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
+ if (op == LYD_VALIDATE_OP_RPC || op == LYD_VALIDATE_OP_REPLY) {
+ if (!(op_node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
LOGERR(LYD_NODE_CTX(op_tree), LY_EINVAL, "No RPC/action to validate found.");
return LY_EINVAL;
}
} else {
- if (op->schema->nodetype != LYS_NOTIF) {
+ if (op_node->schema->nodetype != LYS_NOTIF) {
LOGERR(LYD_NODE_CTX(op_tree), LY_EINVAL, "No notification to validate found.");
return LY_EINVAL;
}
@@ -1225,38 +1224,38 @@
}
/* merge op_tree into tree */
- lyd_val_op_merge_find(op_tree, op, tree, &op_node, &tree_sibling);
- op_parent = (struct lyd_node *)op_node->parent;
- lyd_unlink_tree(op_node);
- lyd_insert_node(NULL, (struct lyd_node **)&tree_sibling, op_node);
+ lyd_val_op_merge_find(op_tree, op_node, tree, &op_subtree, &tree_sibling);
+ op_parent = (struct lyd_node *)op_subtree->parent;
+ lyd_unlink_tree(op_subtree);
+ lyd_insert_node(NULL, (struct lyd_node **)&tree_sibling, op_subtree);
if (!tree) {
tree = tree_sibling;
}
/* prevalidate whole operation subtree */
- LY_CHECK_GOTO(ret = lyd_validate_subtree(op, &type_check, &type_meta_check, &when_check, val_opts), cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_subtree(op_node, &type_check, &type_meta_check, &when_check, 0), cleanup);
/* finish incompletely validated terminal values/attributes and when conditions on the full tree */
LY_CHECK_GOTO(ret = lyd_validate_unres((struct lyd_node **)&tree, &when_check, &type_check, &type_meta_check,
LYD_JSON, lydjson_resolve_prefix, NULL), cleanup);
/* perform final validation of the operation/notification */
- lyd_validate_obsolete(op);
- if (lysc_node_is_disabled(op->schema, 1)) {
- LOGVAL(LYD_NODE_CTX(op_tree), LY_VLOG_LYD, op, LY_VCODE_NOIFF, op->schema->name);
+ lyd_validate_obsolete(op_node);
+ if (lysc_node_is_disabled(op_node->schema, 1)) {
+ LOGVAL(LYD_NODE_CTX(op_tree), LY_VLOG_LYD, op_node, LY_VCODE_NOIFF, op_node->schema->name);
ret = LY_EVALID;
goto cleanup;
}
- LY_CHECK_GOTO(ret = lyd_validate_must(op, val_opts), cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_must(op_node, op), cleanup);
/* final validation of all the descendants */
- LY_CHECK_GOTO(ret = lyd_validate_final_r(lyd_node_children(op, 0), op->schema, NULL, val_opts), cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_final_r(lyd_node_children(op_node, 0), op_node->schema, NULL, 0, op), cleanup);
cleanup:
/* restore operation tree */
- lyd_unlink_tree(op_node);
+ lyd_unlink_tree(op_subtree);
if (op_parent) {
- lyd_insert_node(op_parent, NULL, op_node);
+ lyd_insert_node(op_parent, NULL, op_subtree);
}
ly_set_erase(&type_check, NULL);
diff --git a/src/validation.h b/src/validation.h
index 734d17c..9c6d156 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -54,10 +54,11 @@
* @param[in] sparent Schema parent of the siblings, NULL for top-level siblings.
* @param[in] mod Module of the siblings, NULL for nested siblings.
* @param[in] val_opts Validation options (@ref datavalidationoptions).
+ * @param[in] op Operation to validate (@ref datavalidateop) or 0 for data tree
* @return LY_ERR value.
*/
LY_ERR lyd_validate_final_r(struct lyd_node *first, const struct lysc_node *sparent, const struct lys_module *mod,
- int val_opts);
+ int val_opts, LYD_VALIDATE_OP op);
/**
* @brief Check the existence and create any non-existing default siblings, recursively for the created nodes.
diff --git a/src/xpath.c b/src/xpath.c
index fae13dc..b14ee8c 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -33,6 +33,7 @@
#include "context.h"
#include "dict.h"
#include "hash_table.h"
+#include "parser_data.h"
#include "path.h"
#include "plugins_types.h"
#include "printer.h"
@@ -412,14 +413,13 @@
if (any->value_type == LYD_ANYDATA_LYB) {
/* try to parse it into a data tree */
- tree = lyd_parse_mem((struct ly_ctx *)LYD_NODE_CTX(node), any->value.mem, LYD_LYB,
- LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT);
- if (!ly_errcode(LYD_NODE_CTX(node))) {
+ if (lyd_parse_data_mem((struct ly_ctx *)LYD_NODE_CTX(node), any->value.mem, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
/* successfully parsed */
free(any->value.mem);
any->value.tree = tree;
any->value_type = LYD_ANYDATA_DATATREE;
}
+ /* error is covered by the following switch where LYD_ANYDATA_LYB causes failure */
}
switch (any->value_type) {
@@ -431,7 +431,7 @@
break;
case LYD_ANYDATA_DATATREE:
LY_CHECK_RET(ly_out_new_memory(&buf, 0, &out));
- rc = lyd_print(out, any->value.tree, LYD_XML, LYDP_WITHSIBLINGS);
+ rc = lyd_print(out, any->value.tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
ly_out_free(out, NULL, 0);
LY_CHECK_RET(rc < 0, -rc);
break;