blob: e05f1700042a31e6f91daae893aa36286b517283 [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
Michal Vasko52927e22020-03-16 17:26:14 +010045 uint32_t options; /**< various @ref dataparseroptions. */
46 uint32_t path_len; /**< used bytes in the path buffer */
Radek Krejcie7b95092019-05-15 11:03:07 +020047#define LYD_PARSER_BUFSIZE 4078
48 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko52927e22020-03-16 17:26:14 +010049 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
50 struct ly_set unres_meta_type; /**< set of metadata 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 *
Michal Vasko52927e22020-03-16 17:26:14 +010059lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020060{
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 *
Michal Vasko52927e22020-03-16 17:26:14 +010085 * @param[in] xmlctx XML 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
Michal Vasko52927e22020-03-16 17:26:14 +010092lydxml_attributes_parse(struct lyxml_context *xmlctx, 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
Michal Vasko52927e22020-03-16 17:26:14 +0100100 while (xmlctx->status == LYXML_ATTRIBUTE &&
101 lyxml_get_attribute(xmlctx, 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;
Michal Vasko52927e22020-03-16 17:26:14 +0100118 ret = lyxml_get_string(xmlctx, 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 Vasko52927e22020-03-16 17:26:14 +0100136lydxml_metadata(struct lyxml_context *xmlctx, struct ly_set *attrs_data, const struct lysc_node *sparent, int strict,
137 struct ly_set *type_meta_check, struct lyd_meta **meta)
Radek Krejci28681fa2019-09-06 13:08:45 +0200138{
139 LY_ERR ret = LY_EVALID, rc;
Radek Krejci28681fa2019-09-06 13:08:45 +0200140 const struct lyxml_ns *ns;
141 struct lys_module *mod;
142
143 for (unsigned int u = 0; u < attrs_data->count; ++u) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200144 struct attr_data_s *attr_data = (struct attr_data_s*)attrs_data->objs[u];
145
146 if (!attr_data->prefix_len) {
147 /* in XML, all attributes must be prefixed
148 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vasko52927e22020-03-16 17:26:14 +0100149 if (strict) {
150 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci28681fa2019-09-06 13:08:45 +0200151 attr_data->name_len, attr_data->name);
152 }
153skip_attr:
154 if (attr_data->dynamic) {
155 free(attr_data->value);
156 attr_data->dynamic = 0;
157 }
158 continue;
159 }
160
161 /* get namespace of the attribute to find its annotation definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100162 ns = lyxml_ns_get(xmlctx, attr_data->prefix, attr_data->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200163 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100164 /* unknown namespace, XML error */
165 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
166 attr_data->prefix_len, attr_data->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200167 goto cleanup;
168 }
Michal Vasko52927e22020-03-16 17:26:14 +0100169 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200170 if (!mod) {
171 /* module is not implemented or not present in the schema */
Michal Vasko52927e22020-03-16 17:26:14 +0100172 if (strict) {
173 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100174 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vasko90932a92020-02-12 14:33:03 +0100175 ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len,
176 attr_data->name);
Radek Krejci28681fa2019-09-06 13:08:45 +0200177 }
178 goto skip_attr;
179 }
180
Michal Vasko52927e22020-03-16 17:26:14 +0100181 rc = lyd_create_meta(NULL, meta, mod, attr_data->name, attr_data->name_len, attr_data->value, attr_data->value_len,
182 &attr_data->dynamic, lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
Radek Krejci28681fa2019-09-06 13:08:45 +0200183 if (rc == LY_EINCOMPLETE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100184 if (type_meta_check) {
185 ly_set_add(type_meta_check, meta, LY_SET_OPT_USEASLIST);
186 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200187 } else if (rc) {
188 ret = rc;
Radek Krejci28681fa2019-09-06 13:08:45 +0200189 goto cleanup;
190 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200191 }
Michal Vasko52927e22020-03-16 17:26:14 +0100192
Radek Krejci28681fa2019-09-06 13:08:45 +0200193 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200194
195cleanup:
Radek Krejci28681fa2019-09-06 13:08:45 +0200196 for (unsigned int u = 0; u < attrs_data->count; ++u) {
197 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
198 free(((struct attr_data_s*)attrs_data->objs[u])->value);
Radek Krejci38d85362019-09-05 16:26:38 +0200199 }
200 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200201 ly_set_erase(attrs_data, free);
202
Radek Krejcie7b95092019-05-15 11:03:07 +0200203 return ret;
204}
205
Michal Vasko52927e22020-03-16 17:26:14 +0100206static LY_ERR
207lydxml_attrs(struct lyxml_context *xmlctx, struct ly_set *attrs_data, struct ly_attr **attr)
208{
209 LY_ERR ret = LY_SUCCESS;
210 const struct lyxml_ns *ns;
211 struct ly_prefix *val_prefs;
212 struct ly_attr *attr2;
213
214 assert(attr);
215
216 for (unsigned int u = 0; u < attrs_data->count; ++u) {
217 struct attr_data_s *attr_data = (struct attr_data_s *)attrs_data->objs[u];
218
219 ns = NULL;
220 if (attr_data->prefix_len) {
221 /* get namespace of the attribute */
222 ns = lyxml_ns_get(xmlctx, attr_data->prefix, attr_data->prefix_len);
223 if (!ns) {
224 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
225 attr_data->prefix_len, attr_data->prefix);
226 ret = LY_EVALID;
227 goto cleanup;
228 }
229 }
230
231 if (*attr) {
232 attr2 = *attr;
233 } else {
234 attr2 = NULL;
235 }
236
237 /* get value prefixes */
238 ret = lyxml_get_prefixes(xmlctx, attr_data->value, attr_data->value_len, &val_prefs);
239 LY_CHECK_GOTO(ret, cleanup);
240
241 /* attr2 is always changed to the created attribute */
242 ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, attr_data->name, attr_data->name_len, attr_data->value,
243 attr_data->value_len, &attr_data->dynamic, LYD_XML, val_prefs, attr_data->prefix,
244 attr_data->prefix_len, ns ? ns->uri : NULL);
245 LY_CHECK_GOTO(ret, cleanup);
246
247 if (!*attr) {
248 *attr = attr2;
249 }
250 }
251
252cleanup:
253 for (unsigned int u = 0; u < attrs_data->count; ++u) {
254 if (((struct attr_data_s *)attrs_data->objs[u])->dynamic) {
255 free(((struct attr_data_s *)attrs_data->objs[u])->value);
256 }
257 }
258 ly_set_erase(attrs_data, free);
259 return ret;
260}
261
Michal Vasko44685da2020-03-17 15:38:06 +0100262static LY_ERR
263lydxml_check_list(struct lyxml_context *xmlctx, const struct lysc_node *list, const char **data)
264{
265 LY_ERR ret;
266 struct ly_set key_set = {0};
267 const struct lysc_node *snode;
268 const char *name;
269 char *buffer = NULL, *value;
270 size_t name_len, buffer_size = 0, value_len;
271 int dynamic = 0;
272 uint32_t i, parents_count = xmlctx->elements.count;
273
274 assert(list && (list->nodetype == LYS_LIST));
275
276 /* get all keys into a set (keys do not have if-features or anything) */
277 snode = NULL;
278 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
279 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
280 }
281
282 while ((xmlctx->status == LYXML_ELEMENT) && key_set.count) {
283 /* keys must be from the same module */
284 LY_CHECK_GOTO(ret = lyxml_get_element(xmlctx, data, NULL, NULL, &name, &name_len), cleanup);
285 if (!name) {
286 /* closing previous element */
287 if (xmlctx->elements.count < parents_count) {
288 /* all siblings parsed */
289 break;
290 } else {
291 continue;
292 }
293 }
294
295 /* find key definition */
296 for (i = 0; i < key_set.count; ++i) {
297 snode = (const struct lysc_node *)key_set.objs[i];
298 if (!ly_strncmp(snode->name, name, name_len)) {
299 break;
300 }
301 }
302 if (i == key_set.count) {
303 /* uninteresting, skip it */
304 LY_CHECK_GOTO(ret = lyxml_skip_element(xmlctx, data), cleanup);
305 continue;
306 }
307
308 /* skip attributes */
309 while (xmlctx->status == LYXML_ATTRIBUTE) {
310 LY_CHECK_GOTO(ret = lyxml_get_attribute(xmlctx, data, NULL, NULL, NULL, NULL), cleanup);
311 }
312
313 /* get the value, if any */
314 if (dynamic) {
315 free(value);
316 }
317 value = "";
318 value_len = 0;
319 dynamic = 0;
320 if (xmlctx->status == LYXML_ELEM_CONTENT) {
321 ret = lyxml_get_string(xmlctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
322 if (ret && (ret != LY_EINVAL)) {
323 goto cleanup;
324 }
325 }
326
327 /* validate it */
328 LY_CHECK_GOTO(ret = lys_value_validate(NULL, snode, value, value_len, lydxml_resolve_prefix, xmlctx->ctx, LYD_XML), cleanup);
329
330 /* key with a valid value, remove from the set */
331 ly_set_rm_index(&key_set, i, NULL);
332 }
333
334 if (key_set.count) {
335 /* some keys missing */
336 ret = LY_ENOT;
337 } else {
338 /* all keys found and validated */
339 ret = LY_SUCCESS;
340 }
341
342cleanup:
343 ly_set_erase(&key_set, NULL);
344 return ret;
345}
346
Radek Krejcie7b95092019-05-15 11:03:07 +0200347/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100348 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200349 *
350 * @param[in] ctx XML YANG data parser context.
351 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
352 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
353 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100354 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200355 */
356static LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100357lydxml_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 +0200358{
Michal Vasko44685da2020-03-17 15:38:06 +0100359 LY_ERR ret = LY_SUCCESS, content_ret;
360 const char *prefix, *name, *backup_data;
361 char *buffer = NULL, *value;
362 size_t prefix_len, name_len, buffer_size = 0, value_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200363 struct ly_set attrs_data = {0};
Michal Vasko44685da2020-03-17 15:38:06 +0100364 struct lyxml_context backup_ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200365 const struct lyxml_ns *ns;
Michal Vasko52927e22020-03-16 17:26:14 +0100366 struct lyd_meta *meta = NULL, *meta2, *prev_meta;
367 struct ly_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200368 const struct lysc_node *snode;
369 struct lys_module *mod;
Michal Vasko44685da2020-03-17 15:38:06 +0100370 uint32_t prev_opts, parents_count = ctx->elements.count;
Michal Vasko52927e22020-03-16 17:26:14 +0100371 struct lyd_node *cur = NULL, *anchor;
372 struct ly_prefix *val_prefs;
Michal Vasko90932a92020-02-12 14:33:03 +0100373 int dynamic = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200374
Michal Vasko14654712020-02-06 08:35:21 +0100375 while (ctx->status == LYXML_ELEMENT) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200376 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
377 LY_CHECK_GOTO(ret, cleanup);
378 if (!name) {
379 /* closing previous element */
Radek Krejcie7b95092019-05-15 11:03:07 +0200380 if (ctx->elements.count < parents_count) {
381 /* all siblings parsed */
382 break;
383 } else {
384 continue;
385 }
386 }
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100387
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200388 if (ctx->status == LYXML_ATTRIBUTE) {
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100389 /* first parse all attributes so we have all the namespaces available */
Michal Vasko52927e22020-03-16 17:26:14 +0100390 if (lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data) != LY_SUCCESS) {
Michal Vasko90932a92020-02-12 14:33:03 +0100391 ret = LY_EVALID;
392 goto cleanup;
393 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200394 }
395
Radek Krejcie7b95092019-05-15 11:03:07 +0200396 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
397 if (!ns) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200398 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100399 ret = LY_EVALID;
400 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200401 }
402 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
Michal Vasko52927e22020-03-16 17:26:14 +0100403 if (!mod && (ctx->options & LYD_OPT_STRICT)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200404 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 +0100405 ret = LY_EVALID;
406 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200407 }
Michal Vasko52927e22020-03-16 17:26:14 +0100408
409 snode = NULL;
410 if (mod && (!parent || parent->schema)) {
411 /* leave if-feature check for validation */
412 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
413 if (!snode && (ctx->options & LYD_OPT_STRICT)) {
414 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
415 name_len, name, mod->name);
416 ret = LY_EVALID;
417 goto cleanup;
418 }
419 if (snode) {
420 if ((ctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
421 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INSTATE, snode->name);
422 ret = LY_EVALID;
423 goto cleanup;
424 }
425 if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
426 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
427 snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
428 ret = LY_EVALID;
429 goto cleanup;
430 }
431 }
Michal Vasko5b37a352020-03-06 13:38:33 +0100432 }
Radek Krejci710226d2019-07-24 17:24:59 +0200433
Michal Vasko44685da2020-03-17 15:38:06 +0100434 /* get the value, if any */
435 value = "";
436 value_len = 0;
437 dynamic = 0;
438 content_ret = LY_SUCCESS;
439 if (ctx->status == LYXML_ELEM_CONTENT) {
440 content_ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
441 if (content_ret && (content_ret != LY_EINVAL)) {
442 LOGINT(ctx->ctx);
443 ret = LY_EINT;
444 goto cleanup;
445 }
446 }
447
448 if (snode && (ctx->options & LYD_OPT_OPAQ)) {
449 if (snode->nodetype & LYD_NODE_TERM) {
450 /* value may not be valid in which case we parse it as an opaque node */
451 if (lys_value_validate(NULL, snode, value, value_len, lydxml_resolve_prefix, ctx, LYD_XML)) {
452 snode = NULL;
453 }
454 } else if (snode->nodetype == LYS_LIST) {
455 /* use backup context and data pointer */
456 backup_ctx.ctx = ctx->ctx;
457 backup_ctx.line = ctx->line;
458 backup_ctx.status = ctx->status;
459 memset(&backup_ctx.elements, 0, sizeof backup_ctx.elements);
460 for (uint32_t i = 0; i < ctx->elements.count; ++i) {
461 ly_set_add(&backup_ctx.elements, lyxml_elem_dup(ctx->elements.objs[i]), LY_SET_OPT_USEASLIST);
462 }
463 memset(&backup_ctx.ns, 0, sizeof backup_ctx.ns);
464 for (uint32_t i = 0; i < ctx->ns.count; ++i) {
465 ly_set_add(&backup_ctx.ns, lyxml_ns_dup(ctx->ns.objs[i]), LY_SET_OPT_USEASLIST);
466 }
467 backup_data = *data;
468
469 /* list may be missing some keys, parse as opaque if it does */
470 if (lydxml_check_list(&backup_ctx, snode, &backup_data)) {
471 snode = NULL;
472 }
473
474 lyxml_context_clear(&backup_ctx);
475 }
476 }
477
Michal Vasko9f96a052020-03-10 09:41:45 +0100478 /* create actual metadata so that prefixes are available in the context */
Michal Vasko8d544252020-03-02 10:19:52 +0100479 if (attrs_data.count) {
Michal Vasko52927e22020-03-16 17:26:14 +0100480 if (snode) {
481 ret = lydxml_metadata((struct lyxml_context *)ctx, &attrs_data, snode, ctx->options & LYD_OPT_STRICT,
482 &ctx->unres_meta_type, &meta);
483 LY_CHECK_GOTO(ret, cleanup);
484 } else if (ctx->options & LYD_OPT_OPAQ) {
485 ret = lydxml_attrs((struct lyxml_context *)ctx, &attrs_data, &attr);
486 LY_CHECK_GOTO(ret, cleanup);
487 } else {
488 /* free attr data */
489 for (uint32_t u = 0; u < attrs_data.count; ++u) {
490 if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
491 free(((struct attr_data_s*)attrs_data.objs[u])->value);
492 }
493 }
494 ly_set_erase(&attrs_data, free);
495 }
Michal Vasko8d544252020-03-02 10:19:52 +0100496 }
497
Michal Vasko52927e22020-03-16 17:26:14 +0100498 if (!snode) {
499 if (ctx->options & LYD_OPT_OPAQ) {
Michal Vasko52927e22020-03-16 17:26:14 +0100500 /* get value prefixes */
501 ret = lyxml_get_prefixes((struct lyxml_context *)ctx, value, value_len, &val_prefs);
502 LY_CHECK_GOTO(ret, cleanup);
503
504 /* create node */
505 ret = lyd_create_opaq(ctx->ctx, name, name_len, value, value_len, &dynamic, LYD_XML, val_prefs, prefix,
506 prefix_len, ns->uri, &cur);
507 LY_CHECK_GOTO(ret, cleanup);
508
509 /* process children */
510 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
511 ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
512 LY_CHECK_GOTO(ret, cleanup);
513 }
514 } else {
515 /* skip element */
516 ret = lyxml_skip_element((struct lyxml_context *)ctx, data);
517 LY_CHECK_GOTO(ret, cleanup);
518 break;
519 }
520 } else if (snode->nodetype & LYD_NODE_TERM) {
Michal Vasko44685da2020-03-17 15:38:06 +0100521 if (content_ret == LY_EINVAL) {
522 /* just indentation of a child element found */
523 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside a terminal node \"%s\" found.",
524 snode->name);
525 ret = LY_EVALID;
526 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200527 }
Michal Vasko90932a92020-02-12 14:33:03 +0100528
529 /* create node */
530 ret = lyd_create_term(snode, value, value_len, &dynamic, lydxml_resolve_prefix, ctx, LYD_XML, &cur);
531 /* buffer spent */
532 buffer = NULL;
Radek Krejcie553e6d2019-06-07 15:33:18 +0200533 if (ret == LY_EINCOMPLETE) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100534 if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vasko52927e22020-03-16 17:26:14 +0100535 ly_set_add(&ctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100536 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200537 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200538 goto cleanup;
539 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100540
541 if (parent && (cur->schema->flags & LYS_KEY)) {
542 /* check the key order, the anchor must always be the last child */
Michal Vasko52927e22020-03-16 17:26:14 +0100543 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
544 if ((!anchor && parent->child) || (anchor && anchor->next)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100545 if (ctx->options & LYD_OPT_STRICT) {
546 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
547 cur->schema->name);
548 ret = LY_EVALID;
549 goto cleanup;
550 } else {
551 LOGWRN(ctx->ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
552 }
553 }
554 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200555 } else if (snode->nodetype & LYD_NODE_INNER) {
Michal Vasko44685da2020-03-17 15:38:06 +0100556 if (value_len) {
557 /* value in inner node */
558 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Text value inside an inner node \"%s\" found.",
559 snode->name);
560 ret = LY_EVALID;
561 goto cleanup;
562
Radek Krejcie7b95092019-05-15 11:03:07 +0200563 }
Michal Vasko90932a92020-02-12 14:33:03 +0100564
565 /* create node */
566 ret = lyd_create_inner(snode, &cur);
567 LY_CHECK_GOTO(ret, cleanup);
568
Radek Krejciee4cab22019-07-17 17:07:47 +0200569 /* process children */
Radek Krejcie553e6d2019-06-07 15:33:18 +0200570 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100571 ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
572 LY_CHECK_GOTO(ret, cleanup);
573 }
574
575 if (snode->nodetype == LYS_LIST) {
576 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100577 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200578 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100579
580 if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100581 /* new node validation, autodelete CANNOT occur, all nodes are new */
582 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
583 LY_CHECK_GOTO(ret, cleanup);
584
Michal Vasko9b368d32020-02-14 13:53:31 +0100585 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100586 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vasko52927e22020-03-16 17:26:14 +0100587 &ctx->unres_node_type, &ctx->when_check, ctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100588 LY_CHECK_GOTO(ret, cleanup);
589 }
590
591 /* hash now that all keys should be parsed, rehash for key-less list */
592 if (snode->nodetype == LYS_LIST) {
593 lyd_hash(cur);
594 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200595 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko52927e22020-03-16 17:26:14 +0100596 /* just incorrect status */
597 if (ctx->status == LYXML_ELEM_CONTENT) {
598 LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
599 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200600 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200601 ret = LY_EINT;
Radek Krejciee4cab22019-07-17 17:07:47 +0200602 goto cleanup;
603 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200604 }
Michal Vasko90932a92020-02-12 14:33:03 +0100605
Michal Vasko52927e22020-03-16 17:26:14 +0100606 /* parse any data tree with correct options */
607 prev_opts = ctx->options;
608 ctx->options &= ~LYD_OPT_STRICT;
609 ctx->options |= LYD_OPT_OPAQ;
610 anchor = NULL;
611 ret = lydxml_data_r(ctx, NULL, data, &anchor);
612 ctx->options = prev_opts;
613 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100614
615 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100616 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
617 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200618 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200619
Michal Vasko9b368d32020-02-14 13:53:31 +0100620 /* correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100621 if (snode) {
622 if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
623 if (ctx->options & LYD_OPT_TRUSTED) {
624 /* just set it to true */
625 cur->flags |= LYD_WHEN_TRUE;
626 } else {
627 /* remember we need to evaluate this node's when */
628 ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
629 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100630 }
Michal Vasko52927e22020-03-16 17:26:14 +0100631 if (ctx->options & LYD_OPT_TRUSTED) {
632 /* node is valid */
633 cur->flags &= ~LYD_NEW;
634 }
635 prev_meta = NULL;
636 LY_LIST_FOR(meta, meta2) {
637 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
638 && meta2->value.boolean) {
639 /* node is default according to the metadata */
640 cur->flags |= LYD_DEFAULT;
641
642 /* delete the metadata */
643 if (prev_meta) {
644 prev_meta->next = meta2->next;
645 } else {
646 meta = meta->next;
647 }
648 lyd_free_meta(ctx->ctx, meta2, 0);
649 break;
650 }
651
652 prev_meta = meta2;
Michal Vasko8d544252020-03-02 10:19:52 +0100653 }
654 }
655
Michal Vasko52927e22020-03-16 17:26:14 +0100656 /* add metadata/attributes */
657 if (snode) {
658 cur->meta = meta;
659 meta = NULL;
660 } else {
661 assert(!cur->schema);
662 ((struct lyd_node_opaq *)cur)->attr = attr;
663 attr = NULL;
664 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200665
Michal Vasko90932a92020-02-12 14:33:03 +0100666 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100667 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100668
669 cur = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200670 }
671
Michal Vasko90932a92020-02-12 14:33:03 +0100672 /* success */
673 ret = LY_SUCCESS;
674
Radek Krejcie7b95092019-05-15 11:03:07 +0200675cleanup:
Michal Vasko90932a92020-02-12 14:33:03 +0100676 free(buffer);
Michal Vasko9f96a052020-03-10 09:41:45 +0100677 lyd_free_meta(ctx->ctx, meta, 1);
Michal Vasko52927e22020-03-16 17:26:14 +0100678 ly_free_attr(ctx->ctx, attr, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100679 lyd_free_tree(cur);
Michal Vasko52927e22020-03-16 17:26:14 +0100680 for (uint32_t u = 0; u < attrs_data.count; ++u) {
Michal Vasko44685da2020-03-17 15:38:06 +0100681 if (((struct attr_data_s *)attrs_data.objs[u])->dynamic) {
682 free(((struct attr_data_s *)attrs_data.objs[u])->value);
Radek Krejci28681fa2019-09-06 13:08:45 +0200683 }
684 }
685 ly_set_erase(&attrs_data, free);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100686 if (ret && *first) {
687 lyd_free_siblings(*first);
688 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100689 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200690 return ret;
691}
692
693LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100694lyd_parse_xml_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200695{
Radek Krejci18a57d92019-07-25 14:01:42 +0200696 LY_ERR ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200697 struct lyd_xml_ctx xmlctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100698 uint32_t i = 0;
699 const struct lys_module *mod;
700 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200701
Michal Vaskoe75ecfd2020-03-06 14:12:28 +0100702 xmlctx.options = options;
Radek Krejcie7b95092019-05-15 11:03:07 +0200703 xmlctx.ctx = ctx;
704 xmlctx.line = 1;
705
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200706 /* init */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100707 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200708
Michal Vaskob1b5c262020-03-05 14:29:47 +0100709 /* parse XML data */
Michal Vasko9f96a052020-03-10 09:41:45 +0100710 ret = lydxml_data_r(&xmlctx, NULL, &data, tree);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100711 LY_CHECK_GOTO(ret, cleanup);
712
Michal Vasko9b368d32020-02-14 13:53:31 +0100713 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100714 next = *tree;
715 while (1) {
716 if (options & LYD_VALOPT_DATA_ONLY) {
717 mod = lyd_data_next_module(&next, &first);
718 } else {
719 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
720 }
721 if (!mod) {
722 break;
723 }
724 if (first == *tree) {
725 /* make sure first2 changes are carried to tree */
726 first2 = tree;
727 } else {
728 first2 = &first;
729 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100730
Michal Vaskob1b5c262020-03-05 14:29:47 +0100731 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
732 ret = lyd_validate_new(first2, NULL, mod);
733 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100734
Michal Vaskob1b5c262020-03-05 14:29:47 +0100735 /* add all top-level defaults for this module */
Michal Vasko52927e22020-03-16 17:26:14 +0100736 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &xmlctx.unres_node_type, &xmlctx.when_check,
737 options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100738 LY_CHECK_GOTO(ret, cleanup);
739
740 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vasko52927e22020-03-16 17:26:14 +0100741 ret = lyd_validate_unres(tree, &xmlctx.when_check, &xmlctx.unres_node_type, &xmlctx.unres_meta_type, LYD_XML,
742 lydxml_resolve_prefix, ctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100743 LY_CHECK_GOTO(ret, cleanup);
744
745 /* perform final validation that assumes the data tree is final */
Michal Vasko5b37a352020-03-06 13:38:33 +0100746 ret = lyd_validate_siblings_r(*first2, NULL, mod, options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100747 LY_CHECK_GOTO(ret, cleanup);
748 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100749 }
750
Michal Vaskocde73ac2019-11-14 16:10:27 +0100751cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100752 /* there should be no unresolved types stored */
Michal Vasko52927e22020-03-16 17:26:14 +0100753 assert(!(options & LYD_OPT_PARSE_ONLY) || (!xmlctx.unres_node_type.count && !xmlctx.unres_meta_type.count
754 && !xmlctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100755
Michal Vasko52927e22020-03-16 17:26:14 +0100756 ly_set_erase(&xmlctx.unres_node_type, NULL);
757 ly_set_erase(&xmlctx.unres_meta_type, NULL);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100758 ly_set_erase(&xmlctx.when_check, NULL);
Michal Vasko9b368d32020-02-14 13:53:31 +0100759 lyxml_context_clear((struct lyxml_context *)&xmlctx);
Radek Krejcie92210c2019-05-17 15:53:35 +0200760 if (ret) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100761 lyd_free_all(*tree);
762 *tree = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200763 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200764 return ret;
765}
Michal Vasko9f96a052020-03-10 09:41:45 +0100766
767static LY_ERR
768lydxml_rpc(struct lyd_xml_ctx *ctx, const char **data, struct ly_attr **attr)
769{
770 const char *prefix, *name;
771 size_t prefix_len, name_len;
772 struct ly_set attrs_data = {0};
773 const struct lyxml_ns *ns;
774
775 LY_CHECK_RET(lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len));
776 if (ly_strncmp("rpc", name, name_len)) {
777 /* not an rpc */
778 return LY_ENOT;
779 }
780
781 if (ctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100782 LY_CHECK_RET(lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data));
Michal Vasko9f96a052020-03-10 09:41:45 +0100783 }
784
785 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
786 if (!ns || strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
787 /* wrong namespace */
788 return LY_ENOT;
789 }
790
791 /* all fine, just parse the rest of the attributes */
792 if (attrs_data.count) {
793 /* TODO parse into generic attribute structure, that will also be returned */
794 //LY_CHECK_RET(lydxml_attributes(ctx, &attrs_data, NULL, meta));
795 }
796
797 return LY_SUCCESS;
798}
799
800static LY_ERR
801lydxml_action(struct lyd_xml_ctx *ctx, const char **data)
802{
803 /* TODO */
804 return LY_ENOT;
805}
806
807LY_ERR
808lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct ly_attr **attr,
809 struct lyd_node **op)
810{
811 LY_ERR ret = LY_SUCCESS;
812 const char *data_p;
813 struct lyd_xml_ctx xmlctx = {0};
814
815 xmlctx.ctx = ctx;
816 xmlctx.line = 1;
817
818 /* init */
819 *tree = NULL;
820 data_p = data;
821
822 /* parse optional "rpc" element */
823 ret = lydxml_rpc(&xmlctx, &data_p, attr);
824 if (ret == LY_ENOT) {
825 /* reset data, nothing parsed */
826 data_p = data;
827 } else if (ret) {
828 goto cleanup;
829 } else {
830 /* successfully parsed */
831 data = data_p;
832
833 /* parse optional "action" element */
834 ret = lydxml_action(&xmlctx, &data_p);
835 if (ret == LY_ENOT) {
836 data_p = data;
837 } else if (ret) {
838 goto cleanup;
839 }
840 }
841
842 /* parse the rest of data tree normally */
843 ret = lydxml_data_r(&xmlctx, NULL, &data_p, tree);
844 LY_CHECK_GOTO(ret, cleanup);
845
846cleanup:
847 if (ret) {
848 lyd_free_all(*tree);
849 *tree = NULL;
850 }
851 return ret;
852}