blob: c150f42c951e8830bc9d79bd261d9981e479df84 [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>
20
21#include "context.h"
22#include "dict.h"
23#include "log.h"
24#include "plugins_types.h"
25#include "set.h"
26#include "tree_data.h"
27#include "tree_data_internal.h"
28#include "tree_schema.h"
29#include "xml.h"
Radek Krejci38d85362019-09-05 16:26:38 +020030#include "plugins_exts_internal.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 */
Radek Krejci38d85362019-09-05 16:26:38 +020050 struct ly_set incomplete_type_validation_attrs; /**< set of attributes 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
136lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, struct lyd_node *parent)
137{
138 LY_ERR ret = LY_EVALID, rc;
139 struct lyd_attr *attr = NULL, *last = NULL;
140 const struct lyxml_ns *ns;
141 struct lys_module *mod;
142
143 for (unsigned int u = 0; u < attrs_data->count; ++u) {
144 unsigned int v;
145 struct lysc_ext_instance *ant = NULL;
146 struct attr_data_s *attr_data = (struct attr_data_s*)attrs_data->objs[u];
147
148 if (!attr_data->prefix_len) {
149 /* in XML, all attributes must be prefixed
150 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
151 if (ctx->options & LYD_OPT_STRICT) {
152 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML attribute \"%.*s\".",
153 attr_data->name_len, attr_data->name);
154 }
155skip_attr:
156 if (attr_data->dynamic) {
157 free(attr_data->value);
158 attr_data->dynamic = 0;
159 }
160 continue;
161 }
162
163 /* get namespace of the attribute to find its annotation definition */
164 ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
165 if (!ns) {
166 /* unknown namespace, ignore the attribute */
167 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", attr_data->prefix_len, attr_data->prefix);
168 goto cleanup;
169 }
170 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
171 if (!mod) {
172 /* module is not implemented or not present in the schema */
173 if (ctx->options & LYD_OPT_STRICT) {
174 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
175 "Unknown (or not implemented) YANG module with namespace \"%s\" for attribute \"%.*s%s%.*s\".",
176 ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len, attr_data->name);
177 }
178 goto skip_attr;
179 }
180
181 LY_ARRAY_FOR(mod->compiled->exts, v) {
182 if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
Radek Krejci7f9b6512019-09-18 13:11:09 +0200183 !ly_strncmp(mod->compiled->exts[v].argument, attr_data->name, attr_data->name_len)) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200184 /* we have the annotation definition */
185 ant = &mod->compiled->exts[v];
186 break;
187 }
188 }
189 if (!ant) {
190 /* attribute is not defined as a metadata annotation (RFC 7952) */
191 if (ctx->options & LYD_OPT_STRICT) {
192 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Annotation definition for attribute \"%s:%.*s\" not found.",
193 mod->name, attr_data->name_len, attr_data->name);
194 }
195 goto skip_attr;
196 }
Radek Krejci17a78d82019-05-15 15:49:55 +0200197
198 attr = calloc(1, sizeof *attr);
199 LY_CHECK_ERR_GOTO(!attr, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200200 attr->parent = parent;
201 attr->annotation = ant;
202 rc = lyd_value_parse_attr(attr, attr_data->value, attr_data->value_len, attr_data->dynamic, 0, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
203 if (rc == LY_EINCOMPLETE) {
204 ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
205 } else if (rc) {
206 ret = rc;
207 free(attr);
208 goto cleanup;
209 }
210 attr_data->dynamic = 0; /* value eaten by lyd_value_parse_attr() */
211 attr->name = lydict_insert(ctx->ctx, attr_data->name, attr_data->name_len);
Radek Krejci17a78d82019-05-15 15:49:55 +0200212
213 if (last) {
214 last->next = attr;
215 } else {
Radek Krejci28681fa2019-09-06 13:08:45 +0200216 parent->attr = attr;
Radek Krejci17a78d82019-05-15 15:49:55 +0200217 }
218 last = attr;
Radek Krejcie7b95092019-05-15 11:03:07 +0200219 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200220 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200221
222cleanup:
223
Radek Krejci28681fa2019-09-06 13:08:45 +0200224 for (unsigned int u = 0; u < attrs_data->count; ++u) {
225 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
226 free(((struct attr_data_s*)attrs_data->objs[u])->value);
Radek Krejci38d85362019-09-05 16:26:38 +0200227 }
228 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200229 ly_set_erase(attrs_data, free);
230
Radek Krejcie7b95092019-05-15 11:03:07 +0200231 return ret;
232}
233
234/**
235 * @brief Parse XML elements as children YANG data node of the specified parent node.
236 *
237 * @param[in] ctx XML YANG data parser context.
238 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
239 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
240 * @param[out] node Resulting list of the parsed nodes.
241 * @reutn LY_ERR value.
242 */
243static LY_ERR
244lydxml_nodes(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **node)
245{
246 LY_ERR ret = LY_SUCCESS;
247 const char *prefix, *name;
Radek Krejcie7b95092019-05-15 11:03:07 +0200248 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200249 struct ly_set attrs_data = {0};
Radek Krejcie7b95092019-05-15 11:03:07 +0200250 const struct lyxml_ns *ns;
251 const struct lysc_node *snode;
252 struct lys_module *mod;
253 unsigned int parents_count = ctx->elements.count;
Radek Krejci710226d2019-07-24 17:24:59 +0200254 struct lyd_node *cur = NULL, *prev = NULL, *last = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200255
256 (*node) = NULL;
257
Michal Vasko14654712020-02-06 08:35:21 +0100258 while (ctx->status == LYXML_ELEMENT) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200259 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
260 LY_CHECK_GOTO(ret, cleanup);
261 if (!name) {
262 /* closing previous element */
Radek Krejcie7b95092019-05-15 11:03:07 +0200263 if (ctx->elements.count < parents_count) {
264 /* all siblings parsed */
265 break;
266 } else {
267 continue;
268 }
269 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200270 if (ctx->status == LYXML_ATTRIBUTE) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200271 LY_CHECK_GOTO(lydxml_attributes_parse(ctx, data, &attrs_data), error);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200272 }
273
Radek Krejcie7b95092019-05-15 11:03:07 +0200274 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
275 if (!ns) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200276 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Radek Krejci11702142019-07-24 17:46:04 +0200277 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200278 }
279 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
280 if (!mod) {
281 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Radek Krejci11702142019-07-24 17:46:04 +0200282 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200283 }
Michal Vaskoe444f752020-02-10 12:20:06 +0100284 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, 0);
Radek Krejcie7b95092019-05-15 11:03:07 +0200285 if (!snode) {
286 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.", name_len, name, mod->name);
Radek Krejci11702142019-07-24 17:46:04 +0200287 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200288 }
289
290 /* allocate new node */
291 switch (snode->nodetype) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200292 case LYS_ACTION:
Michal Vaskoa3881362020-01-21 15:57:35 +0100293 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected RPC/action element \"%.*s\".",
294 name_len, name);
295 goto error;
296 /*cur = calloc(1, sizeof(struct lyd_node_inner));
297 break;*/
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200298 case LYS_NOTIF:
Michal Vaskoa3881362020-01-21 15:57:35 +0100299 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected notification element \"%.*s\".",
300 name_len, name);
301 goto error;
302 /*cur = calloc(1, sizeof(struct lyd_node_inner));
303 break;*/
Radek Krejcie7b95092019-05-15 11:03:07 +0200304 case LYS_CONTAINER:
305 case LYS_LIST:
306 cur = calloc(1, sizeof(struct lyd_node_inner));
307 break;
308 case LYS_LEAF:
309 case LYS_LEAFLIST:
310 cur = calloc(1, sizeof(struct lyd_node_term));
311 break;
312 case LYS_ANYDATA:
313 case LYS_ANYXML:
314 cur = calloc(1, sizeof(struct lyd_node_any));
315 break;
Radek Krejcie7b95092019-05-15 11:03:07 +0200316 default:
317 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200318 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200319 goto cleanup;
320 }
321 if (!(*node)) {
322 (*node) = cur;
323 }
Radek Krejci710226d2019-07-24 17:24:59 +0200324 last = cur;
Radek Krejcie7b95092019-05-15 11:03:07 +0200325 cur->schema = snode;
Radek Krejci710226d2019-07-24 17:24:59 +0200326 cur->prev = cur;
Radek Krejcie7b95092019-05-15 11:03:07 +0200327 cur->parent = parent;
Radek Krejcie92210c2019-05-17 15:53:35 +0200328 if (parent) {
Radek Krejci710226d2019-07-24 17:24:59 +0200329 if (prev && cur->schema->nodetype == LYS_LEAF && (cur->schema->flags & LYS_KEY)) {
330 /* it is key and we need to insert it into a correct place */
Radek Krejci0fe9b512019-07-26 17:51:05 +0200331 struct lysc_node *key_s;
Radek Krejci710226d2019-07-24 17:24:59 +0200332 unsigned int cur_index, key_index;
333 struct lyd_node *key;
334
Radek Krejci0fe9b512019-07-26 17:51:05 +0200335 for (cur_index = 0, key_s = ((struct lysc_node_list*)parent->schema)->child;
336 key_s && key_s != cur->schema;
337 ++cur_index, key_s = key_s->next);
338 for (key = prev;
339 !(key->schema->flags & LYS_KEY) && key->prev != prev;
340 key = key->prev);
Radek Krejci710226d2019-07-24 17:24:59 +0200341 for (; key->schema->flags & LYS_KEY; key = key->prev) {
Radek Krejci0fe9b512019-07-26 17:51:05 +0200342 for (key_index = 0, key_s = ((struct lysc_node_list*)parent->schema)->child;
343 key_s && key_s != key->schema;
344 ++key_index, key_s = key_s->next);
Radek Krejci710226d2019-07-24 17:24:59 +0200345 if (key_index < cur_index) {
346 /* cur key is supposed to be placed after the key */
347 cur->next = key->next;
348 cur->prev = key;
349 key->next = cur;
350 if (cur->next) {
351 cur->next->prev = cur;
352 } else {
353 parent->child->prev = cur;
354 }
355 break;
356 }
357 if (key->prev == prev) {
358 /* current key is supposed to be the first child from the current children */
359 key = NULL;
360 break;
361 }
362 }
363 if (!key || !(key->schema->flags & LYS_KEY)) {
364 /* current key is supposed to be the first child from the current children */
365 cur->next = parent->child;
366 cur->prev = parent->child->prev;
367 parent->child->prev = cur;
368 parent->child = cur;
369 }
370 if (cur->next) {
371 last = prev;
372 if (ctx->options & LYD_OPT_STRICT) {
Michal Vaskoecd62de2019-11-13 12:35:11 +0100373 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%.*s\" in a list.",
Radek Krejci710226d2019-07-24 17:24:59 +0200374 name_len, name);
Radek Krejci11702142019-07-24 17:46:04 +0200375 goto error;
Radek Krejci710226d2019-07-24 17:24:59 +0200376 } else {
377 LOGWRN(ctx->ctx, "Invalid position of the key \"%.*s\" in a list.", name_len, name);
378 }
379 }
380 } else {
381 /* last child of the parent */
382 if (prev) {
383 parent->child->prev = cur;
384 prev->next = cur;
385 cur->prev = prev;
386 }
387 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200388 } else {
Radek Krejci710226d2019-07-24 17:24:59 +0200389 /* top level */
390 if (prev) {
391 /* last top level node */
392 struct lyd_node *iter;
393 for (iter = prev; iter->prev->next; iter = iter->prev);
394 iter->prev = cur;
395 prev->next = cur;
396 cur->prev = prev;
397 } /* first top level node - nothing more to do */
Radek Krejcie7b95092019-05-15 11:03:07 +0200398 }
Radek Krejci710226d2019-07-24 17:24:59 +0200399 prev = last;
Radek Krejci28681fa2019-09-06 13:08:45 +0200400 LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200401
402 if (snode->nodetype & LYD_NODE_TERM) {
403 int dynamic = 0;
404 char *buffer = NULL, *value;
405 size_t buffer_size = 0, value_len;
406
407 if (ctx->status == LYXML_ELEM_CONTENT) {
408 /* get the value */
Radek Krejci11702142019-07-24 17:46:04 +0200409 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
Michal Vasko14654712020-02-06 08:35:21 +0100410 if (ret != LY_SUCCESS) {
411 if (ret == LY_EINVAL) {
412 /* just indentation of a child element found */
413 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside terminal node \"%s\" found.", cur->schema->name);
414 }
Radek Krejci339e2de2019-05-17 14:28:24 +0200415 goto cleanup;
416 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200417 } else {
418 /* no content - validate empty value */
419 value = "";
420 value_len = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200421 }
Michal Vasko14654712020-02-06 08:35:21 +0100422 ret = lyd_value_parse((struct lyd_node_term *)cur, value, value_len, dynamic, 0, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200423 if (ret == LY_EINCOMPLETE) {
424 ly_set_add(&ctx->incomplete_type_validation, cur, LY_SET_OPT_USEASLIST);
425 } else if (ret) {
426 if (dynamic){
427 free(value);
428 }
429 goto cleanup;
430 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200431 } else if (snode->nodetype & LYD_NODE_INNER) {
432 int dynamic = 0;
433 char *buffer = NULL, *value;
434 size_t buffer_size = 0, value_len;
435
436 if (ctx->status == LYXML_ELEM_CONTENT) {
437 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 +0200438 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200439 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200440 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200441 goto cleanup;
442 }
443 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200444 /* process children */
Radek Krejcie553e6d2019-06-07 15:33:18 +0200445 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
Michal Vasko14654712020-02-06 08:35:21 +0100446 ret = lydxml_nodes(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
Radek Krejcie92210c2019-05-17 15:53:35 +0200447 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200448 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200449 } else if (snode->nodetype & LYD_NODE_ANY) {
450 unsigned int cur_element_index = ctx->elements.count;
451 const char *start = *data, *stop;
452 const char *p, *n;
453 size_t p_len, n_len;
454
455 /* skip children data and store them as a string */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200456 while (ctx->status != LYXML_END && cur_element_index <= ctx->elements.count) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200457 switch (ctx->status) {
458 case LYXML_ELEMENT:
459 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
460 break;
461 case LYXML_ATTRIBUTE:
Michal Vasko14654712020-02-06 08:35:21 +0100462 lyxml_get_attribute((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
Radek Krejciee4cab22019-07-17 17:07:47 +0200463 break;
464 case LYXML_ELEM_CONTENT:
465 case LYXML_ATTR_CONTENT:
466 ret = lyxml_get_string((struct lyxml_context *)ctx, data, NULL, NULL, NULL, NULL, NULL);
467 if (ret == LY_EINVAL) {
468 /* not an error, just incorrect XML parser status */
469 ret = LY_SUCCESS;
470 }
471 break;
472 case LYXML_END:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200473 /* end of data */
Radek Krejciee4cab22019-07-17 17:07:47 +0200474 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200475 ret = LY_EINT;
Radek Krejciee4cab22019-07-17 17:07:47 +0200476 goto cleanup;
477 }
478 LY_CHECK_GOTO(ret, cleanup);
479 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200480 ((struct lyd_node_any*)cur)->value_type = LYD_ANYDATA_XML;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200481 if (start != *data) {
482 /* data now points after the anydata's closing element tag, we need just end of its content */
483 for (stop = *data - 1; *stop != '<'; --stop);
484 ((struct lyd_node_any*)cur)->value.xml = lydict_insert(ctx->ctx, start, stop - start);
485 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200486 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200487
Michal Vaskocde73ac2019-11-14 16:10:27 +0100488 /* remember we need to evaluate this node's when */
489 if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
490 ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
491 }
492
Michal Vaskoe444f752020-02-10 12:20:06 +0100493 /* calculate the hash and insert it into parent */
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200494 lyd_hash(cur);
495 lyd_insert_hash(cur);
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200496
497 /* if we have empty non-presence container, we keep it, but mark it as default */
Michal Vasko14654712020-02-06 08:35:21 +0100498 if (cur->schema->nodetype == LYS_CONTAINER && !((struct lyd_node_inner *)cur)->child &&
499 !cur->attr && !(((struct lysc_node_container *)cur->schema)->flags & LYS_PRESENCE)) {
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200500 cur->flags |= LYD_DEFAULT;
501 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200502 }
503
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200504 /* TODO add missing siblings default elements */
505
Radek Krejcie7b95092019-05-15 11:03:07 +0200506cleanup:
Radek Krejci28681fa2019-09-06 13:08:45 +0200507 for (unsigned int u = 0; u < attrs_data.count; ++u) {
508 if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
509 free(((struct attr_data_s*)attrs_data.objs[u])->value);
510 }
511 }
512 ly_set_erase(&attrs_data, free);
Radek Krejcie7b95092019-05-15 11:03:07 +0200513 return ret;
Radek Krejci11702142019-07-24 17:46:04 +0200514
515error:
516 ret = LY_EVALID;
517 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200518}
519
520LY_ERR
Michal Vaskoa3881362020-01-21 15:57:35 +0100521lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **result)
Radek Krejcie7b95092019-05-15 11:03:07 +0200522{
Radek Krejci18a57d92019-07-25 14:01:42 +0200523 LY_ERR ret = LY_SUCCESS;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200524 struct lyd_node_inner *parent = NULL;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100525 const struct lyd_node **result_trees = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200526 struct lyd_xml_ctx xmlctx = {0};
527
528 xmlctx.options = options;
529 xmlctx.ctx = ctx;
530 xmlctx.line = 1;
531
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200532 /* init */
533 *result = NULL;
534
Michal Vaskoa3881362020-01-21 15:57:35 +0100535#if 0
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200536 if (options & LYD_OPT_RPCREPLY) {
Radek Krejci3c1046e2019-07-26 13:06:53 +0200537 /* prepare container for RPC reply, for which we need RPC
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200538 * - prepare *result as top-level node
539 * - prepare parent as the RPC/action node */
Radek Krejci3c1046e2019-07-26 13:06:53 +0200540 const struct lyd_node *action;
541 for (action = trees[0]; action && action->schema->nodetype != LYS_ACTION; action = lyd_node_children(action)) {
542 /* skip list's keys */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200543 for ( ;action && action->schema->nodetype == LYS_LEAF; action = action->next);
544 if (action && action->schema->nodetype == LYS_ACTION) {
545 break;
546 }
Radek Krejci3c1046e2019-07-26 13:06:53 +0200547 }
548 if (!action) {
549 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
550 lyd_parse_options_type2str(options));
551 return LY_EINVAL;
552 }
553 parent = (struct lyd_node_inner*)lyd_dup(action, NULL, LYD_DUP_WITH_PARENTS);
554 LY_CHECK_ERR_RET(!parent, LOGERR(ctx, ly_errcode(ctx), "Unable to duplicate RPC/action container for RPC/action reply."), ly_errcode(ctx));
555 for (*result = (struct lyd_node*)parent; (*result)->parent; *result = (struct lyd_node*)(*result)->parent);
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200556 }
Michal Vaskoa3881362020-01-21 15:57:35 +0100557#endif
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200558
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200559 if (!data || !data[0]) {
Michal Vaskocde73ac2019-11-14 16:10:27 +0100560 /* no data - just check for missing mandatory nodes */
561 goto validation;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200562 }
563
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200564 ret = lydxml_nodes(&xmlctx, parent, &data, *result ? &parent->child : result);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100565 LY_CHECK_GOTO(ret, cleanup);
566
567 /* prepare sized array for validator */
568 if (*result) {
569 result_trees = lyd_trees_new(1, *result);
570 }
571
572 /* finish incompletely validated terminal values/attributes and when conditions */
573 ret = lyd_validate_unres(&xmlctx.incomplete_type_validation, &xmlctx.incomplete_type_validation_attrs,
574 &xmlctx.when_check, LYD_XML, lydxml_resolve_prefix, ctx, result_trees);
575 LY_CHECK_GOTO(ret, cleanup);
576
577validation:
Michal Vaskoa3881362020-01-21 15:57:35 +0100578#if 0
Michal Vaskocde73ac2019-11-14 16:10:27 +0100579 if ((!(*result) || (parent && !parent->child)) && (options & (LYD_OPT_RPC | LYD_OPT_NOTIF))) {
580 /* error, missing top level node identify RPC and Notification */
581 LOGERR(ctx, LY_EINVAL, "Invalid input data of data parser - expected %s which cannot be empty.",
582 lyd_parse_options_type2str(options));
583 ret = LY_EINVAL;
584 goto cleanup;
585 }
Michal Vaskoa3881362020-01-21 15:57:35 +0100586#endif
Michal Vaskocde73ac2019-11-14 16:10:27 +0100587
588 /* context node and other validation tasks that depend on other data nodes */
Michal Vaskoacd83e72020-02-04 14:12:01 +0100589 ret = lyd_validate_data(result_trees, NULL, 0, ctx, options);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100590 LY_CHECK_GOTO(result, cleanup);
591
592cleanup:
593 ly_set_erase(&xmlctx.incomplete_type_validation, NULL);
594 ly_set_erase(&xmlctx.incomplete_type_validation_attrs, NULL);
595 ly_set_erase(&xmlctx.when_check, NULL);
596 lyxml_context_clear((struct lyxml_context*)&xmlctx);
597 lyd_trees_free(result_trees, 0);
Radek Krejcie92210c2019-05-17 15:53:35 +0200598 if (ret) {
599 lyd_free_all(*result);
600 *result = NULL;
601 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200602 return ret;
603}