blob: 28238bf2e506cf3fb8f00099deb44df7e01d3a41 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "common.h"
16
17#include <stdint.h>
18#include <stdlib.h>
19#include <string.h>
Michal Vasko9b368d32020-02-14 13:53:31 +010020#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021
22#include "context.h"
23#include "dict.h"
24#include "log.h"
25#include "plugins_types.h"
26#include "set.h"
27#include "tree_data.h"
28#include "tree_data_internal.h"
29#include "tree_schema.h"
30#include "xml.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010031#include "validation.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032
33/**
34 * @brief internal context for XML YANG data parser.
35 *
36 * The leading part is compatible with the struct lyxml_context
37 */
38struct lyd_xml_ctx {
39 struct ly_ctx *ctx; /**< libyang context */
40 uint64_t line; /**< number of the line being currently processed */
41 enum LYXML_PARSER_STATUS status; /**< status providing information about the next expected object in input data */
42 struct ly_set elements; /**< list of not-yet-closed elements */
43 struct ly_set ns; /**< handled with LY_SET_OPT_USEASLIST */
44
45 uint16_t options; /**< various @ref dataparseroptions. */
46 uint16_t path_len; /**< used bytes in the path buffer */
47#define LYD_PARSER_BUFSIZE 4078
48 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Radek Krejcie553e6d2019-06-07 15:33:18 +020049 struct ly_set incomplete_type_validation; /**< set of nodes validated with LY_EINCOMPLETE result */
Michal Vasko9f96a052020-03-10 09:41:45 +010050 struct ly_set incomplete_type_validation_meta; /**< set of metdata validated with LY_EINCOMPLETE result */
Michal Vaskoecd62de2019-11-13 12:35:11 +010051 struct ly_set when_check; /**< set of nodes with "when" conditions */
Radek Krejcie7b95092019-05-15 11:03:07 +020052};
53
54/**
Radek Krejciaca74032019-06-04 08:53:06 +020055 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used in the values to the schema
56 * via XML namespaces.
57 */
58static const struct lys_module *
59lydxml_resolve_prefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
60{
61 const struct lyxml_ns *ns;
62 struct lyxml_context *xmlctx = (struct lyxml_context*)parser;
63
64 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
65 if (!ns) {
66 return NULL;
67 }
68
69 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
70}
71
Radek Krejci28681fa2019-09-06 13:08:45 +020072struct attr_data_s {
73 const char *prefix;
74 const char *name;
75 char *value;
76 size_t prefix_len;
77 size_t name_len;
78 size_t value_len;
79 int dynamic;
80};
81
Radek Krejciaca74032019-06-04 08:53:06 +020082/**
Radek Krejcie7b95092019-05-15 11:03:07 +020083 * @brief Parse XML attributes of the XML element of YANG data.
84 *
85 * @param[in] ctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +020086 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
87 * @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
88 * as attributes, they are stored internally in the parser context.
89 * @reutn LY_ERR value.
90 */
91static LY_ERR
Radek Krejci28681fa2019-09-06 13:08:45 +020092lydxml_attributes_parse(struct lyd_xml_ctx *ctx, const char **data, struct ly_set *attrs_data)
Radek Krejcie7b95092019-05-15 11:03:07 +020093{
94 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020095 unsigned int u;
Radek Krejcie7b95092019-05-15 11:03:07 +020096 const char *prefix, *name;
97 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020098 struct attr_data_s *attr_data;
Radek Krejcie7b95092019-05-15 11:03:07 +020099
100 while(ctx->status == LYXML_ATTRIBUTE &&
101 lyxml_get_attribute((struct lyxml_context*)ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
Radek Krejci38d85362019-09-05 16:26:38 +0200102 char *buffer = NULL;
103 size_t buffer_size = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200104
Radek Krejci17a78d82019-05-15 15:49:55 +0200105 if (!name) {
106 /* seems like all the attrributes were internally processed as namespace definitions */
107 continue;
Radek Krejcie7b95092019-05-15 11:03:07 +0200108 }
Radek Krejci17a78d82019-05-15 15:49:55 +0200109
Radek Krejci38d85362019-09-05 16:26:38 +0200110 /* auxiliary store the prefix information and value string, because we have to wait with resolving prefix
111 * to the time when all the namespaces, defined in this element, are parsed. With the prefix we can find the
112 * annotation definition for the attribute and correctly process the value */
113 attr_data = malloc(sizeof *attr_data);
114 attr_data->prefix = prefix;
Radek Krejci28681fa2019-09-06 13:08:45 +0200115 attr_data->name = name;
Radek Krejci38d85362019-09-05 16:26:38 +0200116 attr_data->prefix_len = prefix_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200117 attr_data->name_len = name_len;
Radek Krejci38d85362019-09-05 16:26:38 +0200118 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &attr_data->value, &attr_data->value_len, &attr_data->dynamic);
Radek Krejci28681fa2019-09-06 13:08:45 +0200119 LY_CHECK_ERR_GOTO(ret, free(attr_data), error);
120 ly_set_add(attrs_data, attr_data, LY_SET_OPT_USEASLIST);
121 }
122
123 return LY_SUCCESS;
124
125error:
126 for (u = 0; u < attrs_data->count; ++u) {
127 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
128 free(((struct attr_data_s*)attrs_data->objs[u])->value);
129 }
130 }
131 ly_set_erase(attrs_data, free);
132 return ret;
133}
134
135static LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100136lydxml_metadata(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, const struct lysc_node *sparent, struct lyd_meta **meta)
Radek Krejci28681fa2019-09-06 13:08:45 +0200137{
138 LY_ERR ret = LY_EVALID, rc;
Radek Krejci28681fa2019-09-06 13:08:45 +0200139 const struct lyxml_ns *ns;
140 struct lys_module *mod;
141
142 for (unsigned int u = 0; u < attrs_data->count; ++u) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200143 struct attr_data_s *attr_data = (struct attr_data_s*)attrs_data->objs[u];
144
145 if (!attr_data->prefix_len) {
146 /* in XML, all attributes must be prefixed
147 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
148 if (ctx->options & LYD_OPT_STRICT) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100149 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci28681fa2019-09-06 13:08:45 +0200150 attr_data->name_len, attr_data->name);
151 }
152skip_attr:
153 if (attr_data->dynamic) {
154 free(attr_data->value);
155 attr_data->dynamic = 0;
156 }
157 continue;
158 }
159
160 /* get namespace of the attribute to find its annotation definition */
161 ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
162 if (!ns) {
163 /* unknown namespace, ignore the attribute */
164 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", attr_data->prefix_len, attr_data->prefix);
165 goto cleanup;
166 }
167 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
168 if (!mod) {
169 /* module is not implemented or not present in the schema */
170 if (ctx->options & LYD_OPT_STRICT) {
171 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100172 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vasko90932a92020-02-12 14:33:03 +0100173 ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len,
174 attr_data->name);
Radek Krejci28681fa2019-09-06 13:08:45 +0200175 }
176 goto skip_attr;
177 }
178
Michal Vasko9f96a052020-03-10 09:41:45 +0100179 rc = lyd_create_meta(NULL, meta, mod, attr_data->name, attr_data->name_len, attr_data->value,
Michal Vasko8d544252020-03-02 10:19:52 +0100180 attr_data->value_len, &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML, sparent);
Radek Krejci28681fa2019-09-06 13:08:45 +0200181 if (rc == LY_EINCOMPLETE) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100182 ly_set_add(&ctx->incomplete_type_validation_meta, meta, LY_SET_OPT_USEASLIST);
Radek Krejci28681fa2019-09-06 13:08:45 +0200183 } else if (rc) {
184 ret = rc;
Radek Krejci28681fa2019-09-06 13:08:45 +0200185 goto cleanup;
186 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200187 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200188 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200189
190cleanup:
191
Radek Krejci28681fa2019-09-06 13:08:45 +0200192 for (unsigned int u = 0; u < attrs_data->count; ++u) {
193 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
194 free(((struct attr_data_s*)attrs_data->objs[u])->value);
Radek Krejci38d85362019-09-05 16:26:38 +0200195 }
196 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200197 ly_set_erase(attrs_data, free);
198
Radek Krejcie7b95092019-05-15 11:03:07 +0200199 return ret;
200}
201
202/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100203 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200204 *
205 * @param[in] ctx XML YANG data parser context.
206 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
207 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
208 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100209 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200210 */
211static LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100212lydxml_data_r(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200213{
214 LY_ERR ret = LY_SUCCESS;
215 const char *prefix, *name;
Radek Krejcie7b95092019-05-15 11:03:07 +0200216 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200217 struct ly_set attrs_data = {0};
Radek Krejcie7b95092019-05-15 11:03:07 +0200218 const struct lyxml_ns *ns;
Michal Vasko9f96a052020-03-10 09:41:45 +0100219 struct lyd_meta *meta = NULL, *meta2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200220 const struct lysc_node *snode;
221 struct lys_module *mod;
222 unsigned int parents_count = ctx->elements.count;
Michal Vasko90932a92020-02-12 14:33:03 +0100223 struct lyd_node *cur = NULL, *key_anchor;
224 int dynamic = 0;
225 char *buffer = NULL, *value;
226 size_t buffer_size = 0, value_len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200227
Michal Vasko14654712020-02-06 08:35:21 +0100228 while (ctx->status == LYXML_ELEMENT) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200229 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
230 LY_CHECK_GOTO(ret, cleanup);
231 if (!name) {
232 /* closing previous element */
Radek Krejcie7b95092019-05-15 11:03:07 +0200233 if (ctx->elements.count < parents_count) {
234 /* all siblings parsed */
235 break;
236 } else {
237 continue;
238 }
239 }
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100240
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200241 if (ctx->status == LYXML_ATTRIBUTE) {
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100242 /* first parse all attributes so we have all the namespaces available */
Michal Vasko90932a92020-02-12 14:33:03 +0100243 if (lydxml_attributes_parse(ctx, data, &attrs_data) != LY_SUCCESS) {
244 ret = LY_EVALID;
245 goto cleanup;
246 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200247 }
248
Radek Krejcie7b95092019-05-15 11:03:07 +0200249 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
250 if (!ns) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200251 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100252 ret = LY_EVALID;
253 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200254 }
255 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
256 if (!mod) {
257 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100258 ret = LY_EVALID;
259 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200260 }
Michal Vaskoc193ce92020-03-06 11:04:48 +0100261 /* leave if-feature check for validation */
262 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
Radek Krejcie7b95092019-05-15 11:03:07 +0200263 if (!snode) {
Michal Vasko90932a92020-02-12 14:33:03 +0100264 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
265 name_len, name, mod->name);
266 ret = LY_EVALID;
Radek Krejcie7b95092019-05-15 11:03:07 +0200267 goto cleanup;
268 }
Michal Vasko5b37a352020-03-06 13:38:33 +0100269 if ((ctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
270 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INSTATE, snode->name);
271 return LY_EVALID;
272 }
Radek Krejci710226d2019-07-24 17:24:59 +0200273
Michal Vasko9f96a052020-03-10 09:41:45 +0100274 /* create actual metadata so that prefixes are available in the context */
Michal Vasko8d544252020-03-02 10:19:52 +0100275 if (attrs_data.count) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100276 LY_CHECK_GOTO(ret = lydxml_metadata(ctx, &attrs_data, snode, &meta), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +0100277 }
278
Michal Vasko90932a92020-02-12 14:33:03 +0100279 if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
280 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
281 snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
282 ret = LY_EVALID;
283 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200284 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200285
286 if (snode->nodetype & LYD_NODE_TERM) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200287 if (ctx->status == LYXML_ELEM_CONTENT) {
288 /* get the value */
Radek Krejci11702142019-07-24 17:46:04 +0200289 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
Michal Vasko14654712020-02-06 08:35:21 +0100290 if (ret != LY_SUCCESS) {
291 if (ret == LY_EINVAL) {
292 /* just indentation of a child element found */
Michal Vasko90932a92020-02-12 14:33:03 +0100293 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside terminal node \"%s\" found.",
294 snode->name);
Michal Vasko14654712020-02-06 08:35:21 +0100295 }
Radek Krejci339e2de2019-05-17 14:28:24 +0200296 goto cleanup;
297 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200298 } else {
299 /* no content - validate empty value */
300 value = "";
301 value_len = 0;
Michal Vasko90932a92020-02-12 14:33:03 +0100302 dynamic = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200303 }
Michal Vasko90932a92020-02-12 14:33:03 +0100304
305 /* create node */
306 ret = lyd_create_term(snode, value, value_len, &dynamic, lydxml_resolve_prefix, ctx, LYD_XML, &cur);
307 /* buffer spent */
308 buffer = NULL;
Radek Krejcie553e6d2019-06-07 15:33:18 +0200309 if (ret == LY_EINCOMPLETE) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100310 if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
311 ly_set_add(&ctx->incomplete_type_validation, cur, LY_SET_OPT_USEASLIST);
312 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200313 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200314 goto cleanup;
315 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100316
317 if (parent && (cur->schema->flags & LYS_KEY)) {
318 /* check the key order, the anchor must always be the last child */
319 key_anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
320 if ((!key_anchor && parent->child) || (key_anchor && key_anchor->next)) {
321 if (ctx->options & LYD_OPT_STRICT) {
322 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
323 cur->schema->name);
324 ret = LY_EVALID;
325 goto cleanup;
326 } else {
327 LOGWRN(ctx->ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
328 }
329 }
330 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200331 } else if (snode->nodetype & LYD_NODE_INNER) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200332 if (ctx->status == LYXML_ELEM_CONTENT) {
333 LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200334 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200335 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200336 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200337 goto cleanup;
338 }
339 }
Michal Vasko90932a92020-02-12 14:33:03 +0100340
341 /* create node */
342 ret = lyd_create_inner(snode, &cur);
343 LY_CHECK_GOTO(ret, cleanup);
344
Radek Krejciee4cab22019-07-17 17:07:47 +0200345 /* process children */
Radek Krejcie553e6d2019-06-07 15:33:18 +0200346 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100347 ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
348 LY_CHECK_GOTO(ret, cleanup);
349 }
350
351 if (snode->nodetype == LYS_LIST) {
352 /* check all keys exist */
353 ret = lyd_parse_check_keys(cur);
Radek Krejcie92210c2019-05-17 15:53:35 +0200354 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200355 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100356
357 if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100358 /* new node validation, autodelete CANNOT occur, all nodes are new */
359 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
360 LY_CHECK_GOTO(ret, cleanup);
361
Michal Vasko9b368d32020-02-14 13:53:31 +0100362 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100363 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vaskoe75ecfd2020-03-06 14:12:28 +0100364 &ctx->incomplete_type_validation, &ctx->when_check, ctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100365 LY_CHECK_GOTO(ret, cleanup);
366 }
367
368 /* hash now that all keys should be parsed, rehash for key-less list */
369 if (snode->nodetype == LYS_LIST) {
370 lyd_hash(cur);
371 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200372 } else if (snode->nodetype & LYD_NODE_ANY) {
373 unsigned int cur_element_index = ctx->elements.count;
374 const char *start = *data, *stop;
375 const char *p, *n;
376 size_t p_len, n_len;
377
378 /* skip children data and store them as a string */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200379 while (ctx->status != LYXML_END && cur_element_index <= ctx->elements.count) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200380 switch (ctx->status) {
381 case LYXML_ELEMENT:
382 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
Michal Vasko90932a92020-02-12 14:33:03 +0100383 LY_CHECK_GOTO(ret, cleanup);
Radek Krejciee4cab22019-07-17 17:07:47 +0200384 break;
385 case LYXML_ATTRIBUTE:
Michal Vasko14654712020-02-06 08:35:21 +0100386 lyxml_get_attribute((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
Radek Krejciee4cab22019-07-17 17:07:47 +0200387 break;
388 case LYXML_ELEM_CONTENT:
389 case LYXML_ATTR_CONTENT:
390 ret = lyxml_get_string((struct lyxml_context *)ctx, data, NULL, NULL, NULL, NULL, NULL);
Michal Vasko90932a92020-02-12 14:33:03 +0100391 /* not an error, just incorrect XML parser status */
392 if (ret && (ret != LY_EINVAL)) {
393 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200394 }
395 break;
396 case LYXML_END:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200397 /* end of data */
Radek Krejciee4cab22019-07-17 17:07:47 +0200398 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200399 ret = LY_EINT;
Radek Krejciee4cab22019-07-17 17:07:47 +0200400 goto cleanup;
401 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200402 }
Michal Vasko90932a92020-02-12 14:33:03 +0100403
404 /* get value */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200405 if (start != *data) {
406 /* data now points after the anydata's closing element tag, we need just end of its content */
407 for (stop = *data - 1; *stop != '<'; --stop);
Michal Vasko90932a92020-02-12 14:33:03 +0100408 start = lydict_insert(ctx->ctx, start, stop - start);
409 } else {
410 start = NULL;
411 }
412
413 /* create node */
414 ret = lyd_create_any(snode, start, LYD_ANYDATA_XML, &cur);
415 if (ret) {
416 lydict_remove(ctx->ctx, start);
417 goto cleanup;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200418 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200419 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200420
Michal Vasko9b368d32020-02-14 13:53:31 +0100421 /* correct flags */
Michal Vaskocde73ac2019-11-14 16:10:27 +0100422 if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100423 if (ctx->options & LYD_OPT_TRUSTED) {
424 /* just set it to true */
425 cur->flags |= LYD_WHEN_TRUE;
426 } else {
427 /* remember we need to evaluate this node's when */
428 ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
429 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100430 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100431 if (ctx->options & LYD_OPT_TRUSTED) {
432 /* node is valid */
433 cur->flags &= ~LYD_NEW;
434 }
Michal Vasko9f96a052020-03-10 09:41:45 +0100435 LY_LIST_FOR(meta, meta2) {
436 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
437 && meta2->value.boolean) {
Michal Vasko8d544252020-03-02 10:19:52 +0100438 /* node is default according to the metadata */
439 cur->flags |= LYD_DEFAULT;
440 }
441 }
442
Michal Vasko9f96a052020-03-10 09:41:45 +0100443 /* add metdata */
444 assert(!cur->meta);
445 cur->meta = meta;
446 meta = NULL;
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200447
Michal Vasko90932a92020-02-12 14:33:03 +0100448 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100449 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100450
451 cur = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200452 }
453
Michal Vasko90932a92020-02-12 14:33:03 +0100454 /* success */
455 ret = LY_SUCCESS;
456
Radek Krejcie7b95092019-05-15 11:03:07 +0200457cleanup:
Michal Vasko90932a92020-02-12 14:33:03 +0100458 free(buffer);
Michal Vasko9f96a052020-03-10 09:41:45 +0100459 lyd_free_meta(ctx->ctx, meta, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100460 lyd_free_tree(cur);
Radek Krejci28681fa2019-09-06 13:08:45 +0200461 for (unsigned int u = 0; u < attrs_data.count; ++u) {
462 if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
463 free(((struct attr_data_s*)attrs_data.objs[u])->value);
464 }
465 }
466 ly_set_erase(&attrs_data, free);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100467 if (ret && *first) {
468 lyd_free_siblings(*first);
469 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100470 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200471 return ret;
472}
473
474LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100475lyd_parse_xml_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200476{
Radek Krejci18a57d92019-07-25 14:01:42 +0200477 LY_ERR ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200478 struct lyd_xml_ctx xmlctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100479 uint32_t i = 0;
480 const struct lys_module *mod;
481 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200482
Michal Vaskoe75ecfd2020-03-06 14:12:28 +0100483 xmlctx.options = options;
Radek Krejcie7b95092019-05-15 11:03:07 +0200484 xmlctx.ctx = ctx;
485 xmlctx.line = 1;
486
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200487 /* init */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100488 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200489
Michal Vaskob1b5c262020-03-05 14:29:47 +0100490 /* parse XML data */
Michal Vasko9f96a052020-03-10 09:41:45 +0100491 ret = lydxml_data_r(&xmlctx, NULL, &data, tree);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100492 LY_CHECK_GOTO(ret, cleanup);
493
Michal Vasko9b368d32020-02-14 13:53:31 +0100494 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100495 next = *tree;
496 while (1) {
497 if (options & LYD_VALOPT_DATA_ONLY) {
498 mod = lyd_data_next_module(&next, &first);
499 } else {
500 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
501 }
502 if (!mod) {
503 break;
504 }
505 if (first == *tree) {
506 /* make sure first2 changes are carried to tree */
507 first2 = tree;
508 } else {
509 first2 = &first;
510 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100511
Michal Vaskob1b5c262020-03-05 14:29:47 +0100512 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
513 ret = lyd_validate_new(first2, NULL, mod);
514 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100515
Michal Vaskob1b5c262020-03-05 14:29:47 +0100516 /* add all top-level defaults for this module */
Michal Vaskoe75ecfd2020-03-06 14:12:28 +0100517 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &xmlctx.incomplete_type_validation,
518 &xmlctx.when_check, options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100519 LY_CHECK_GOTO(ret, cleanup);
520
521 /* finish incompletely validated terminal values/attributes and when conditions */
522 ret = lyd_validate_unres(tree, &xmlctx.when_check, &xmlctx.incomplete_type_validation,
Michal Vasko9f96a052020-03-10 09:41:45 +0100523 &xmlctx.incomplete_type_validation_meta, LYD_XML, lydxml_resolve_prefix, ctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100524 LY_CHECK_GOTO(ret, cleanup);
525
526 /* perform final validation that assumes the data tree is final */
Michal Vasko5b37a352020-03-06 13:38:33 +0100527 ret = lyd_validate_siblings_r(*first2, NULL, mod, options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100528 LY_CHECK_GOTO(ret, cleanup);
529 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100530 }
531
Michal Vaskocde73ac2019-11-14 16:10:27 +0100532cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100533 /* there should be no unresolved types stored */
534 assert(!(options & LYD_OPT_PARSE_ONLY) || (!xmlctx.incomplete_type_validation.count
Michal Vasko9f96a052020-03-10 09:41:45 +0100535 && !xmlctx.incomplete_type_validation_meta.count && !xmlctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100536
Michal Vaskocde73ac2019-11-14 16:10:27 +0100537 ly_set_erase(&xmlctx.incomplete_type_validation, NULL);
Michal Vasko9f96a052020-03-10 09:41:45 +0100538 ly_set_erase(&xmlctx.incomplete_type_validation_meta, NULL);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100539 ly_set_erase(&xmlctx.when_check, NULL);
Michal Vasko9b368d32020-02-14 13:53:31 +0100540 lyxml_context_clear((struct lyxml_context *)&xmlctx);
Radek Krejcie92210c2019-05-17 15:53:35 +0200541 if (ret) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100542 lyd_free_all(*tree);
543 *tree = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200544 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200545 return ret;
546}
Michal Vasko9f96a052020-03-10 09:41:45 +0100547
548static LY_ERR
549lydxml_rpc(struct lyd_xml_ctx *ctx, const char **data, struct ly_attr **attr)
550{
551 const char *prefix, *name;
552 size_t prefix_len, name_len;
553 struct ly_set attrs_data = {0};
554 const struct lyxml_ns *ns;
555
556 LY_CHECK_RET(lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len));
557 if (ly_strncmp("rpc", name, name_len)) {
558 /* not an rpc */
559 return LY_ENOT;
560 }
561
562 if (ctx->status == LYXML_ATTRIBUTE) {
563 LY_CHECK_RET(lydxml_attributes_parse(ctx, data, &attrs_data));
564 }
565
566 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
567 if (!ns || strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
568 /* wrong namespace */
569 return LY_ENOT;
570 }
571
572 /* all fine, just parse the rest of the attributes */
573 if (attrs_data.count) {
574 /* TODO parse into generic attribute structure, that will also be returned */
575 //LY_CHECK_RET(lydxml_attributes(ctx, &attrs_data, NULL, meta));
576 }
577
578 return LY_SUCCESS;
579}
580
581static LY_ERR
582lydxml_action(struct lyd_xml_ctx *ctx, const char **data)
583{
584 /* TODO */
585 return LY_ENOT;
586}
587
588LY_ERR
589lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct ly_attr **attr,
590 struct lyd_node **op)
591{
592 LY_ERR ret = LY_SUCCESS;
593 const char *data_p;
594 struct lyd_xml_ctx xmlctx = {0};
595
596 xmlctx.ctx = ctx;
597 xmlctx.line = 1;
598
599 /* init */
600 *tree = NULL;
601 data_p = data;
602
603 /* parse optional "rpc" element */
604 ret = lydxml_rpc(&xmlctx, &data_p, attr);
605 if (ret == LY_ENOT) {
606 /* reset data, nothing parsed */
607 data_p = data;
608 } else if (ret) {
609 goto cleanup;
610 } else {
611 /* successfully parsed */
612 data = data_p;
613
614 /* parse optional "action" element */
615 ret = lydxml_action(&xmlctx, &data_p);
616 if (ret == LY_ENOT) {
617 data_p = data;
618 } else if (ret) {
619 goto cleanup;
620 }
621 }
622
623 /* parse the rest of data tree normally */
624 ret = lydxml_data_r(&xmlctx, NULL, &data_p, tree);
625 LY_CHECK_GOTO(ret, cleanup);
626
627cleanup:
628 if (ret) {
629 lyd_free_all(*tree);
630 *tree = NULL;
631 }
632 return ret;
633}