data types CHANGE validate instance-identifier values
Quite a big patch dut to the problems with instance-identifiers:
- different format in XML and JSON
- prefixes must be resolved correctly even in predicates to be able to
compare values in predicates with other values (even another
instance-identifier, prefixed identityrefs or, in contrast, strings
where 'something:' is not a prefix).
diff --git a/src/common.c b/src/common.c
index 76f3b84..3c36baa 100644
--- a/src/common.c
+++ b/src/common.c
@@ -425,9 +425,9 @@
}
LY_ERR
-ly_parse_instance_predicate(const char **pred, size_t limit,
- const char **prefix, size_t *prefix_len, const char **id, size_t *id_len, const char **value, size_t *value_len,
- const char **errmsg)
+ly_parse_instance_predicate(const char **pred, size_t limit, LYD_FORMAT format,
+ const char **prefix, size_t *prefix_len, const char **id, size_t *id_len, const char **value, size_t *value_len,
+ const char **errmsg)
{
LY_ERR ret = LY_EVALID;
const char *in = *pred;
@@ -473,6 +473,11 @@
*errmsg = "Invalid node-identifier.";
goto error;
}
+ if (format == LYD_XML && !(*prefix)) {
+ /* all node names MUST be qualified with explicit namespace prefix */
+ *errmsg = "Missing prefix of a node name.";
+ goto error;
+ }
offset = in - *pred;
in = *pred;
expr = 2;
@@ -500,7 +505,7 @@
goto error;
}
*value = &in[offset];
- for (;offset < limit && in[offset] != quot; offset++);
+ for (;offset < limit && (in[offset] != quot || (offset && in[offset - 1] == '\\')); offset++);
if (in[offset] == quot) {
*value_len = &in[offset] - *value;
offset++;
diff --git a/src/common.h b/src/common.h
index 437a90f..1c18a13 100644
--- a/src/common.h
+++ b/src/common.h
@@ -403,18 +403,19 @@
* (even for error case, so it can be used to determine which substring caused failure).
* @param[in] limit Limiting length of the @p pred. Function expects NULL terminated string which is not overread.
* The limit value is not checked with each character, so it can be overread and the failure is detected later.
+ * @param[in] format Input format of the data containing the @p pred.
* @param[out] prefix Start of the node-identifier's prefix if any, NULL in case of pos or leaf-list-predicate rules.
* @param[out] prefix_len Length of the parsed @p prefix.
* @param[out] id Start of the node-identifier's identifier string, NULL in case of pos rule, "." in case of leaf-list-predicate rule.
* @param[out] id_len Length of the parsed @p id.
- * @param[out] value Start of the quoted-string (without quotation marks), NULL in case of pos rule.
+ * @param[out] value Start of the quoted-string (without quotation marks), not NULL in case of success.
* @param[out] value_len Length of the parsed @p value.
* @param[out] errmsg Error message string in case of error.
* @return LY_SUCCESS in case a complete predicate was parsed.
* @return LY_EVALID in case of invalid predicate form.
* @return LY_EINVAL in case of reaching @p limit when parsing @p pred.
*/
-LY_ERR ly_parse_instance_predicate(const char **pred, size_t limit,
+LY_ERR ly_parse_instance_predicate(const char **pred, size_t limit, LYD_FORMAT format,
const char **prefix, size_t *prefix_len, const char **id, size_t *id_len,
const char **value, size_t *value_len, const char **errmsg);
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 8f625c7..6e15b60 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -254,7 +254,7 @@
value = "";
value_len = 0;
}
- ret = lyd_value_parse((struct lyd_node_term*)cur, value, value_len, dynamic, lydxml_resolve_prefix, ctx, NULL);
+ ret = lyd_value_parse((struct lyd_node_term*)cur, value, value_len, dynamic, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
if (ret == LY_EINCOMPLETE) {
ly_set_add(&ctx->incomplete_type_validation, cur, LY_SET_OPT_USEASLIST);
} else if (ret) {
@@ -315,7 +315,8 @@
*tree = *result;
}
/* validate and store the value of the node */
- ret = lyd_value_parse(node, node->value.canonized, strlen(node->value.canonized), 0, lydxml_resolve_prefix, ctx, trees);
+ ret = lyd_value_parse(node, node->value.canonized, node->value.canonized ? strlen(node->value.canonized) : 0, 0,
+ lydxml_resolve_prefix, ctx, LYD_XML, trees);
LY_ARRAY_FREE(trees);
if (ret) {
lyd_free_all(*result);
diff --git a/src/plugins_types.c b/src/plugins_types.c
index fb0d899..7564591 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -25,6 +25,8 @@
#include "dict.h"
#include "tree_schema.h"
#include "tree_schema_internal.h"
+#include "tree_data_internal.h"
+#include "xml.h"
#include "xpath.h"
API LY_ERR
@@ -58,6 +60,58 @@
return LY_EVALID;
}
+API struct lyd_value_prefix *
+ly_type_get_prefixes(struct ly_ctx *ctx, const char *value, size_t value_len, ly_clb_resolve_prefix get_prefix, void *parser)
+{
+ LY_ERR ret;
+ const char *start, *stop;
+ struct lyd_value_prefix *prefixes = NULL;
+ const struct lys_module *mod;
+ unsigned int u;
+
+ for (stop = start = value; (size_t)(stop - value) <= value_len; stop++, start++) {
+ if (is_xmlqnamestartchar(*start)) {
+ int i = 1;
+ while (is_xmlqnamechar(stop[i])) {
+ i++;
+ }
+ if (stop[i] == ':') {
+ /* we have a possible prefix */
+ struct lyd_value_prefix *p;
+ size_t len = &stop[i] - start;
+ mod = NULL;
+
+ LY_ARRAY_FOR(prefixes, u) {
+ if (!strncmp(prefixes[u].prefix, start, len) && prefixes[u].prefix[len] == '\0') {
+ mod = prefixes[u].mod;
+ break;
+ }
+ }
+ if (!mod) {
+ mod = get_prefix(ctx, start, len, parser);
+ if (mod) {
+ LY_ARRAY_NEW_GOTO(ctx, prefixes, p, ret, error);
+ p->mod = mod;
+ p->prefix = lydict_insert(ctx, start, len);
+ }
+ } /* else the prefix already present */
+ }
+ start = stop = &stop[i];
+ }
+ }
+
+ return prefixes;
+
+error:
+ LY_ARRAY_FOR(prefixes, u) {
+ lydict_remove(ctx, prefixes[u].prefix);
+ }
+ LY_ARRAY_FREE(prefixes);
+
+ (void)ret;
+ return NULL;
+}
+
API LY_ERR
ly_type_parse_uint(const char *datatype, int base, uint64_t max, const char *value, size_t value_len, uint64_t *ret, struct ly_err_item **err)
{
@@ -325,8 +379,8 @@
*/
static LY_ERR
ly_type_validate_int(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **priv)
{
LY_ERR ret;
@@ -415,8 +469,8 @@
*/
static LY_ERR
ly_type_validate_uint(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **priv)
{
LY_ERR ret;
@@ -487,8 +541,8 @@
*/
static LY_ERR
ly_type_validate_decimal64(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **priv)
{
int64_t d;
@@ -587,19 +641,21 @@
*/
static LY_ERR
ly_type_validate_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **UNUSED(priv))
{
size_t start = 0, stop = 0, count = 0, u, termination = 0;
struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
char *errmsg;
+ LY_CHECK_ARG_RET(ctx, value, LY_EINVAL);
+
/* initiate */
*err = NULL;
/* validate characters and remember the number of octets for length validation */
- if (value && value_len) {
+ if (value_len) {
/* silently skip leading/trailing whitespaces */
for (start = 0; (start < value_len) && isspace(value[start]); start++);
for (stop = value_len - 1; stop > start && isspace(value[stop]); stop--);
@@ -654,7 +710,7 @@
}
if (options & LY_TYPE_OPTS_CANONIZE) {
- if (start != 0 || stop != value_len) {
+ if (start != 0 || (value_len && stop != value_len - 1)) {
*canonized = lydict_insert_zc(ctx, strndup(&value[start], stop + 1 - start));
} else if (options & LY_TYPE_OPTS_DYNAMIC) {
*canonized = lydict_insert_zc(ctx, (char*)value);
@@ -683,8 +739,8 @@
*/
static LY_ERR
ly_type_validate_string(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **UNUSED(priv))
{
struct lysc_type_str *type_str = (struct lysc_type_str *)type;
@@ -722,8 +778,8 @@
*/
static LY_ERR
ly_type_validate_bits(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **priv)
{
LY_ERR ret = LY_EVALID;
@@ -916,8 +972,8 @@
*/
static LY_ERR
ly_type_validate_enum(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **priv)
{
unsigned int u, v;
@@ -1001,8 +1057,8 @@
*/
static LY_ERR
ly_type_validate_boolean(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **priv)
{
int8_t i;
@@ -1072,8 +1128,8 @@
*/
static LY_ERR
ly_type_validate_empty(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
- ly_type_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser),
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **UNUSED(priv))
{
if (value_len) {
@@ -1089,6 +1145,18 @@
return LY_SUCCESS;
}
+/**
+ * @brief Comparison callback for built-in empty type.
+ *
+ * Implementation of the ly_type_compare_clb.
+ */
+static LY_ERR
+ly_type_compare_empty(const struct lyd_value *UNUSED(val1), const struct lyd_value *UNUSED(val2))
+{
+ /* empty has just one value, so empty data must be always the same */
+ return LY_SUCCESS;
+}
+
API LY_ERR
ly_type_identity_isderived(struct lysc_ident *base, struct lysc_ident *der)
{
@@ -1112,8 +1180,8 @@
*/
static LY_ERR
ly_type_validate_identityref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix get_prefix, void *parser,
- struct lyd_node *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+ ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT UNUSED(format),
+ const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
const char **canonized, struct ly_err_item **err, void **priv)
{
struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
@@ -1217,14 +1285,27 @@
}
/**
- * @brief Validation of instance-identifier - check presence of the specific node in the (data/schema) tree.
+ * @brief Comparison callback for built-in identityref type.
+ *
+ * Implementation of the ly_type_compare_clb.
+ */
+static LY_ERR
+ly_type_compare_identityref(const struct lyd_value *val1, const struct lyd_value *val2)
+{
+ if (val1->ident == val2->ident) {
+ return LY_SUCCESS;
+ }
+ return LY_EVALID;
+}
+
+/**
+ * @brief Helper function for ly_type_validate_instanceid() to check presence of the specific node in the (data/schema) tree.
*
* In the case the instance-identifier type does not require instance (@p require_instance is 0) or the data @p trees
* are not complete (called in the middle of data parsing), the @p token is checked only to match schema tree.
* Otherwise, the provided data @p trees are used to find instance of the node specified by the token and @p node_d as
* its parent.
*
- * @param[in] ctx libyang context
* @param[in] orig Complete instance-identifier expression for logging.
* @param[in] orig_len Length of the @p orig string.
* @param[in] options [Type plugin options ](@ref plugintypeopts) - only LY_TYPE_OPTS_INCOMPLETE_DATA is used.
@@ -1232,13 +1313,12 @@
* If the flag is zero, the data tree is not needed and the @p token is checked only by checking the schema tree.
* @param[in,out] token Pointer to the specific position inside the @p orig string where the node-identifier starts.
* The pointer is updated to point after the processed node-identifier.
- * @param[in,out] prefixes [Sized array](@ref sizedarrays) of known mappings between prefix used in the @p orig and modules from the context.
+ * @param[in] prefixes [Sized array](@ref sizedarrays) of known mappings between prefix used in the @p orig and modules from the context.
+ * @param[in] format Format of the input YANG data, since XML and JSON format differs in case of instance-identifiers.
* @param[in,out] node_s Parent schema node as input, resolved schema node as output. Alternative parameter for @p node_d
* in case the instance is not available (@p trees are not yet complete) or required.
* @param[in,out] node_d Parent data node as input, resolved data node instance as output. Alternative parameter for @p node_s
* in case the instance is required and @p trees are complete.
- * @param[in] get_prefix Callback to resolve (map it to a schema) prefix used in the @p token.
- * @param[in] parser Context data for @p get_prefix callback.
* @param[in] trees [Sized array](@ref sizedarrays)) of data trees where the data instance is supposed to be present.
* @param[out] errmsg Error message in case of failure. Function does not log on its own, instead it creates error message. Caller is supposed to
* free (or store somewhere) the returned message.
@@ -1246,55 +1326,48 @@
* @return LY_EMEM or LY_EVALID in case of failure or when the node is not present in the schema/data tree.
*/
static LY_ERR
-ly_type_validate_instanceid_checknodeid(struct ly_ctx *ctx, const char *orig, size_t orig_len, int options, int require_instance,
- const char **token, struct lyd_value_prefix **prefixes,
+ly_type_validate_instanceid_checknodeid(const char *orig, size_t orig_len, int options, int require_instance,
+ const char **token, struct lyd_value_prefix *prefixes, LYD_FORMAT format,
const struct lysc_node **node_s, const struct lyd_node **node_d,
- ly_type_resolve_prefix get_prefix, void *parser, struct lyd_node **trees,
- char **errmsg)
+ struct lyd_node **trees, char **errmsg)
{
const char *id, *prefix;
size_t id_len, prefix_len;
const struct lys_module *mod = NULL;
unsigned int u;
- int present_prefix = 0;
if (ly_parse_nodeid(token, &prefix, &prefix_len, &id, &id_len)) {
- asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value at character %lu.",
- (int)orig_len, orig, *token - orig + 1);
+ asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value at character %lu (%.*s).",
+ (int)orig_len, orig, *token - orig + 1, (int)(orig_len - (*token - orig)), *token);
return LY_EVALID;
}
if (!prefix || !prefix_len) {
- asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - all node names (%.*s) MUST be qualified with explicit namespace prefix.",
- (int)orig_len, orig, (int)id_len + 1, &id[-1]);
- return LY_EVALID;
- }
-
- /* map prefix to schema module */
- LY_ARRAY_FOR(*prefixes, u) {
- if (!strncmp((*prefixes)[u].prefix, prefix, prefix_len) && (*prefixes)[u].prefix[prefix_len] == '\0') {
- mod = (*prefixes)[u].mod;
- present_prefix = 1;
- break;
+ if (format == LYD_XML || (!*node_s && !*node_d)) {
+ asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - all node names (%.*s) MUST be qualified with explicit namespace prefix.",
+ (int)orig_len, orig, (int)id_len + 1, &id[-1]);
+ return LY_EVALID;
}
- }
- if (!mod && get_prefix) {
- mod = get_prefix(ctx, prefix, prefix_len, parser);
- }
- if (!mod) {
- asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - unable to map prefix \"%.*s\" to YANG schema.",
- (int)orig_len, orig, (int)prefix_len, prefix);
- return LY_EVALID;
- }
- if (!present_prefix) {
- /* store the prefix record for later use */
- struct lyd_value_prefix *p;
- *errmsg = strdup("Memory allocation failed.");
- LY_ARRAY_NEW_RET(ctx, *prefixes, p, LY_EMEM);
- free(*errmsg);
- *errmsg = NULL;
- p->mod = mod;
- p->prefix = lydict_insert(ctx, prefix, prefix_len);
+ /* non top-level node from JSON */
+ if (*node_d) {
+ mod = (*node_d)->schema->module;
+ } else {
+ mod = (*node_s)->module;
+ }
+ } else {
+ /* map prefix to schema module */
+ LY_ARRAY_FOR(prefixes, u) {
+ if (!strncmp(prefixes[u].prefix, prefix, prefix_len) && prefixes[u].prefix[prefix_len] == '\0') {
+ mod = prefixes[u].mod;
+ break;
+ }
+ }
+
+ if (!mod) {
+ asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - unable to map prefix \"%.*s\" to YANG schema.",
+ (int)orig_len, orig, (int)prefix_len, prefix);
+ return LY_EVALID;
+ }
}
if ((options & LY_TYPE_OPTS_INCOMPLETE_DATA) || !require_instance) {
@@ -1336,30 +1409,173 @@
}
/**
+ * @brief Helper function for ly_type_validate_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.
+ */
+static const struct lys_module *
+ly_type_validate_instanceid_get_prefix(struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
+{
+ struct lyd_value_prefix *prefixes = (struct lyd_value_prefix*)private;
+ unsigned int u;
+
+ LY_ARRAY_FOR(prefixes, u) {
+ if (!strncmp(prefixes[u].prefix, prefix, prefix_len) && prefixes[u].prefix[prefix_len] == '\0') {
+ return prefixes[u].mod;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief Helper function for ly_type_validate_instanceid() to prepare predicate's value structure into the lyd_value_path structure.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] key Schema key node of the predicate (list's key in case of key-predicate, leaf-list in case of leaf-list-predicate).
+ * @param[in] val Value string of the predicate.
+ * @param[in] val_len Length of the @p val.
+ * @param[in] prefixes [Sized array](@ref sizedarrays) of the prefix mappings used in the instance-identifier value.
+ * @param[in] format Input format of the data.
+ * @param[in,out] pred Prepared predicate structure where the predicate information will be added.
+ * @param[out] errmsg Error description in case the function fails. Caller is responsible to free the string.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+ly_type_validate_instanceid_parse_predicate_value(struct ly_ctx *ctx, const struct lysc_node *key, const char *val, size_t val_len,
+ struct lyd_value_prefix *prefixes, LYD_FORMAT format,
+ struct lyd_value_path_predicate *pred, char **errmsg)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysc_type *type;
+ struct ly_err_item *err = NULL;
+ void *priv = NULL;
+ int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA;
+
+ pred->value = calloc(1, sizeof *pred->value);
+
+ type = ((struct lysc_node_leaf*)key)->type;
+ if (type->plugin->validate) {
+ ret = type->plugin->validate(ctx, type, val, val_len, options,
+ ly_type_validate_instanceid_get_prefix, prefixes, format, key, NULL,
+ &pred->value->canonized, &err, &priv);
+ if (ret == LY_EINCOMPLETE) {
+ /* actually expected success without complete data */
+ ret = LY_SUCCESS;
+ } else if (ret) {
+ if (err) {
+ *errmsg = err->msg;
+ err->msg = NULL;
+ ly_err_free(err);
+ } else {
+ *errmsg = strdup("Type validation failed with unknown error.");
+ }
+ goto error;
+ }
+ } else {
+ pred->value->canonized = lydict_insert(ctx, val, val_len);
+ }
+ pred->value->plugin = type->plugin;
+
+ if (type->plugin->store) {
+ ret = type->plugin->store(ctx, type, options, pred->value, &err, &priv);
+ if (ret) {
+ if (err) {
+ *errmsg = err->msg;
+ err->msg = NULL;
+ ly_err_free(err);
+ } else {
+ *errmsg = strdup("Data storing failed with unknown error.");
+ }
+ goto error;
+ }
+ }
+
+error:
+ return ret;
+}
+
+/**
+ * @brief Helper function for ly_type_validate_instanceid() to correctly find the end of the predicate section.
+ *
+ * @param[in] predicate Start of the beginning section.
+ * @return Pointer to the end of the predicate section.
+ */
+static const char *
+ly_type_validate_instanceid_predicate_end(const char *predicate)
+{
+ size_t i = 0;
+ while (predicate[i] != ']') {
+ if (predicate[i] == '\'') {
+ i++;
+ while (predicate[i] != '\'') {
+ i++;
+ }
+ }
+ if (predicate[i] == '"') {
+ i++;
+ while (predicate[i] != '"') {
+ if (predicate[i] == '\\') {
+ i += 2;
+ continue;
+ }
+ i++;
+ }
+ }
+ i++;
+ }
+ return &predicate[i];
+}
+
+/**
* @brief Validate value of the YANG built-in instance-identifier type.
*
* Implementation of the ly_type_validate_clb.
*/
static LY_ERR
ly_type_validate_instanceid(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix get_prefix, void *parser,
- struct lyd_node *context_node, struct lyd_node **trees,
+ ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+ const void *context_node, struct lyd_node **trees,
const char **canonized, struct ly_err_item **err, void **priv)
{
LY_ERR ret = LY_EVALID;
struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
- const char *id, *prefix, *val, *token;
+ const char *id, *prefix, *val, *token, *node_start;
size_t id_len, prefix_len, val_len;
char *errmsg = NULL;
const struct lysc_node *node_s = NULL;
const struct lyd_node *node_d = NULL;
struct lyd_value_prefix *prefixes = NULL;
unsigned int u;
+ struct lyd_value_path *target = NULL, *t;
+ struct lyd_value_path_predicate *pred;
+ struct ly_set predicates = {0};
+ uint64_t pos;
+ int i;
- if (((struct lyd_node_term*)context_node)->value.prefixes) {
- /* the second run, the first one ended with LY_EINCOMPLETE */
- prefixes = ((struct lyd_node_term*)context_node)->value.prefixes;
- get_prefix = NULL;
+ /* init */
+ *err = NULL;
+
+ if (!(options & LY_TYPE_OPTS_INCOMPLETE_DATA) && ((struct lyd_node_term*)context_node)->value.target) {
+ /* the second run, the first one ended with LY_EINCOMPLETE, but we have prepared the target structure */
+
+ if (!lyd_target(((struct lyd_node_term*)context_node)->value.target, trees)) {
+ /* TODO print instance-identifier */
+ asprintf(&errmsg, "Invalid instance-identifier \"%s\" value - required instance not found.",
+ "TODO");
+ goto error;
+ }
+ *priv = ((struct lyd_node_term*)context_node)->value.target;
+ return LY_SUCCESS;
+ } else {
+ /* first run without prepared target, we will need all the prefixes used in the instance-identifier value */
+ prefixes = ly_type_get_prefixes(ctx, value, value_len, get_prefix, parser);
+ }
+
+ if (value[0] != '/') {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - instance-identifier must starts with '/'.",
+ (int)value_len, value);
+ goto error;
}
/* parse the value and try to resolve it in:
@@ -1368,68 +1584,267 @@
for(token = value; (size_t)(token - value) < value_len;) {
if (token[0] == '/') {
/* node identifier */
+ node_start = &token[1];
+
+ /* clean them to correctly check predicates presence restrictions */
+ pos = 0;
+ ly_set_clean(&predicates, NULL);
+
token++;
- if (ly_type_validate_instanceid_checknodeid(ctx, value, value_len, options, type_inst->require_instance,
- &token, &prefixes, &node_s, &node_d, get_prefix, parser, trees, &errmsg)) {
+ if (ly_type_validate_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
+ &token, prefixes, format, &node_s, &node_d, trees, &errmsg)) {
goto error;
}
+ if (node_d) {
+ node_s = node_d->schema;
+ }
+ if (token[0] == '[') {
+ /* predicate follows, this must be a list or leaf-list */
+ if (node_s->nodetype != LYS_LIST && node_s->nodetype != LYS_LEAFLIST) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - predicate \"%.*s\" for %s is not accepted.",
+ (int)value_len, value, (int)(ly_type_validate_instanceid_predicate_end(token) - token) + 1, token,
+ lys_nodetype2str(node_s->nodetype));
+ goto error;
+ }
+ }
+
+ if (options & LY_TYPE_OPTS_STORE) {
+ /* prepare target path structure */
+ LY_ARRAY_NEW_GOTO(ctx, target, t, ret, error);
+ t->node = node_s;
+ }
} else if (token[0] == '[') {
/* predicate */
+ const char *pred_start = &token[0];
const char *pred_errmsg = NULL;
const struct lysc_node *key_s = node_s;
const struct lyd_node *key_d = node_d;
- if (ly_parse_instance_predicate(&token, value_len - (token - value), &prefix, &prefix_len, &id, &id_len, &val, &val_len, &pred_errmsg)) {
- asprintf(&errmsg, "Invalid instance-identifier's predicate (%s).", pred_errmsg);
+ if (ly_parse_instance_predicate(&token, value_len - (token - value), format, &prefix, &prefix_len, &id, &id_len, &val, &val_len, &pred_errmsg)) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value's predicate \"%.*s\" (%s).", (int)value_len, value,
+ (int)(token - pred_start), pred_start, pred_errmsg);
goto error;
}
- if (prefix) {
+
+ if (options & LY_TYPE_OPTS_STORE) {
+ /* update target path structure by adding predicate info */
+ LY_ARRAY_NEW_GOTO(ctx, t->predicates, pred, ret, error);
+ }
+
+ if (prefix || (id && id[0] != '.')) {
/* key-predicate */
- if (ly_type_validate_instanceid_checknodeid(ctx, value, value_len, options, type_inst->require_instance,
- &prefix, &prefixes, &key_s, &key_d, get_prefix, parser, trees, &errmsg)) {
+ const char *start, *t;
+ start = t = prefix ? prefix : id;
+
+ /* check that the parent is a list */
+ if (node_s->nodetype != LYS_LIST) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - key-predicate \"%.*s\" is accepted only for lists, not %s.",
+ (int)value_len, value, (int)(token - pred_start), pred_start, lys_nodetype2str(node_s->nodetype));
+ goto error;
+ }
+
+ /* resolve the key in predicate */
+ if (ly_type_validate_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
+ &t, prefixes, format, &key_s, &key_d, trees, &errmsg)) {
goto error;
}
if (key_d) {
- /* TODO check value */
- } else if (key_s) {
- /* TODO check type of the value with the type of the node */
- } else {
- LOGINT(ctx);
+ key_s = key_d->schema;
+ }
+
+ /* check the key in predicate is really a key */
+ if (!(key_s->flags & LYS_KEY)) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - node \"%s\" used in key-predicate \"%.*s\" must be a key.",
+ (int)value_len, value, key_s->name, (int)(token - pred_start), pred_start);
goto error;
}
- } else if (id) {
- /* TODO leaf-list-predicate */
- } else {
- /* TODO pos predicate */
- }
+ if (node_d) {
+ while (node_d) {
+ if (!lyd_value_compare((const struct lyd_node_term*)key_d, val, val_len, get_prefix, parser, format, trees)) {
+ /* match */
+ break;
+ }
+ /* go to another instance */
+ t = start;
+ node_d = lyd_search(node_d->next, node_s->module, node_s->name, strlen(node_s->name), LYS_LIST, NULL, 0);
+ if (node_d) {
+ key_d = node_d;
+ if (ly_type_validate_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
+ &t, prefixes, format, &key_s, &key_d, trees, &errmsg)) {
+ goto error;
+ }
+ }
+ }
+ if (!node_d) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - key-predicate \"%.*s\" does not match any \"%s\" instance.",
+ (int)value_len, value, (int)(token - pred_start), pred_start, node_s->name);
+ goto error;
+ }
+ } else {
+ /* check value to the type */
+ if (lys_value_validate(NULL, key_s, val, val_len, get_prefix, parser, format)) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - key-predicate \"%.*s\"'s key value is invalid.",
+ (int)value_len, value, (int)(token - pred_start), pred_start);
+ goto error;
+ }
+ }
+
+ if (options & LY_TYPE_OPTS_STORE) {
+ /* update target path structure by adding predicate info */
+ pred->type = 1;
+ pred->key = key_s;
+ LY_CHECK_GOTO(ly_type_validate_instanceid_parse_predicate_value(ctx, key_s, val, val_len, prefixes, format, pred, &errmsg), error);
+ }
+ i = predicates.count;
+ if (i != ly_set_add(&predicates, (void*)key_s, 0)) {
+ /* the same key is used repeatedly */
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - key \"%s\" is referenced the second time in key-predicate \"%.*s\".",
+ (int)value_len, value, key_s->name, (int)(token - pred_start), pred_start);
+ goto error;
+ }
+ if (token[0] != '[') {
+ /* now we should have all the keys */
+ if (LY_ARRAY_SIZE(((struct lysc_node_list*)node_s)->keys) != predicates.count) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - missing %u key(s) for the list instance \"%.*s\".",
+ (int)value_len, value, LY_ARRAY_SIZE(((struct lysc_node_list*)node_s)->keys) - predicates.count,
+ (int)(token - node_start), node_start);
+ goto error;
+ }
+ }
+ } else if (id) {
+ /* leaf-list-predicate */
+ if (predicates.count) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - "
+ "leaf-list-predicate (\"%.*s\") cannot be used repeatedly for a single node.",
+ (int)value_len, value, (int)(token - pred_start), pred_start);
+ goto error;
+ }
+
+ /* check that the parent is a leaf-list */
+ if (node_s->nodetype != LYS_LEAFLIST) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - leaf-list-predicate \"%.*s\" is accepted only for leaf-lists, not %s.",
+ (int)value_len, value, (int)(token - pred_start), pred_start, lys_nodetype2str(node_s->nodetype));
+ goto error;
+ }
+
+ if (key_d) {
+ while (key_d) {
+ if (!lyd_value_compare((const struct lyd_node_term*)key_d, val, val_len, get_prefix, parser, format, trees)) {
+ /* match */
+ break;
+ }
+ /* go to another instance */
+ key_d = lyd_search(key_d->next, node_s->module, node_s->name, strlen(node_s->name), LYS_LEAFLIST, NULL, 0);
+ }
+ if (!key_d) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - leaf-list-predicate \"%.*s\" does not match any \"%s\" instance.",
+ (int)value_len, value, (int)(token - pred_start), pred_start, node_s->name);
+ goto error;
+ }
+ } else {
+ /* check value to the type */
+ if (lys_value_validate(NULL, key_s, val, val_len, get_prefix, parser, format)) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - leaf-list-predicate \"%.*s\"'s value is invalid.",
+ (int)value_len, value, (int)(token - pred_start), pred_start);
+ goto error;
+ }
+ }
+
+ if (options & LY_TYPE_OPTS_STORE) {
+ /* update target path structure by adding predicate info */
+ pred->type = 2;
+ pred->key = node_s;
+ LY_CHECK_GOTO(ly_type_validate_instanceid_parse_predicate_value(ctx, node_s, val, val_len, prefixes, format, pred, &errmsg), error);
+ }
+ ly_set_add(&predicates, (void*)node_s, 0);
+ } else {
+ /* pos predicate */
+ if (pos) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - "
+ "position predicate (\"%.*s\") cannot be used repeatedly for a single node.",
+ (int)value_len, value, (int)(token - pred_start), pred_start);
+ goto error;
+ }
+
+ /* check that the parent is a list without keys
+ * The check is actually commented, libyang does not want to be so strict here, since
+ * we see usecases even for lists with keys and leaf-lists
+ if (node_s->nodetype != LYS_LIST || ((struct lysc_node_list*)node_s)->keys) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - position predicate \"%.*s\" is accepted only for lists without keys.",
+ (int)value_len, value, (int)(token - pred_start), pred_start, lys_nodetype2str(node_s->nodetype));
+ goto error;
+ }
+ */
+
+ if (ly_type_parse_uint("instance-identifier", 10, UINT64_MAX, val, val_len, &pos, err)) {
+ goto error;
+ }
+ if (node_d) {
+ /* get the correct instance */
+ for (uint64_t u = pos; u > 1; u--) {
+ node_d = lyd_search(node_d->next, node_s->module, node_s->name, strlen(node_s->name), node_s->nodetype, NULL, 0);
+ if (!node_d) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - "
+ "position-predicate %"PRIu64" is bigger than number of instances in the data tree (%"PRIu64").",
+ (int)value_len, value, pos, pos - u + 1);
+ goto error;
+ }
+ }
+ } else {
+ /* check that there is not a limit below the position number */
+ if (node_s->nodetype == LYS_LIST) {
+ if (((struct lysc_node_list*)node_s)->max < pos) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - position-predicate %"PRIu64" is bigger than allowed max-elements (%u).",
+ (int)value_len, value, pos, ((struct lysc_node_list*)node_s)->max);
+ goto error;
+ }
+ } else {
+ if (((struct lysc_node_leaflist*)node_s)->max < pos) {
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - position-predicate %"PRIu64" is bigger than allowed max-elements (%u).",
+ (int)value_len, value, pos, ((struct lysc_node_leaflist*)node_s)->max);
+ goto error;
+ }
+ }
+ }
+
+ if (options & LY_TYPE_OPTS_STORE) {
+ /* update target path structure by adding predicate info */
+ pred->type = 0;
+ pred->position = pos;
+ }
+ }
} else {
- asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - unexpected character %lu.",
- (int)value_len, value, token - value + 1);
+ asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value at character %lu (%.*s).",
+ (int)value_len, value, token - value + 1, (int)(value_len - (token - value)), token);
goto error;
}
}
- if ((options & LY_TYPE_OPTS_CANONIZE) && *canonized != value) {
- if (options & LY_TYPE_OPTS_DYNAMIC) {
- *canonized = lydict_insert_zc(ctx, (char*)value);
- value = NULL;
- } else {
- *canonized = lydict_insert(ctx, value, value_len);
- }
+ if ((options & LY_TYPE_OPTS_CANONIZE) && !(*canonized)) {
+ /* instance-identifier does not have a canonical form (lexical representation in in XML and JSON are
+ * even different) - to make it clear, the canonized form is represented as NULL to make the caller
+ * print it always via callback printer */
+ *canonized = NULL;
}
-#if 0
+
if (options & LY_TYPE_OPTS_STORE) {
- *priv = ident;
+ *priv = target;
+ } else {
+ lyd_value_free_path(ctx, target);
}
-#endif
+
+ LY_ARRAY_FOR(prefixes, u) {
+ lydict_remove(ctx, prefixes[u].prefix);
+ }
+ LY_ARRAY_FREE(prefixes);
+ ly_set_erase(&predicates, NULL);
+
if (options & LY_TYPE_OPTS_DYNAMIC) {
free((char*)value);
}
- *priv = prefixes;
-
if ((options & LY_TYPE_OPTS_INCOMPLETE_DATA) && type_inst->require_instance) {
return LY_EINCOMPLETE;
} else {
@@ -1437,13 +1852,17 @@
}
error:
- if (!((struct lyd_node_term*)context_node)->value.prefixes) {
- LY_ARRAY_FOR(prefixes, u) {
- lydict_remove(ctx, prefixes[u].prefix);
- }
- LY_ARRAY_FREE(prefixes);
+ LY_ARRAY_FOR(prefixes, u) {
+ lydict_remove(ctx, prefixes[u].prefix);
}
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ LY_ARRAY_FREE(prefixes);
+ ly_set_erase(&predicates, NULL);
+
+ lyd_value_free_path(ctx, target);
+
+ if (!*err) {
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ }
return ret;
}
@@ -1459,7 +1878,7 @@
{
if (options & LY_TYPE_OPTS_VALIDATE) {
/* the value was prepared by ly_type_validate_enum() */
- value->prefixes = *priv;
+ value->target = *priv;
} else {
/* TODO if there is usecase for store without validate */
LOGINT(NULL);
@@ -1470,6 +1889,56 @@
}
/**
+ * @brief Comparison callback checking the instance-identifier value.
+ *
+ * Implementation of the ly_type_compare_clb.
+ */
+static LY_ERR
+ly_type_compare_instanceid(const struct lyd_value *val1, const struct lyd_value *val2)
+{
+ unsigned int u, v;
+
+ if (val1 == val2) {
+ return LY_SUCCESS;
+ } else if (!val1->target || !val2->target || LY_ARRAY_SIZE(val1->target) != LY_ARRAY_SIZE(val2->target)) {
+ return LY_EVALID;
+ }
+
+ LY_ARRAY_FOR(val1->target, u) {
+ struct lyd_value_path *s1 = &val1->target[u];
+ struct lyd_value_path *s2 = &val2->target[u];
+
+ if (s1->node != s2->node || (s1->predicates && !s2->predicates) || (!s1->predicates && s2->predicates) ||
+ (s1->predicates && LY_ARRAY_SIZE(s1->predicates) != LY_ARRAY_SIZE(s2->predicates))) {
+ return LY_EVALID;
+ }
+ if (s1->predicates) {
+ LY_ARRAY_FOR(s1->predicates, v) {
+ struct lyd_value_path_predicate *pred1 = &s1->predicates[v];
+ struct lyd_value_path_predicate *pred2 = &s2->predicates[v];
+
+ if (pred1->type != pred2->type) {
+ return LY_EVALID;
+ }
+ if (pred1->type == 0) {
+ /* position predicate */
+ if (pred1->position != pred2->position) {
+ return LY_EVALID;
+ }
+ } else {
+ /* key-predicate or leaf-list-predicate */
+ if (pred1->key != pred2->key || ((struct lysc_node_leaf*)pred1->key)->type->plugin->compare(pred1->value, pred2->value)) {
+ return LY_EVALID;
+ }
+ }
+ }
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
* @brief Free value of the YANG built-in instance-identifier type.
*
* Implementation of the ly_type_free_clb.
@@ -1477,35 +1946,45 @@
static void
ly_type_free_instanceid(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), struct lyd_value *value)
{
- unsigned int u;
+ lyd_value_free_path(ctx, value->target);
+ value->target = NULL;
+}
- LY_ARRAY_FOR(value->prefixes, u) {
- lydict_remove(ctx, value->prefixes[u].prefix);
+/**
+ * @brief Generic comparison callback checking the canonical value.
+ *
+ * Implementation of the ly_type_compare_clb.
+ */
+static LY_ERR
+ly_type_compare_canonical(const struct lyd_value *val1, const struct lyd_value *val2)
+{
+ if (val1 == val2 || !strcmp(val1->canonized, val2->canonized)) {
+ return LY_SUCCESS;
}
- LY_ARRAY_FREE(value->prefixes);
- value->prefixes = NULL;
+
+ return LY_EVALID;
}
struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
{0}, /* LY_TYPE_UNKNOWN */
- {.type = LY_TYPE_BINARY, .validate = ly_type_validate_binary, .store = NULL, .free = NULL},
- {.type = LY_TYPE_UINT8, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .free = NULL},
- {.type = LY_TYPE_UINT16, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .free = NULL},
- {.type = LY_TYPE_UINT32, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .free = NULL},
- {.type = LY_TYPE_UINT64, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .free = NULL},
- {.type = LY_TYPE_STRING, .validate = ly_type_validate_string, .store = NULL, .free = NULL},
- {.type = LY_TYPE_BITS, .validate = ly_type_validate_bits, .store = ly_type_store_bits, .free = ly_type_free_bits},
- {.type = LY_TYPE_BOOL, .validate = ly_type_validate_boolean, .store = ly_type_store_boolean, .free = NULL},
- {.type = LY_TYPE_DEC64, .validate = ly_type_validate_decimal64, .store = ly_type_store_decimal64, .free = NULL},
- {.type = LY_TYPE_EMPTY, .validate = ly_type_validate_empty, .store = NULL, .free = NULL},
- {.type = LY_TYPE_ENUM, .validate = ly_type_validate_enum, .store = ly_type_store_enum, .free = NULL},
- {.type = LY_TYPE_IDENT, .validate = ly_type_validate_identityref, .store = ly_type_store_identityref, .free = NULL},
- {.type = LY_TYPE_INST, .validate = ly_type_validate_instanceid, .store = ly_type_store_instanceid, .free = ly_type_free_instanceid},
+ {.type = LY_TYPE_BINARY, .validate = ly_type_validate_binary, .store = NULL, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_UINT8, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_UINT16, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_UINT32, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_UINT64, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_STRING, .validate = ly_type_validate_string, .store = NULL, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_BITS, .validate = ly_type_validate_bits, .store = ly_type_store_bits, .compare = ly_type_compare_canonical, .free = ly_type_free_bits},
+ {.type = LY_TYPE_BOOL, .validate = ly_type_validate_boolean, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_DEC64, .validate = ly_type_validate_decimal64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_EMPTY, .validate = ly_type_validate_empty, .store = NULL, .compare = ly_type_compare_empty, .free = NULL},
+ {.type = LY_TYPE_ENUM, .validate = ly_type_validate_enum, .store = ly_type_store_enum, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_IDENT, .validate = ly_type_validate_identityref, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref, .free = NULL},
+ {.type = LY_TYPE_INST, .validate = ly_type_validate_instanceid, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid, .free = ly_type_free_instanceid},
{0}, /* TODO LY_TYPE_LEAFREF */
{0}, /* TODO LY_TYPE_UNION */
- {.type = LY_TYPE_INT8, .validate = ly_type_validate_int, .store = ly_type_store_int, .free = NULL},
- {.type = LY_TYPE_INT16, .validate = ly_type_validate_int, .store = ly_type_store_int, .free = NULL},
- {.type = LY_TYPE_INT32, .validate = ly_type_validate_int, .store = ly_type_store_int, .free = NULL},
- {.type = LY_TYPE_INT64, .validate = ly_type_validate_int, .store = ly_type_store_int, .free = NULL},
+ {.type = LY_TYPE_INT8, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_INT16, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_INT32, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
+ {.type = LY_TYPE_INT64, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
};
diff --git a/src/plugins_types.h b/src/plugins_types.h
index f0df0fb..5556817 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -82,20 +82,6 @@
*/
/**
- * @brief Callback provided by the data parsers to type plugins to resolve (format-specific) mapping between prefixes used in the value strings
- * to the YANG schemas.
- *
- * XML uses XML namespaces, JSON uses schema names as prefixes.
- *
- * @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] parser Internal parser's data.
- * @return Pointer to the YANG schema identified by the provided prefix or NULL if no mapping found.
- */
-typedef const struct lys_module *(*ly_type_resolve_prefix)(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser);
-
-/**
* @brief Callback to validate the given @p value according to the given @p type. Optionaly, it can be requested to canonize the value.
*
* Note that the \p value string is not necessarily zero-terminated. The provided \p value_len is always correct.
@@ -103,12 +89,15 @@
* @param[in] ctx libyang Context
* @param[in] type Type of the value being canonized.
* @param[in] value Lexical representation of the value to be validated (and canonized).
+ * It is never NULL, empty string is represented as "" with zero @p value_len.
* @param[in] value_len Length of the given \p value.
* @param[in] options [Type plugin options ](@ref plugintypeopts).
*
* @param[in] get_prefix Parser-specific getter to resolve prefixes used in the value strings.
* @param[in] parser Parser's data for @p get_prefix
- * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved.
+ * @param[in] format Input format of the data.
+ * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved. This argument is of
+ * lys_node (in case LY_TYPE_OPTS_INCOMPLETE_DATA set in @p options) or lyd_node structure.
* @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification) where the required data
* instance can be placed.
*
@@ -121,8 +110,8 @@
* @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_validate_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_type_resolve_prefix get_prefix, void *parser,
- struct lyd_node *context_node, struct lyd_node **trees,
+ ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+ const void *context_node, struct lyd_node **trees,
const char **canonized, struct ly_err_item **err, void **priv);
/**
@@ -142,6 +131,18 @@
struct lyd_value *value, struct ly_err_item **err, void **priv);
/**
+ * @brief Callback for comparing 2 values of the same type.
+ *
+ * Caller is responsible to provide values of the SAME type.
+ *
+ * @param[in] val1 First value to compare.
+ * @param[in] val2 Second value to compare.
+ * @return LY_SUCCESS if values are same (according to the type's definition of being same).
+ * @return LY_EVALID if values differ.
+ */
+typedef LY_ERR (*ly_type_compare_clb)(const struct lyd_value *val1, const struct lyd_value *val2);
+
+/**
* @brief Callback for freeing the user type values stored by ly_type_store_clb().
*
*
@@ -162,7 +163,8 @@
LY_DATA_TYPE type; /**< implemented type, use LY_TYPE_UNKNOWN for derived data types */
ly_type_validate_clb validate; /**< function to validate and canonize given value */
ly_type_store_clb store; /**< function to store the value in the type-specific way */
- ly_type_free_clb free; /**< function to free the type-spceific way stored value */
+ ly_type_compare_clb compare; /**< comparison callback to compare 2 values of the same type */
+ ly_type_free_clb free; /**< optional function to free the type-spceific way stored value */
uint32_t flags; /**< [type flags ](@ref plugintypeflags). */
};
@@ -253,4 +255,17 @@
*/
LY_ERR ly_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len, struct ly_err_item **err);
+/**
+ * @brief Helper function for type validation callbacks to prepare list of all possible prefixes used in the value string.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] value Value string to be parsed.
+ * @param[in] value_len Length of the @p value string.
+ * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the value strings.
+ * @param[in] parser Parser's data for @p get_prefix.
+ * @return Created [sized array](@ref sizedarrays) of prefix mappings, NULL in case of error.
+ */
+struct lyd_value_prefix *ly_type_get_prefixes(struct ly_ctx *ctx, const char *value, size_t value_len,
+ ly_clb_resolve_prefix get_prefix, void *parser);
+
#endif /* LY_PLUGINS_TYPES_H_ */
diff --git a/src/tree.h b/src/tree.h
index 65c2405..5210ce2 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -156,6 +156,20 @@
*/
extern const char* ly_data_type2str[LY_DATA_TYPE_COUNT];
+/**
+ * @brief Callback provided by the data parsers to type plugins to resolve (format-specific) mapping between prefixes used in the value strings
+ * to the YANG schemas.
+ *
+ * XML uses XML namespaces, JSON uses schema names as prefixes.
+ *
+ * @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_clb_resolve_prefix)(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private);
+
/** @} */
#ifdef __cplusplus
diff --git a/src/tree_data.c b/src/tree_data.c
index eb551e2..02059b9 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -14,6 +14,7 @@
#include "common.h"
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -87,6 +88,197 @@
return NULL;
}
+LY_ERR
+lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int dynamic,
+ ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, struct lyd_node **trees)
+{
+ LY_ERR ret = LY_SUCCESS, rc;
+ struct ly_err_item *err = NULL;
+ struct ly_ctx *ctx;
+ struct lysc_type *type;
+ void *priv = NULL;
+ int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE |
+ (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+ assert(node);
+
+ ctx = node->schema->module->ctx;
+ type = ((struct lysc_node_leaf*)node->schema)->type;
+ if (type->plugin->validate) {
+ rc = type->plugin->validate(ctx, type, value, value_len, options, get_prefix, parser, format,
+ trees ? (void*)node : (void*)node->schema, trees,
+ &node->value.canonized, &err, &priv);
+ if (rc == LY_EINCOMPLETE) {
+ ret = rc;
+ /* continue with storing, just remember what to return if storing is ok */
+ } else if (rc) {
+ ret = rc;
+ if (err) {
+ ly_err_print(err);
+ LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+ ly_err_free(err);
+ }
+ goto error;
+ }
+ } else if (dynamic) {
+ node->value.canonized = lydict_insert_zc(ctx, (char*)value);
+ } else {
+ node->value.canonized = lydict_insert(ctx, value, value_len);
+ }
+ node->value.plugin = type->plugin;
+
+ if (type->plugin->store) {
+ rc = type->plugin->store(ctx, type, options, &node->value, &err, &priv);
+ if (rc) {
+ ret = rc;
+ if (err) {
+ ly_err_print(err);
+ LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+ ly_err_free(err);
+ }
+ goto error;
+ }
+ }
+
+error:
+ return ret;
+}
+
+API LY_ERR
+lys_value_validate(struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
+ ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct ly_err_item *err = NULL;
+ struct lysc_type *type;
+ void *priv = NULL;
+ int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_INCOMPLETE_DATA;
+
+ LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
+
+ if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
+ LOGARG(ctx, node);
+ return LY_EINVAL;
+ }
+
+ type = ((struct lysc_node_leaf*)node)->type;
+
+ if (type->plugin->validate) {
+ rc = type->plugin->validate(ctx ? ctx : node->module->ctx, type, value, value_len, options,
+ get_prefix, get_prefix_data, format, node, NULL, NULL, &err, &priv);
+ if (rc == LY_EINCOMPLETE) {
+ /* actually success since we do not provide the context tree and call validation with
+ * LY_TYPE_OPTS_INCOMPLETE_DATA */
+ rc = LY_SUCCESS;
+ } else if (rc && err) {
+ if (ctx) {
+ /* log only in case the ctx was provided as input parameter */
+ ly_err_print(err);
+ LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+ }
+ ly_err_free(err);
+ }
+ }
+
+ return rc;
+}
+
+API LY_ERR
+lyd_value_validate(struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
+ ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, struct lyd_node **trees)
+{
+ LY_ERR rc;
+ struct ly_err_item *err = NULL;
+ struct lysc_type *type;
+ void *priv = NULL;
+ int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+
+ LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
+
+ type = ((struct lysc_node_leaf*)node->schema)->type;
+
+ if (type->plugin->validate) {
+ rc = type->plugin->validate(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
+ get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
+ NULL, &err, &priv);
+ if (rc == LY_EINCOMPLETE) {
+ return rc;
+ } else if (rc) {
+ if (err) {
+ if (ctx) {
+ ly_err_print(err);
+ LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+ }
+ ly_err_free(err);
+ }
+ return rc;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
+ ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, struct lyd_node **trees)
+{
+ LY_ERR ret = LY_SUCCESS, rc;
+ struct ly_err_item *err = NULL;
+ struct ly_ctx *ctx;
+ struct lysc_type *type;
+ void *priv = NULL;
+ struct lyd_value data = {0};
+ int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+
+ LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
+
+ ctx = node->schema->module->ctx;
+ type = ((struct lysc_node_leaf*)node->schema)->type;
+ if (type->plugin->validate) {
+ rc = type->plugin->validate(ctx, type, value, value_len, options,
+ get_prefix, get_prefix_data, format, (struct lyd_node*)node, trees,
+ &data.canonized, &err, &priv);
+ if (rc == LY_EINCOMPLETE) {
+ ret = rc;
+ /* continue with comparing, just remember what to return if storing is ok */
+ } else if (rc) {
+ /* value to compare is invalid */
+ ret = LY_EINVAL;
+ if (err) {
+ ly_err_free(err);
+ }
+ goto cleanup;
+ }
+ } else {
+ data.canonized = lydict_insert(ctx, value, value_len);
+ }
+
+ /* store the value to compare into a dummy storage to do a comparison */
+ if (type->plugin->store) {
+ if (type->plugin->store(ctx, type, options, &data, &err, &priv)) {
+ ret = LY_EINVAL;
+ if (err) {
+ ly_err_free(err);
+ }
+ goto cleanup;
+ }
+ }
+
+ /* compare data */
+ if (type->plugin->compare) {
+ ret = type->plugin->compare(&node->value, &data);
+ } else if (data.canonized != node->value.canonized) {
+ ret = LY_EVALID;
+ }
+
+cleanup:
+ if (type->plugin->free) {
+ type->plugin->free(ctx, type, &data);
+ }
+ lydict_remove(ctx, data.canonized);
+
+ return ret;
+}
+
static struct lyd_node *
lyd_parse_mem_(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, va_list ap)
{
@@ -251,3 +443,82 @@
return result;
}
+
+API const struct lyd_node_term *
+lyd_target(struct lyd_value_path *path, struct lyd_node **trees)
+{
+ unsigned int u, v, x;
+ const struct lyd_node *node = NULL, *parent = NULL, *start_search;
+ uint64_t pos = 1;
+
+ LY_CHECK_ARG_RET(NULL, path, trees, NULL);
+
+ LY_ARRAY_FOR(path, u) {
+ if (parent) {
+ start_search = lyd_node_children(parent);
+search_inner:
+ node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
+ } else {
+ LY_ARRAY_FOR(trees, v) {
+ start_search = trees[v];
+search_toplevel:
+ /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
+ node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
+ if (node) {
+ break;
+ }
+ }
+ }
+ if (!node) {
+ return NULL;
+ }
+
+ /* check predicate if any */
+ LY_ARRAY_FOR(path[u].predicates, x) {
+ if (path[u].predicates[x].type == 0) {
+ /* position predicate */
+ if (pos != path[u].predicates[x].position) {
+ pos++;
+ goto search_repeat;
+ }
+ /* done, no more predicates are allowed here */
+ break;
+ } else if (path[u].predicates[x].type == 1) {
+ /* key-predicate */
+ struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
+ const struct lyd_node *key = lyd_search(lyd_node_children(node), path[u].predicates[x].key->module,
+ path[u].predicates[x].key->name, strlen(path[u].predicates[x].key->name),
+ LYS_LEAF, NULL, 0);
+ if (!key) {
+ /* probably error and we shouldn't be here due to previous checks when creating path */
+ goto search_repeat;
+ }
+ if (type->plugin->compare(&((struct lyd_node_term*)key)->value, path[u].predicates[x].value)) {
+ goto search_repeat;
+ }
+ } else if (path[u].predicates[x].type == 2) {
+ /* leaf-list-predicate */
+ struct lysc_type *type = ((struct lysc_node_leaf*)path[u].node)->type;
+ if (type->plugin->compare(&((struct lyd_node_term*)node)->value, path[u].predicates[x].value)) {
+ goto search_repeat;
+ }
+ } else {
+ LOGINT(NULL);
+ }
+ }
+
+ parent = node;
+ }
+
+ return (const struct lyd_node_term*)node;
+
+search_repeat:
+ start_search = node->next;
+ if (parent) {
+ goto search_inner;
+ } else {
+ goto search_toplevel;
+ }
+}
+
+
diff --git a/src/tree_data.h b/src/tree_data.h
index ec23aac..84021b5 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -181,6 +181,21 @@
const char *prefix; /**< prefix string used in the canonized string to identify the mod of the YANG schema */
const struct lys_module *mod; /**< YANG schema module identified by the prefix string */
} *prefixes; /**< list of mappings between prefix in canonized value to a YANG schema ([sized array](@ref sizedarrays)) */
+
+ struct lyd_value_path {
+ const struct lysc_node *node;
+ struct lyd_value_path_predicate {
+ union {
+ struct {
+ const struct lysc_node *key;
+ struct lyd_value *value;
+ };
+ uint64_t position;
+ };
+ uint8_t type; /**< 0 - position, 1 - key-predicate, 2 - leaf-list-predicate */
+ } *predicates;
+ } *target;
+
int8_t int8; /**< 8-bit signed integer */
int16_t int16; /**< 16-bit signed integer */
int32_t int32; /**< 32-bit signed integer */
@@ -192,6 +207,11 @@
void *ptr; /**< generic data type structure used to store the data */
}; /**< The union is just a list of shorthands to possible values stored by a type's plugin. libyang works only with the canonized string,
this specific data type storage is just to simplify use of the values by the libyang users. */
+
+ struct lysc_type_plugin *plugin; /**< pointer to the type plugin which stored the data. This pointer can differ from the pointer
+ in the lysc_type structure since the plugin itself can use other plugins for storing data.
+ Speaking about built-in types, this is the case of leafref which stores data as its target type.
+ Similarly union types stores the currently used type plugin in its internal lyd_value structure. */
};
/**
@@ -409,7 +429,10 @@
* @param[in] name Name of the node to find (mandatory argument).
* @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
* @param[in] nodetype Optional mask for the nodetype of the node to find, 0 is understood as all nodetypes.
- * @param[in] value Optional restriction for lyd_node_term nodes to select node with the specific value.
+ * @param[in] value Optional restriction for lyd_node_term nodes to select node with the specific value. Note that this
+ * search restriction is limited to compare canonical representation of the type. Some of the types have no canonical
+ * representation and 2 different strings can represent the same value (e.g. different prefixes of the same namespace in instance-identifiers).
+ * In this case there is more advanced lyd_value_compare() to check if the values matches.
* @param[in] value_len Optional length of the @p value argument in case it is not NULL-terminated string.
* @return The sibling node of the @p first (or itself), satisfying the given restrictions.
* @return NULL in case there is no node satisfying the restrictions.
@@ -568,6 +591,55 @@
*/
void lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive);
+/**
+ * @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
+ *
+ * The given node is not modified in any way - it is just checked if the @p value can be set to the node.
+ *
+ * If there is no data node instance and you are fine with checking just the type's restrictions without the
+ * data tree context (e.g. for the case of require-instance restriction), use lys_value_validate().
+ *
+ * @param[in] ctx libyang context for logging (function does not log errors when @p ctx is NULL)
+ * @param[in] node Data node for the @p value.
+ * @param[in] value String value to be checked.
+ * @param[in] value_len Length of the given @p value (mandatory).
+ * @param[in] get_prefix Callback function to resolve prefixes used in the @p value string.
+ * @param[in] get_prefix_data Private data for the @p get_prefix callback.
+ * @param[in] format Input format of the data.
+ * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
+ * data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
+ * then LY_EINCOMPLETE can be returned.
+ * @return LY_SUCCESS on success
+ * @return LY_EINCOMPLETE in case the @p trees is not provided and it was needed to finish the validation (e.g. due to require-instance).
+ * @return LY_ERR value if an error occurred.
+ */
+LY_ERR lyd_value_validate(struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
+ ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, struct lyd_node **trees);
+
+/**
+ * @brief Compare the node's value with the given string value. The string value is first validated according to the node's type.
+ *
+ * @param[in] node Data node to compare.
+ * @param[in] value String value to be compared. It does not need to be in a canonical form - as part of the process,
+ * it is validated and canonized if possible.
+ * @param[in] value_len Length of the given @p value (mandatory).
+ * @param[in] get_prefix Callback function to resolve prefixes used in the @p value string.
+ * @param[in] get_prefix_data Private data for the @p get_prefix callback.
+ * @param[in] format Input format of the data.
+ * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
+ * data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
+ * then LY_EINCOMPLETE can be returned in case the validation was not completed, but values matches.
+ * @return LY_SUCCESS on success
+ * @return LY_EINCOMPLETE in case of success when the @p trees is not provided and it was needed to finish the validation of
+ * the given string @p value (e.g. due to require-instance).
+ * @return LY_ERR value if an error occurred.
+ */
+LY_ERR lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
+ ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, struct lyd_node **trees);
+
+
+const struct lyd_node_term *lyd_target(struct lyd_value_path *path, struct lyd_node **trees);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index f594872..6e28fdb 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -25,6 +25,27 @@
#include "tree_data_internal.h"
#include "plugins_types.h"
+void
+lyd_value_free_path(struct ly_ctx *ctx, struct lyd_value_path *path)
+{
+ unsigned int u, v;
+
+ LY_ARRAY_FOR(path, u) {
+ LY_ARRAY_FOR(path[u].predicates, v) {
+ if (path[u].predicates[v].type > 0) {
+ struct lysc_type *t = ((struct lysc_node_leaf*)path[u].predicates[v].key)->type;
+ if (t->plugin->free) {
+ t->plugin->free(ctx, t, path[u].predicates[v].value);
+ }
+ lydict_remove(ctx, path[u].predicates[v].value->canonized);
+ free(path[u].predicates[v].value);
+ }
+ }
+ LY_ARRAY_FREE(path[u].predicates);
+ }
+ LY_ARRAY_FREE(path);
+}
+
API LY_ERR
lyd_unlink_tree(struct lyd_node *node)
{
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index b30dd98..256c442 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -82,58 +82,3 @@
return LY_SUCCESS;
}
-
-LY_ERR
-lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int dynamic,
- ly_type_resolve_prefix get_prefix, void *parser, struct lyd_node **trees)
-{
- LY_ERR ret = LY_SUCCESS, rc;
- struct ly_err_item *err = NULL;
- struct ly_ctx *ctx;
- struct lysc_type *type;
- void *priv = NULL;
- int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE |
- (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
- assert(node);
-
- ctx = node->schema->module->ctx;
- type = ((struct lysc_node_leaf*)node->schema)->type;
- if (type->plugin->validate) {
- rc = type->plugin->validate(ctx, type, value, value_len, options,
- get_prefix, parser, (struct lyd_node*)node, trees,
- &node->value.canonized, &err, &priv);
- if (rc == LY_EINCOMPLETE) {
- ret = rc;
- /* continue with storing, just remember what to return if storing is ok */
- } else if (rc) {
- ret = rc;
- if (err) {
- ly_err_print(err);
- LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
- ly_err_free(err);
- }
- goto error;
- }
- } else if (dynamic) {
- node->value.canonized = lydict_insert_zc(ctx, (char*)value);
- } else {
- node->value.canonized = lydict_insert(ctx, value, value_len);
- }
-
- if (type->plugin->store) {
- rc = type->plugin->store(ctx, type, options, &node->value, &err, &priv);
- if (rc) {
- ret = rc;
- if (err) {
- ly_err_print(err);
- LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
- ly_err_free(err);
- }
- goto error;
- }
- }
-
-error:
- return ret;
-}
-
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 7abb4b5..668f9a0 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -42,11 +42,12 @@
* @brief Validate, canonize and store the given @p value into the node according to the node's type's rules.
*
* @param[in] node Data node for with the @p value.
- * @param[in] value String value to be parsed.
+ * @param[in] value String value to be parsed, must not be NULL.
* @param[in] value_len Length of the give @p value (mandatory).
* @param[in] dynamic Flag if @p value is a dynamically allocated memory and should be directly consumed/freed inside the function.
- * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the value strings.
+ * @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.
* @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
* data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
* then LY_EINCOMPLETE can be returned.
@@ -55,7 +56,7 @@
* @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,
- ly_type_resolve_prefix get_prefix, void *parser, struct lyd_node **trees);
+ ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,struct lyd_node **trees);
/**
* @brief Parse XML string as YANG data tree.
@@ -84,4 +85,12 @@
/** @} datahash */
+/**
+ * @brief Free path (target) structure of the lyd_value.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] path The structure ([sized array](@ref sizedarrays)) to free.
+ */
+void lyd_value_free_path(struct ly_ctx *ctx, struct lyd_value_path *path);
+
#endif /* LY_TREE_DATA_INTERNAL_H_ */
diff --git a/src/tree_schema.h b/src/tree_schema.h
index f5ddc35..8ed59a4 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -24,6 +24,7 @@
#include "log.h"
#include "tree.h"
#include "extensions.h"
+#include "tree_data.h"
struct ly_ctx;
@@ -1640,6 +1641,25 @@
*/
const struct lysc_iffeature *lys_is_disabled(const struct lysc_node *node, int recursive);
+/**
+ * @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
+ *
+ * This function check just the type's restriction, if you want to check also the data tree context (e.g. in case of
+ * require-instance restriction), use lyd_value_validate().
+ *
+ * @param[in] ctx libyang context for logging (function does not log errors when @p ctx is NULL)
+ * @param[in] node Schema node for the @p value.
+ * @param[in] value String value to be checked.
+ * @param[in] value_len Length of the given @p value (mandatory).
+ * @param[in] get_prefix Callback function to resolve prefixes used in the @p value string.
+ * @param[in] get_prefix_data Private data for the @p get_prefix callback.
+ * @param[in] format Input format of the @p value.
+ * @return LY_SUCCESS on success
+ * @return LY_ERR value if an error occurred.
+ */
+LY_ERR lys_value_validate(struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
+ ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format);
+
/** @} */
#ifdef __cplusplus