blob: 34e31612d0d92b2c7f67559688ff606e95348d8a [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
Radek Krejcie7b95092019-05-15 11:03:07 +0200262/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100263 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200264 *
265 * @param[in] ctx XML YANG data parser context.
266 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
267 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
268 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100269 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200270 */
271static LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100272lydxml_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 +0200273{
274 LY_ERR ret = LY_SUCCESS;
275 const char *prefix, *name;
Radek Krejcie7b95092019-05-15 11:03:07 +0200276 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200277 struct ly_set attrs_data = {0};
Radek Krejcie7b95092019-05-15 11:03:07 +0200278 const struct lyxml_ns *ns;
Michal Vasko52927e22020-03-16 17:26:14 +0100279 struct lyd_meta *meta = NULL, *meta2, *prev_meta;
280 struct ly_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200281 const struct lysc_node *snode;
282 struct lys_module *mod;
283 unsigned int parents_count = ctx->elements.count;
Michal Vasko52927e22020-03-16 17:26:14 +0100284 uint32_t prev_opts;
285 struct lyd_node *cur = NULL, *anchor;
286 struct ly_prefix *val_prefs;
Michal Vasko90932a92020-02-12 14:33:03 +0100287 int dynamic = 0;
288 char *buffer = NULL, *value;
289 size_t buffer_size = 0, value_len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200290
Michal Vasko14654712020-02-06 08:35:21 +0100291 while (ctx->status == LYXML_ELEMENT) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200292 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
293 LY_CHECK_GOTO(ret, cleanup);
294 if (!name) {
295 /* closing previous element */
Radek Krejcie7b95092019-05-15 11:03:07 +0200296 if (ctx->elements.count < parents_count) {
297 /* all siblings parsed */
298 break;
299 } else {
300 continue;
301 }
302 }
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100303
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200304 if (ctx->status == LYXML_ATTRIBUTE) {
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100305 /* first parse all attributes so we have all the namespaces available */
Michal Vasko52927e22020-03-16 17:26:14 +0100306 if (lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data) != LY_SUCCESS) {
Michal Vasko90932a92020-02-12 14:33:03 +0100307 ret = LY_EVALID;
308 goto cleanup;
309 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200310 }
311
Radek Krejcie7b95092019-05-15 11:03:07 +0200312 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
313 if (!ns) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200314 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100315 ret = LY_EVALID;
316 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200317 }
318 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
Michal Vasko52927e22020-03-16 17:26:14 +0100319 if (!mod && (ctx->options & LYD_OPT_STRICT)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200320 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 +0100321 ret = LY_EVALID;
322 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200323 }
Michal Vasko52927e22020-03-16 17:26:14 +0100324
325 snode = NULL;
326 if (mod && (!parent || parent->schema)) {
327 /* leave if-feature check for validation */
328 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
329 if (!snode && (ctx->options & LYD_OPT_STRICT)) {
330 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
331 name_len, name, mod->name);
332 ret = LY_EVALID;
333 goto cleanup;
334 }
335 if (snode) {
336 if ((ctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
337 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INSTATE, snode->name);
338 ret = LY_EVALID;
339 goto cleanup;
340 }
341 if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
342 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
343 snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
344 ret = LY_EVALID;
345 goto cleanup;
346 }
347 }
Michal Vasko5b37a352020-03-06 13:38:33 +0100348 }
Radek Krejci710226d2019-07-24 17:24:59 +0200349
Michal Vasko9f96a052020-03-10 09:41:45 +0100350 /* create actual metadata so that prefixes are available in the context */
Michal Vasko8d544252020-03-02 10:19:52 +0100351 if (attrs_data.count) {
Michal Vasko52927e22020-03-16 17:26:14 +0100352 if (snode) {
353 ret = lydxml_metadata((struct lyxml_context *)ctx, &attrs_data, snode, ctx->options & LYD_OPT_STRICT,
354 &ctx->unres_meta_type, &meta);
355 LY_CHECK_GOTO(ret, cleanup);
356 } else if (ctx->options & LYD_OPT_OPAQ) {
357 ret = lydxml_attrs((struct lyxml_context *)ctx, &attrs_data, &attr);
358 LY_CHECK_GOTO(ret, cleanup);
359 } else {
360 /* free attr data */
361 for (uint32_t u = 0; u < attrs_data.count; ++u) {
362 if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
363 free(((struct attr_data_s*)attrs_data.objs[u])->value);
364 }
365 }
366 ly_set_erase(&attrs_data, free);
367 }
Michal Vasko8d544252020-03-02 10:19:52 +0100368 }
369
Michal Vasko52927e22020-03-16 17:26:14 +0100370 if (!snode) {
371 if (ctx->options & LYD_OPT_OPAQ) {
372 /* get the value */
373 LY_ERR r = LY_EINVAL;
374 if (ctx->status == LYXML_ELEM_CONTENT) {
375 r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
376 if (r && (r != LY_EINVAL)) {
377 LOGINT(ctx->ctx);
378 ret = LY_EINT;
379 goto cleanup;
380 }
381 }
382 if (r == LY_EINVAL) {
383 /* empty value */
384 value = "";
385 value_len = 0;
386 dynamic = 0;
387 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200388
Michal Vasko52927e22020-03-16 17:26:14 +0100389 /* get value prefixes */
390 ret = lyxml_get_prefixes((struct lyxml_context *)ctx, value, value_len, &val_prefs);
391 LY_CHECK_GOTO(ret, cleanup);
392
393 /* create node */
394 ret = lyd_create_opaq(ctx->ctx, name, name_len, value, value_len, &dynamic, LYD_XML, val_prefs, prefix,
395 prefix_len, ns->uri, &cur);
396 LY_CHECK_GOTO(ret, cleanup);
397
398 /* process children */
399 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
400 ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
401 LY_CHECK_GOTO(ret, cleanup);
402 }
403 } else {
404 /* skip element */
405 ret = lyxml_skip_element((struct lyxml_context *)ctx, data);
406 LY_CHECK_GOTO(ret, cleanup);
407 break;
408 }
409 } else if (snode->nodetype & LYD_NODE_TERM) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200410 if (ctx->status == LYXML_ELEM_CONTENT) {
411 /* get the value */
Radek Krejci11702142019-07-24 17:46:04 +0200412 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
Michal Vasko14654712020-02-06 08:35:21 +0100413 if (ret != LY_SUCCESS) {
414 if (ret == LY_EINVAL) {
415 /* just indentation of a child element found */
Michal Vasko90932a92020-02-12 14:33:03 +0100416 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside terminal node \"%s\" found.",
417 snode->name);
Michal Vasko14654712020-02-06 08:35:21 +0100418 }
Radek Krejci339e2de2019-05-17 14:28:24 +0200419 goto cleanup;
420 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200421 } else {
422 /* no content - validate empty value */
423 value = "";
424 value_len = 0;
Michal Vasko90932a92020-02-12 14:33:03 +0100425 dynamic = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200426 }
Michal Vasko90932a92020-02-12 14:33:03 +0100427
428 /* create node */
429 ret = lyd_create_term(snode, value, value_len, &dynamic, lydxml_resolve_prefix, ctx, LYD_XML, &cur);
430 /* buffer spent */
431 buffer = NULL;
Radek Krejcie553e6d2019-06-07 15:33:18 +0200432 if (ret == LY_EINCOMPLETE) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100433 if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vasko52927e22020-03-16 17:26:14 +0100434 ly_set_add(&ctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100435 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200436 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200437 goto cleanup;
438 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100439
440 if (parent && (cur->schema->flags & LYS_KEY)) {
441 /* check the key order, the anchor must always be the last child */
Michal Vasko52927e22020-03-16 17:26:14 +0100442 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
443 if ((!anchor && parent->child) || (anchor && anchor->next)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100444 if (ctx->options & LYD_OPT_STRICT) {
445 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
446 cur->schema->name);
447 ret = LY_EVALID;
448 goto cleanup;
449 } else {
450 LOGWRN(ctx->ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
451 }
452 }
453 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200454 } else if (snode->nodetype & LYD_NODE_INNER) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200455 if (ctx->status == LYXML_ELEM_CONTENT) {
456 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 +0200457 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200458 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200459 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200460 goto cleanup;
461 }
462 }
Michal Vasko90932a92020-02-12 14:33:03 +0100463
464 /* create node */
465 ret = lyd_create_inner(snode, &cur);
466 LY_CHECK_GOTO(ret, cleanup);
467
Radek Krejciee4cab22019-07-17 17:07:47 +0200468 /* process children */
Radek Krejcie553e6d2019-06-07 15:33:18 +0200469 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100470 ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
471 LY_CHECK_GOTO(ret, cleanup);
472 }
473
474 if (snode->nodetype == LYS_LIST) {
475 /* check all keys exist */
476 ret = lyd_parse_check_keys(cur);
Radek Krejcie92210c2019-05-17 15:53:35 +0200477 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200478 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100479
480 if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100481 /* new node validation, autodelete CANNOT occur, all nodes are new */
482 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
483 LY_CHECK_GOTO(ret, cleanup);
484
Michal Vasko9b368d32020-02-14 13:53:31 +0100485 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100486 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vasko52927e22020-03-16 17:26:14 +0100487 &ctx->unres_node_type, &ctx->when_check, ctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100488 LY_CHECK_GOTO(ret, cleanup);
489 }
490
491 /* hash now that all keys should be parsed, rehash for key-less list */
492 if (snode->nodetype == LYS_LIST) {
493 lyd_hash(cur);
494 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200495 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko52927e22020-03-16 17:26:14 +0100496 /* just incorrect status */
497 if (ctx->status == LYXML_ELEM_CONTENT) {
498 LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
499 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200500 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200501 ret = LY_EINT;
Radek Krejciee4cab22019-07-17 17:07:47 +0200502 goto cleanup;
503 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200504 }
Michal Vasko90932a92020-02-12 14:33:03 +0100505
Michal Vasko52927e22020-03-16 17:26:14 +0100506 /* parse any data tree with correct options */
507 prev_opts = ctx->options;
508 ctx->options &= ~LYD_OPT_STRICT;
509 ctx->options |= LYD_OPT_OPAQ;
510 anchor = NULL;
511 ret = lydxml_data_r(ctx, NULL, data, &anchor);
512 ctx->options = prev_opts;
513 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100514
515 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100516 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
517 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200518 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200519
Michal Vasko9b368d32020-02-14 13:53:31 +0100520 /* correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100521 if (snode) {
522 if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
523 if (ctx->options & LYD_OPT_TRUSTED) {
524 /* just set it to true */
525 cur->flags |= LYD_WHEN_TRUE;
526 } else {
527 /* remember we need to evaluate this node's when */
528 ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
529 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100530 }
Michal Vasko52927e22020-03-16 17:26:14 +0100531 if (ctx->options & LYD_OPT_TRUSTED) {
532 /* node is valid */
533 cur->flags &= ~LYD_NEW;
534 }
535 prev_meta = NULL;
536 LY_LIST_FOR(meta, meta2) {
537 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
538 && meta2->value.boolean) {
539 /* node is default according to the metadata */
540 cur->flags |= LYD_DEFAULT;
541
542 /* delete the metadata */
543 if (prev_meta) {
544 prev_meta->next = meta2->next;
545 } else {
546 meta = meta->next;
547 }
548 lyd_free_meta(ctx->ctx, meta2, 0);
549 break;
550 }
551
552 prev_meta = meta2;
Michal Vasko8d544252020-03-02 10:19:52 +0100553 }
554 }
555
Michal Vasko52927e22020-03-16 17:26:14 +0100556 /* add metadata/attributes */
557 if (snode) {
558 cur->meta = meta;
559 meta = NULL;
560 } else {
561 assert(!cur->schema);
562 ((struct lyd_node_opaq *)cur)->attr = attr;
563 attr = NULL;
564 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200565
Michal Vasko90932a92020-02-12 14:33:03 +0100566 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100567 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100568
569 cur = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200570 }
571
Michal Vasko90932a92020-02-12 14:33:03 +0100572 /* success */
573 ret = LY_SUCCESS;
574
Radek Krejcie7b95092019-05-15 11:03:07 +0200575cleanup:
Michal Vasko90932a92020-02-12 14:33:03 +0100576 free(buffer);
Michal Vasko9f96a052020-03-10 09:41:45 +0100577 lyd_free_meta(ctx->ctx, meta, 1);
Michal Vasko52927e22020-03-16 17:26:14 +0100578 ly_free_attr(ctx->ctx, attr, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100579 lyd_free_tree(cur);
Michal Vasko52927e22020-03-16 17:26:14 +0100580 for (uint32_t u = 0; u < attrs_data.count; ++u) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200581 if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
582 free(((struct attr_data_s*)attrs_data.objs[u])->value);
583 }
584 }
585 ly_set_erase(&attrs_data, free);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100586 if (ret && *first) {
587 lyd_free_siblings(*first);
588 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100589 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200590 return ret;
591}
592
593LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100594lyd_parse_xml_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200595{
Radek Krejci18a57d92019-07-25 14:01:42 +0200596 LY_ERR ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200597 struct lyd_xml_ctx xmlctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100598 uint32_t i = 0;
599 const struct lys_module *mod;
600 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200601
Michal Vaskoe75ecfd2020-03-06 14:12:28 +0100602 xmlctx.options = options;
Radek Krejcie7b95092019-05-15 11:03:07 +0200603 xmlctx.ctx = ctx;
604 xmlctx.line = 1;
605
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200606 /* init */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100607 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200608
Michal Vaskob1b5c262020-03-05 14:29:47 +0100609 /* parse XML data */
Michal Vasko9f96a052020-03-10 09:41:45 +0100610 ret = lydxml_data_r(&xmlctx, NULL, &data, tree);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100611 LY_CHECK_GOTO(ret, cleanup);
612
Michal Vasko9b368d32020-02-14 13:53:31 +0100613 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100614 next = *tree;
615 while (1) {
616 if (options & LYD_VALOPT_DATA_ONLY) {
617 mod = lyd_data_next_module(&next, &first);
618 } else {
619 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
620 }
621 if (!mod) {
622 break;
623 }
624 if (first == *tree) {
625 /* make sure first2 changes are carried to tree */
626 first2 = tree;
627 } else {
628 first2 = &first;
629 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100630
Michal Vaskob1b5c262020-03-05 14:29:47 +0100631 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
632 ret = lyd_validate_new(first2, NULL, mod);
633 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100634
Michal Vaskob1b5c262020-03-05 14:29:47 +0100635 /* add all top-level defaults for this module */
Michal Vasko52927e22020-03-16 17:26:14 +0100636 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &xmlctx.unres_node_type, &xmlctx.when_check,
637 options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100638 LY_CHECK_GOTO(ret, cleanup);
639
640 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vasko52927e22020-03-16 17:26:14 +0100641 ret = lyd_validate_unres(tree, &xmlctx.when_check, &xmlctx.unres_node_type, &xmlctx.unres_meta_type, LYD_XML,
642 lydxml_resolve_prefix, ctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100643 LY_CHECK_GOTO(ret, cleanup);
644
645 /* perform final validation that assumes the data tree is final */
Michal Vasko5b37a352020-03-06 13:38:33 +0100646 ret = lyd_validate_siblings_r(*first2, NULL, mod, options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100647 LY_CHECK_GOTO(ret, cleanup);
648 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100649 }
650
Michal Vaskocde73ac2019-11-14 16:10:27 +0100651cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100652 /* there should be no unresolved types stored */
Michal Vasko52927e22020-03-16 17:26:14 +0100653 assert(!(options & LYD_OPT_PARSE_ONLY) || (!xmlctx.unres_node_type.count && !xmlctx.unres_meta_type.count
654 && !xmlctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100655
Michal Vasko52927e22020-03-16 17:26:14 +0100656 ly_set_erase(&xmlctx.unres_node_type, NULL);
657 ly_set_erase(&xmlctx.unres_meta_type, NULL);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100658 ly_set_erase(&xmlctx.when_check, NULL);
Michal Vasko9b368d32020-02-14 13:53:31 +0100659 lyxml_context_clear((struct lyxml_context *)&xmlctx);
Radek Krejcie92210c2019-05-17 15:53:35 +0200660 if (ret) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100661 lyd_free_all(*tree);
662 *tree = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200663 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200664 return ret;
665}
Michal Vasko9f96a052020-03-10 09:41:45 +0100666
667static LY_ERR
668lydxml_rpc(struct lyd_xml_ctx *ctx, const char **data, struct ly_attr **attr)
669{
670 const char *prefix, *name;
671 size_t prefix_len, name_len;
672 struct ly_set attrs_data = {0};
673 const struct lyxml_ns *ns;
674
675 LY_CHECK_RET(lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len));
676 if (ly_strncmp("rpc", name, name_len)) {
677 /* not an rpc */
678 return LY_ENOT;
679 }
680
681 if (ctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100682 LY_CHECK_RET(lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data));
Michal Vasko9f96a052020-03-10 09:41:45 +0100683 }
684
685 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
686 if (!ns || strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
687 /* wrong namespace */
688 return LY_ENOT;
689 }
690
691 /* all fine, just parse the rest of the attributes */
692 if (attrs_data.count) {
693 /* TODO parse into generic attribute structure, that will also be returned */
694 //LY_CHECK_RET(lydxml_attributes(ctx, &attrs_data, NULL, meta));
695 }
696
697 return LY_SUCCESS;
698}
699
700static LY_ERR
701lydxml_action(struct lyd_xml_ctx *ctx, const char **data)
702{
703 /* TODO */
704 return LY_ENOT;
705}
706
707LY_ERR
708lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct ly_attr **attr,
709 struct lyd_node **op)
710{
711 LY_ERR ret = LY_SUCCESS;
712 const char *data_p;
713 struct lyd_xml_ctx xmlctx = {0};
714
715 xmlctx.ctx = ctx;
716 xmlctx.line = 1;
717
718 /* init */
719 *tree = NULL;
720 data_p = data;
721
722 /* parse optional "rpc" element */
723 ret = lydxml_rpc(&xmlctx, &data_p, attr);
724 if (ret == LY_ENOT) {
725 /* reset data, nothing parsed */
726 data_p = data;
727 } else if (ret) {
728 goto cleanup;
729 } else {
730 /* successfully parsed */
731 data = data_p;
732
733 /* parse optional "action" element */
734 ret = lydxml_action(&xmlctx, &data_p);
735 if (ret == LY_ENOT) {
736 data_p = data;
737 } else if (ret) {
738 goto cleanup;
739 }
740 }
741
742 /* parse the rest of data tree normally */
743 ret = lydxml_data_r(&xmlctx, NULL, &data_p, tree);
744 LY_CHECK_GOTO(ret, cleanup);
745
746cleanup:
747 if (ret) {
748 lyd_free_all(*tree);
749 *tree = NULL;
750 }
751 return ret;
752}