blob: 5e1f0dc474f93a704a11c6c4c06d451c0be497ca [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko8cc3f662022-03-29 11:25:51 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Radek Krejcie7b95092019-05-15 11:03:07 +02005 * @brief XML data parser for libyang
6 *
Michal Vasko8cc3f662022-03-29 11:25:51 +02007 * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
Radek Krejcie7b95092019-05-15 11:03:07 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Michal Vasko742a5b12022-02-24 16:07:27 +010016#define _GNU_SOURCE
17
Michal Vasko69730152020-10-09 16:30:07 +020018#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22
Radek Krejci535ea9f2020-05-29 16:01:05 +020023#include "common.h"
Michal Vasko742a5b12022-02-24 16:07:27 +010024#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010026#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020027#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020029#include "parser_data.h"
30#include "parser_internal.h"
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010031#include "plugins_exts.h"
Michal Vasko51de7b72022-04-29 09:50:22 +020032#include "plugins_internal.h"
33#include "schema_compile_node.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020034#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010035#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010036#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020037#include "tree_data_internal.h"
38#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010039#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010040#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020041#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020042
Radek Krejci1798aae2020-07-14 13:26:06 +020043void
44lyd_xml_ctx_free(struct lyd_ctx *lydctx)
45{
46 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
47
48 lyd_ctx_free(lydctx);
49 lyxml_ctx_free(ctx->xmlctx);
50 free(ctx);
51}
52
Michal Vasko45791ad2021-06-17 08:45:03 +020053/**
54 * @brief Parse and create XML metadata.
55 *
56 * @param[in] lydctx XML data parser context.
Michal Vaskoddd76592022-01-17 13:34:48 +010057 * @param[in] sparent Schema node of the parent.
Michal Vasko45791ad2021-06-17 08:45:03 +020058 * @param[out] meta List of created metadata instances.
59 * @return LY_ERR value.
60 */
Radek Krejcie7b95092019-05-15 11:03:07 +020061static LY_ERR
Michal Vaskoddd76592022-01-17 13:34:48 +010062lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020063{
aPiecek1c4da362021-04-29 14:26:34 +020064 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020065 const struct lyxml_ns *ns;
66 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010067 const char *name;
68 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020069 LY_ARRAY_COUNT_TYPE u;
70 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020071 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020072
Michal Vaskob36053d2020-03-26 15:49:30 +010073 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020074
Michal Vasko45791ad2021-06-17 08:45:03 +020075 /* check for NETCONF filter unqualified attributes */
Michal Vaskoddd76592022-01-17 13:34:48 +010076 LY_ARRAY_FOR(sparent->exts, u) {
77 if (!strcmp(sparent->exts[u].def->name, "get-filter-element-attributes") &&
78 !strcmp(sparent->exts[u].def->module->name, "ietf-netconf")) {
Michal Vasko45791ad2021-06-17 08:45:03 +020079 filter_attrs = 1;
80 break;
81 }
82 }
83
Michal Vaskob36053d2020-03-26 15:49:30 +010084 while (xmlctx->status == LYXML_ATTRIBUTE) {
85 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +020086 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
87 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
88 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
89 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
90 if (!mod) {
91 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
92 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
93 ret = LY_ENOTFOUND;
94 goto cleanup;
95 }
96 goto create_meta;
97 }
98
Michal Vaskoe0665742021-02-11 11:08:44 +010099 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100100 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100101 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200102 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +0100103 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200104 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100105
Michal Vasko45791ad2021-06-17 08:45:03 +0200106 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100107 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
108 assert(xmlctx->status == LYXML_ATTR_CONTENT);
109 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200110 continue;
111 }
112
113 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200114 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200115 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100116 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100117 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200118 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200119 goto cleanup;
120 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200121
122 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100123 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200124 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100125 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100126 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200127 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100128 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
129 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200130 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100131 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200132 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200133
134 /* skip attr */
135 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
136 assert(xmlctx->status == LYXML_ATTR_CONTENT);
137 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
138 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200139 }
140
Michal Vasko45791ad2021-06-17 08:45:03 +0200141create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200142 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100143 name = xmlctx->name;
144 name_len = xmlctx->name_len;
145 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
146 assert(xmlctx->status == LYXML_ATTR_CONTENT);
147
148 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200149 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskoddd76592022-01-17 13:34:48 +0100150 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, sparent);
Radek Krejci1798aae2020-07-14 13:26:06 +0200151 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100152
153 /* next attribute */
154 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200155 }
Michal Vasko52927e22020-03-16 17:26:14 +0100156
Radek Krejcie7b95092019-05-15 11:03:07 +0200157cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100158 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200159 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100160 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200161 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200162 return ret;
163}
164
Michal Vasko52927e22020-03-16 17:26:14 +0100165static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200166lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100167{
168 LY_ERR ret = LY_SUCCESS;
169 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100170 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200171 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200172 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 const char *name, *prefix;
174 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100175
176 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100177 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100178
Michal Vaskob36053d2020-03-26 15:49:30 +0100179 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100180 if (*attr) {
181 attr2 = *attr;
182 } else {
183 attr2 = NULL;
184 }
185
Michal Vaskob36053d2020-03-26 15:49:30 +0100186 /* remember attr prefix, name, and get its content */
187 prefix = xmlctx->prefix;
188 prefix_len = xmlctx->prefix_len;
189 name = xmlctx->name;
190 name_len = xmlctx->name_len;
191 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
192 assert(xmlctx->status == LYXML_ATTR_CONTENT);
193
Michal Vaskoe137fc42021-07-22 11:53:13 +0200194 /* handle special "xml" attribute prefix */
195 if ((prefix_len == 3) && !strncmp(prefix, "xml", 3)) {
196 name = prefix;
197 name_len += 1 + prefix_len;
198 prefix = NULL;
199 prefix_len = 0;
200 }
201
202 /* find namespace of the attribute, if any */
203 ns = NULL;
204 if (prefix_len) {
205 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
206 if (!ns) {
207 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
208 ret = LY_EVALID;
209 goto cleanup;
210 }
211 }
212
Michal Vasko52927e22020-03-16 17:26:14 +0100213 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100214 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200215 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100216 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100217
218 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100219 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
Michal Vaskoe5e49e92022-02-01 13:15:08 +0100220 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data,
221 LYD_HINT_DATA);
Michal Vasko52927e22020-03-16 17:26:14 +0100222 LY_CHECK_GOTO(ret, cleanup);
223
224 if (!*attr) {
225 *attr = attr2;
226 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100227
228 /* next attribute */
229 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100230 }
231
232cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100233 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200234 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100235 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100236 }
Michal Vasko52927e22020-03-16 17:26:14 +0100237 return ret;
238}
239
Michal Vasko44685da2020-03-17 15:38:06 +0100240static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100241lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100242{
Michal Vaskob36053d2020-03-26 15:49:30 +0100243 LY_ERR ret = LY_SUCCESS, r;
244 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100245 struct ly_set key_set = {0};
246 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100247 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100248
249 assert(list && (list->nodetype == LYS_LIST));
250
251 /* get all keys into a set (keys do not have if-features or anything) */
252 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100253 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200254 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200255 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100256 }
257
Michal Vasko12d809c2021-03-03 16:34:32 +0100258 /* remember parent count */
259 parents_count = xmlctx->elements.count;
260
Michal Vaskob36053d2020-03-26 15:49:30 +0100261 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100262 /* find key definition */
263 for (i = 0; i < key_set.count; ++i) {
264 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100265 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100266 break;
267 }
268 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100269 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100270
271 /* skip attributes */
272 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100273 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
274 assert(xmlctx->status == LYXML_ATTR_CONTENT);
275 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100276 }
277
Michal Vaskob36053d2020-03-26 15:49:30 +0100278 assert(xmlctx->status == LYXML_ELEM_CONTENT);
279 if (i < key_set.count) {
280 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200281 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100282 if (!r) {
283 /* key with a valid value, remove from the set */
284 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100285 }
286 }
287
Michal Vaskob36053d2020-03-26 15:49:30 +0100288 /* parser next */
289 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100290
Michal Vaskob36053d2020-03-26 15:49:30 +0100291 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100292 while (xmlctx->status == LYXML_ELEMENT) {
293 while (parents_count < xmlctx->elements.count) {
294 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
295 }
296 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100297 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
298 }
299
300 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
301 assert(xmlctx->status == LYXML_ELEM_CLOSE);
302 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
303 if (next != LYXML_ELEM_CLOSE) {
304 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
305 }
Michal Vasko44685da2020-03-17 15:38:06 +0100306 }
307
308 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100309 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100310 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100311 }
312
313cleanup:
314 ly_set_erase(&key_set, NULL);
315 return ret;
316}
317
Michal Vasko5c24ed12021-06-09 09:27:32 +0200318/**
319 * @brief Skip an element with all its descendants.
320 *
321 * @param[in] xmlctx XML parser context.
322 * @return LY_ERR value.
323 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100324static LY_ERR
325lydxml_data_skip(struct lyxml_ctx *xmlctx)
326{
327 uint32_t parents_count;
328
329 /* remember current number of parents */
330 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200331 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100332
333 /* skip after the content */
334 while (xmlctx->status != LYXML_ELEM_CONTENT) {
335 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
336 }
337 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
338
339 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200340 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100341 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
342 }
343
344 /* close element */
345 assert(xmlctx->status == LYXML_ELEM_CLOSE);
346 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
347
348 return LY_SUCCESS;
349}
350
Michal Vasko5c24ed12021-06-09 09:27:32 +0200351/**
352 * @brief Check that the current element can be parsed as a data node.
353 *
354 * @param[in] lydctx XML data parser context.
355 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
356 * @return LY_ERR value.
357 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100358static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200359lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100360{
361 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200362 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100363
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100364 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
365 /* only checks specific to opaque nodes */
366 return LY_SUCCESS;
367 }
368
Michal Vasko13854662021-06-09 09:27:50 +0200369 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
370 /* nothing to check */
371 return LY_SUCCESS;
372 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100373
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200374 assert(xmlctx->elements.count);
375
Michal Vasko13854662021-06-09 09:27:50 +0200376 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200377 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100378
Michal Vasko13854662021-06-09 09:27:50 +0200379 /* skip attributes */
380 while (xmlctx->status == LYXML_ATTRIBUTE) {
381 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
382 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
383 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100384
Michal Vasko13854662021-06-09 09:27:50 +0200385 if ((*snode)->nodetype & LYD_NODE_TERM) {
386 /* value may not be valid in which case we parse it as an opaque node */
387 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200388 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
389 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200390 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100391 }
Michal Vasko13854662021-06-09 09:27:50 +0200392 } else if ((*snode)->nodetype == LYS_LIST) {
393 /* skip content */
394 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100395
Michal Vasko13854662021-06-09 09:27:50 +0200396 if (lydxml_check_list(xmlctx, *snode)) {
397 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200398 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200399 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100400 }
Michal Vasko13854662021-06-09 09:27:50 +0200401 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100402 /* if there is a non-WS value, it cannot be parsed as an inner node */
403 assert(xmlctx->status == LYXML_ELEM_CONTENT);
404 if (!xmlctx->ws_only) {
405 *snode = NULL;
406 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100407 }
408
Michal Vasko13854662021-06-09 09:27:50 +0200409restore:
410 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200411 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100412 return ret;
413}
414
Radek Krejcie7b95092019-05-15 11:03:07 +0200415/**
Michal Vaskocea58712022-04-01 14:37:08 +0200416 * @brief Get sensible data hints for an opaque node.
417 *
418 * @param[in] name Node name.
419 * @param[in] name_len Length of @p name.
420 * @param[in] value Node value.
421 * @param[in] value_len Length of @p value.
422 * @param[in] first Node first sibling.
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100423 * @param[in] ns Node module namespace, NULL for no namespace.
Michal Vaskocea58712022-04-01 14:37:08 +0200424 * @param[out] hints Data hints to use.
425 * @param[out] anchor Anchor to insert after in case of a list.
426 */
427static void
428lydxml_get_hints_opaq(const char *name, size_t name_len, const char *value, size_t value_len, struct lyd_node *first,
429 const char *ns, uint32_t *hints, struct lyd_node **anchor)
430{
431 struct lyd_node_opaq *opaq;
432 char *ptr;
433 long num;
434
435 *hints = 0;
436 *anchor = NULL;
437
438 if (!value_len) {
439 /* no value */
440 *hints |= LYD_VALHINT_EMPTY;
441 } else if (!strncmp(value, "true", value_len) || !strncmp(value, "false", value_len)) {
442 /* boolean value */
443 *hints |= LYD_VALHINT_BOOLEAN;
444 } else {
445 num = strtol(value, &ptr, 10);
446 if ((unsigned)(ptr - value) == value_len) {
447 /* number value */
448 *hints |= LYD_VALHINT_DECNUM;
449 if ((num < INT32_MIN) || (num > UINT32_MAX)) {
450 /* large number */
451 *hints |= LYD_VALHINT_NUM64;
452 }
453 } else {
454 /* string value */
455 *hints |= LYD_VALHINT_STRING;
456 }
457 }
458
459 if (!first) {
460 return;
461 }
462
463 /* search backwards to find the last instance */
464 do {
465 first = first->prev;
466 if (first->schema) {
467 continue;
468 }
469
470 opaq = (struct lyd_node_opaq *)first;
471 assert(opaq->format == LY_VALUE_XML);
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100472 if (!ly_strncmp(opaq->name.name, name, name_len) &&
473 ((ns && !strcmp(opaq->name.module_ns, ns)) || (!ns && !opaq->name.module_ns))) {
Michal Vaskocea58712022-04-01 14:37:08 +0200474 if (opaq->value && opaq->value[0]) {
475 /* leaf-list nodes */
476 opaq->hints |= LYD_NODEHINT_LEAFLIST;
477 *hints |= LYD_NODEHINT_LEAFLIST;
478 } else {
479 /* list nodes */
480 opaq->hints |= LYD_NODEHINT_LIST;
481 *hints |= LYD_NODEHINT_LIST;
482 }
483 *anchor = first;
484 break;
485 }
486 } while (first->prev->next);
487}
488
489/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200490 * @brief Get schema node for the current element.
Michal Vaskoddd76592022-01-17 13:34:48 +0100491 *
492 * @param[in] lydctx XML data parser context.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200493 * @param[in] parent Parsed parent data node, if any.
494 * @param[in] prefix Element prefix, if any.
495 * @param[in] prefix_len Length of @p prefix.
496 * @param[in] name Element name.
497 * @param[in] name_len Length of @p name.
498 * @param[out] snode Found schema node, NULL if no suitable was found.
499 * @param[out] ext Extension instance that provided @p snode, if any.
Michal Vaskoddd76592022-01-17 13:34:48 +0100500 * @return LY_SUCCESS on success;
Michal Vaskoddd76592022-01-17 13:34:48 +0100501 * @return LY_ERR on error.
502 */
503static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200504lydxml_subtree_snode(struct lyd_xml_ctx *lydctx, const struct lyd_node *parent, const char *prefix, size_t prefix_len,
505 const char *name, size_t name_len, const struct lysc_node **snode, struct lysc_ext_instance **ext)
Michal Vaskoddd76592022-01-17 13:34:48 +0100506{
507 LY_ERR r;
Michal Vaskob36053d2020-03-26 15:49:30 +0100508 struct lyxml_ctx *xmlctx;
509 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200510 const struct lyxml_ns *ns;
Radek Krejcie7b95092019-05-15 11:03:07 +0200511 struct lys_module *mod;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200512 uint32_t getnext_opts;
Michal Vaskoe0665742021-02-11 11:08:44 +0100513
Michal Vaskob36053d2020-03-26 15:49:30 +0100514 xmlctx = lydctx->xmlctx;
515 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100516 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100517
Michal Vasko8cc3f662022-03-29 11:25:51 +0200518 *snode = NULL;
519 *ext = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100520
Michal Vasko8cc3f662022-03-29 11:25:51 +0200521 /* get current namespace */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200522 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200523 if (!ns) {
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100524 if (lydctx->int_opts & LYD_INTOPT_ANY) {
525 goto unknown_module;
526 }
527
528 if (prefix_len) {
529 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
530 } else {
531 LOGVAL(ctx, LYVE_REFERENCE, "Missing XML namespace.");
532 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200533 return LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200534 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200535
536 /* get the element module, use parent context if possible because of extensions */
537 mod = ly_ctx_get_module_implemented_ns(parent ? LYD_CTX(parent) : ctx, ns->uri);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200538 if (!mod) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100539 /* check for extension data */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200540 r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name, name_len,
541 snode, ext);
542 if (r != LY_ENOT) {
543 /* success or error */
Michal Vaskoddd76592022-01-17 13:34:48 +0100544 return r;
Michal Vaskoddd76592022-01-17 13:34:48 +0100545 }
546
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100547unknown_module:
Michal Vaskoe0665742021-02-11 11:08:44 +0100548 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100549 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200550 return LY_EVALID;
Radek Krejcie7b95092019-05-15 11:03:07 +0200551 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200552 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200553 }
554
Michal Vaskoa5da3292020-08-12 13:10:50 +0200555 /* get the schema node */
Michal Vasko81008a52021-07-21 16:06:12 +0200556 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100557 if (!parent && lydctx->ext) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200558 *snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100559 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200560 *snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100561 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200562 if (!*snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100563 /* check for extension data */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200564 r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name,
565 name_len, snode, ext);
566 if (r != LY_ENOT) {
567 /* success or error */
Michal Vaskoddd76592022-01-17 13:34:48 +0100568 return r;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100569 }
Michal Vaskoddd76592022-01-17 13:34:48 +0100570
571 /* unknown data node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100572 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
573 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100574 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100575 (int)name_len, name, LYD_NAME(parent));
Radek Krejcif16e2542021-02-17 15:39:23 +0100576 } else if (lydctx->ext) {
577 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100578 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
579 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100580 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100581 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
582 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100583 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100584 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100585 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
586 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100587 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200588 return LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200589 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200590 return LY_SUCCESS;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200591 } else {
592 /* check that schema node is valid and can be used */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200593 LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode));
594 LY_CHECK_RET(lydxml_data_check_opaq(lydctx, snode));
Michal Vaskoa5da3292020-08-12 13:10:50 +0200595 }
596 }
597
Michal Vasko8cc3f662022-03-29 11:25:51 +0200598 return LY_SUCCESS;
599}
600
601/**
602 * @brief Parse XML subtree.
603 *
604 * @param[in] lydctx XML YANG data parser context.
605 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
606 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
607 * this may point to a previously existing node.
608 * @param[in,out] parsed Optional set to add all the parsed siblings into.
609 * @return LY_ERR value.
610 */
611static LY_ERR
612lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
613{
614 LY_ERR ret = LY_SUCCESS;
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100615 const char *prefix, *name, *ns_uri;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200616 size_t prefix_len, name_len;
617 struct lyxml_ctx *xmlctx;
618 const struct ly_ctx *ctx;
619 const struct lyxml_ns *ns;
620 struct lyd_meta *meta = NULL;
621 struct lyd_attr *attr = NULL;
622 const struct lysc_node *snode;
623 struct lysc_ext_instance *ext;
Michal Vaskocea58712022-04-01 14:37:08 +0200624 uint32_t prev_parse_opts, orig_parse_opts, prev_int_opts, hints;
625 struct lyd_node *node = NULL, *anchor, *insert_anchor = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200626 void *val_prefix_data = NULL;
627 LY_VALUE_FORMAT format;
628 ly_bool parse_subtree;
629 char *val;
630
631 assert(parent || first_p);
632
633 xmlctx = lydctx->xmlctx;
634 ctx = xmlctx->ctx;
635
636 parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
637 /* all descendants should be parsed */
638 lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
639 orig_parse_opts = lydctx->parse_opts;
640
641 assert(xmlctx->status == LYXML_ELEMENT);
642
643 /* remember element prefix and name */
644 prefix = xmlctx->prefix;
645 prefix_len = xmlctx->prefix_len;
646 name = xmlctx->name;
647 name_len = xmlctx->name_len;
648
649 /* parser next */
650 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
651
652 /* get the schema node */
653 LY_CHECK_GOTO(ret = lydxml_subtree_snode(lydctx, parent, prefix, prefix_len, name, name_len, &snode, &ext), error);
654
655 if (!snode && !(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
656 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
657
658 /* skip element with children */
659 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
660 return LY_SUCCESS;
661 }
662
Michal Vaskoa5da3292020-08-12 13:10:50 +0200663 /* create metadata/attributes */
664 if (xmlctx->status == LYXML_ATTRIBUTE) {
665 if (snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100666 ret = lydxml_metadata(lydctx, snode, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200667 LY_CHECK_GOTO(ret, error);
668 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100669 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200670 ret = lydxml_attrs(xmlctx, &attr);
671 LY_CHECK_GOTO(ret, error);
672 }
673 }
674
675 assert(xmlctx->status == LYXML_ELEM_CONTENT);
676 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100677 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200678
679 if (xmlctx->ws_only) {
680 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100681 if (xmlctx->dynamic) {
Michal Vaskocea58712022-04-01 14:37:08 +0200682 free((char *)xmlctx->value);
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100683 }
684 xmlctx->dynamic = 0;
685 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200686 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200687 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200688 } else {
689 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200690 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100691 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200692 LY_CHECK_GOTO(ret, error);
693 }
694
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200695 /* get NS again, it may have been backed up and restored */
696 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100697 ns_uri = ns ? ns->uri : NULL;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200698
Michal Vaskocea58712022-04-01 14:37:08 +0200699 /* get best-effort node hints */
700 lydxml_get_hints_opaq(name, name_len, xmlctx->value, xmlctx->value_len, parent ? lyd_child(parent) : *first_p,
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100701 ns_uri, &hints, &insert_anchor);
Michal Vaskocea58712022-04-01 14:37:08 +0200702
Michal Vaskoa5da3292020-08-12 13:10:50 +0200703 /* create node */
Michal Vaskoce2e07c2022-12-01 11:08:52 +0100704 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns_uri, ns_uri ? strlen(ns_uri) : 0,
705 xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, hints, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200706 LY_CHECK_GOTO(ret, error);
707
708 /* parser next */
709 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
710
711 /* process children */
712 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100713 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200714 LY_CHECK_GOTO(ret, error);
715 }
716 } else if (snode->nodetype & LYD_NODE_TERM) {
717 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200718 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Radek Krejci8df109d2021-04-23 12:19:08 +0200719 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100720 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200721
722 if (parent && (node->schema->flags & LYS_KEY)) {
723 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100724 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vasko441e0fa2022-03-03 13:45:00 +0100725 if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100726 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100727 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200728 ret = LY_EVALID;
729 goto error;
730 } else {
731 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
732 }
733 }
734 }
735
736 /* parser next */
737 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
738
739 /* no children expected */
740 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100741 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100742 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200743 ret = LY_EVALID;
744 goto error;
745 }
746 } else if (snode->nodetype & LYD_NODE_INNER) {
747 if (!xmlctx->ws_only) {
748 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100749 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100750 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200751 ret = LY_EVALID;
752 goto error;
753 }
754
755 /* create node */
756 ret = lyd_create_inner(snode, &node);
757 LY_CHECK_GOTO(ret, error);
758
Radek Krejciddace2c2021-01-08 11:30:56 +0100759 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100760
Michal Vaskoa5da3292020-08-12 13:10:50 +0200761 /* parser next */
762 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
763
Michal Vasko8cc3f662022-03-29 11:25:51 +0200764 prev_parse_opts = lydctx->parse_opts;
765 if (ext) {
766 /* only parse these extension data and validate afterwards */
767 lydctx->parse_opts |= LYD_PARSE_ONLY;
768 }
769
Michal Vaskoa5da3292020-08-12 13:10:50 +0200770 /* process children */
771 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100772 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200773 LY_CHECK_GOTO(ret, error);
774 }
775
Michal Vasko8cc3f662022-03-29 11:25:51 +0200776 /* restore options */
777 lydctx->parse_opts = prev_parse_opts;
778
Michal Vaskoa5da3292020-08-12 13:10:50 +0200779 if (snode->nodetype == LYS_LIST) {
780 /* check all keys exist */
781 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
782 }
783
Michal Vaskoe0665742021-02-11 11:08:44 +0100784 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200785 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100786 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200787 LY_CHECK_GOTO(ret, error);
788
789 /* add any missing default children */
Michal Vaskoddd76592022-01-17 13:34:48 +0100790 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
Michal Vaskofcbd78f2022-08-26 08:34:15 +0200791 &lydctx->ext_node, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200792 LY_CHECK_GOTO(ret, error);
793 }
794
795 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
796 /* rememeber the RPC/action/notification */
797 lydctx->op_node = node;
798 }
799 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100800 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
801 /* value in anydata node, we expect a tree */
802 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100803 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200804 ret = LY_EVALID;
805 goto error;
806 }
807
Michal Vasko27c4dce2021-03-04 15:50:50 +0100808 if (!xmlctx->ws_only) {
809 /* use an arbitrary text value for anyxml */
Michal Vasko742a5b12022-02-24 16:07:27 +0100810 val = strndup(xmlctx->value, xmlctx->value_len);
811 LY_CHECK_ERR_GOTO(!val, LOGMEM(xmlctx->ctx); ret = LY_EMEM, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200812
Michal Vasko27c4dce2021-03-04 15:50:50 +0100813 /* parser next */
Michal Vaskoa04107f2022-03-29 12:09:50 +0200814 LY_CHECK_ERR_GOTO(ret = lyxml_ctx_next(xmlctx), free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100815
816 /* create node */
817 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
Michal Vasko742a5b12022-02-24 16:07:27 +0100818 LY_CHECK_ERR_GOTO(ret, free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100819 } else {
820 /* parser next */
821 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
822
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200823 /* update options so that generic data can be parsed */
824 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100825 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200826 lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200827 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200828 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200829
830 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100831 anchor = NULL;
832 while (xmlctx->status == LYXML_ELEMENT) {
833 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200834 if (ret) {
Michal Vaskocc53c582022-04-01 12:07:44 +0200835 lyd_free_siblings(anchor);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200836 break;
837 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100838 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200839
840 /* restore options */
841 lydctx->parse_opts = prev_parse_opts;
842 lydctx->int_opts = prev_int_opts;
843
844 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100845
846 /* create node */
847 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
848 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200849 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200850 }
851 assert(node);
852
Michal Vaskoa5da3292020-08-12 13:10:50 +0200853 if (snode) {
Michal Vasko135719f2022-08-25 12:18:17 +0200854 /* add/correct flags */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200855 LY_CHECK_GOTO(ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext), error);
Michal Vasko135719f2022-08-25 12:18:17 +0200856
Michal Vaskoeba23112022-08-26 08:35:41 +0200857 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
858 /* store for ext instance node validation, if needed */
859 LY_CHECK_GOTO(ret = lyd_validate_node_ext(node, &lydctx->ext_node), error);
860 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200861 }
862
863 /* parser next */
864 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskoddd76592022-01-17 13:34:48 +0100865 if (!parse_subtree) {
866 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
867 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200868
869 /* add metadata/attributes */
870 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100871 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200872 } else {
873 lyd_insert_attr(node, attr);
874 }
875
876 /* insert, keep first pointer correct */
Michal Vaskocea58712022-04-01 14:37:08 +0200877 if (insert_anchor) {
878 lyd_insert_after(insert_anchor, node);
879 } else if (ext) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200880 LY_CHECK_GOTO(ret = lyplg_ext_insert(parent, node), error);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200881 } else {
882 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
883 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200884 while (!parent && (*first_p)->prev->next) {
885 *first_p = (*first_p)->prev;
886 }
887
Michal Vaskoe0665742021-02-11 11:08:44 +0100888 /* rememeber a successfully parsed node */
889 if (parsed) {
890 ly_set_add(parsed, node, 1, NULL);
891 }
892
Michal Vasko8cc3f662022-03-29 11:25:51 +0200893 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100894 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200895 return LY_SUCCESS;
896
897error:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200898 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100899 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200900 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200901 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200902 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200903 return ret;
904}
905
Michal Vaskoe0665742021-02-11 11:08:44 +0100906/**
907 * @brief Parse a specific XML element into an opaque node.
908 *
909 * @param[in] xmlctx XML parser context.
910 * @param[in] name Name of the element.
911 * @param[in] uri URI of the element.
912 * @param[in] value Whether a value is expected in the element.
913 * @param[out] evnp Parsed envelope (opaque node).
914 * @return LY_SUCCESS on success.
915 * @return LY_ENOT if the specified element did not match.
916 * @return LY_ERR value on error.
917 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100918static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100919lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, ly_bool value, struct lyd_node **envp)
Michal Vasko1bf09392020-03-27 12:38:10 +0100920{
Michal Vaskoe0665742021-02-11 11:08:44 +0100921 LY_ERR rc = LY_SUCCESS;
922 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200923 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100924 const char *prefix;
925 size_t prefix_len;
926
Michal Vasko1bf09392020-03-27 12:38:10 +0100927 assert(xmlctx->status == LYXML_ELEMENT);
928 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
929 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100930 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100931 }
932
933 prefix = xmlctx->prefix;
934 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200935 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100936 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100937 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100938 return LY_EVALID;
939 } else if (strcmp(ns->uri, uri)) {
940 /* different namespace */
941 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100942 }
943
944 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
945
946 /* create attributes */
947 if (xmlctx->status == LYXML_ATTRIBUTE) {
948 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
949 }
950
Michal Vaskoe0665742021-02-11 11:08:44 +0100951 assert(xmlctx->status == LYXML_ELEM_CONTENT);
952 if (!value && !xmlctx->ws_only) {
953 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100954 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100955 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100956 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100957 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100958
959 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100960 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200961 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100962 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100963
964 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100965 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100966 attr = NULL;
967
Michal Vaskoe0665742021-02-11 11:08:44 +0100968 /* parser next element */
969 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100970
Michal Vaskoe0665742021-02-11 11:08:44 +0100971cleanup:
972 lyd_free_attr_siblings(xmlctx->ctx, attr);
973 if (rc) {
974 lyd_free_tree(*envp);
975 *envp = NULL;
976 }
977 return rc;
978}
979
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100980LY_ERR
981lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
982 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
983 struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
984{
985 LY_ERR rc = LY_SUCCESS;
986 struct lyd_xml_ctx *lydctx;
987 ly_bool parsed_data_nodes = 0;
988 enum LYXML_PARSER_STATUS status;
989
990 assert(ctx && in && lydctx_p);
991 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
992 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
993
994 /* init context */
995 lydctx = calloc(1, sizeof *lydctx);
996 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
997 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
998 lydctx->parse_opts = parse_opts;
999 lydctx->val_opts = val_opts;
1000 lydctx->int_opts = int_opts;
1001 lydctx->free = lyd_xml_ctx_free;
1002 lydctx->ext = ext;
1003
1004 /* find the operation node if it exists already */
1005 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1006
1007 /* parse XML data */
1008 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1009 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1010 parsed_data_nodes = 1;
1011
1012 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1013 break;
1014 }
1015 }
1016
1017 /* check final state */
1018 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1019 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1020 rc = LY_EVALID;
1021 goto cleanup;
1022 }
1023 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1024 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1025 rc = LY_EVALID;
1026 goto cleanup;
1027 }
1028
1029 if (!parsed_data_nodes) {
1030 /* no data nodes were parsed */
1031 lydctx->op_node = NULL;
1032 }
1033
1034 if (parse_opts & LYD_PARSE_SUBTREE) {
1035 /* check for a sibling element */
1036 assert(subtree_sibling);
1037 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1038 *subtree_sibling = 1;
1039 } else {
1040 *subtree_sibling = 0;
1041 }
1042 }
1043
1044cleanup:
1045 /* there should be no unres stored if validation should be skipped */
1046 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1047 !lydctx->node_when.count));
1048
1049 if (rc) {
1050 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1051 } else {
1052 *lydctx_p = (struct lyd_ctx *)lydctx;
1053
1054 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1055 lyxml_ctx_free(lydctx->xmlctx);
1056 lydctx->xmlctx = NULL;
1057 }
1058 return rc;
1059}
1060
Michal Vaskoe0665742021-02-11 11:08:44 +01001061/**
1062 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
1063 *
1064 * @param[in] xmlctx XML parser context.
1065 * @param[out] evnp Parsed envelope(s) (opaque node).
1066 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1067 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1068 * @return LY_SUCCESS on success.
1069 * @return LY_ERR value on error.
1070 */
1071static LY_ERR
1072lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1073{
1074 LY_ERR rc = LY_SUCCESS, r;
1075 struct lyd_node *child;
1076
1077 assert(envp && !*envp);
1078
Michal Vasko50375272022-04-26 12:07:46 +02001079 if (xmlctx->status != LYXML_ELEMENT) {
1080 /* nothing to parse */
1081 assert(xmlctx->status == LYXML_END);
1082 goto cleanup;
1083 }
1084
Michal Vaskoe0665742021-02-11 11:08:44 +01001085 /* parse "rpc" */
1086 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001087 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1088
1089 /* parse "action", if any */
1090 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
1091 if (r == LY_SUCCESS) {
1092 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001093 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +01001094
1095 /* NETCONF action */
1096 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
1097 *close_elem = 2;
1098 } else if (r == LY_ENOT) {
1099 /* NETCONF RPC */
1100 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
1101 *close_elem = 1;
1102 } else {
1103 rc = r;
1104 goto cleanup;
1105 }
1106
1107cleanup:
1108 if (rc) {
1109 lyd_free_tree(*envp);
1110 *envp = NULL;
1111 }
1112 return rc;
1113}
1114
1115/**
Michal Vasko51de7b72022-04-29 09:50:22 +02001116 * @brief Validate eventTime date-and-time value.
1117 *
1118 * @param[in] node Opaque eventTime node.
1119 * @return LY_SUCCESS on success.
1120 * @return LY_ERR value on error.
1121 */
1122static LY_ERR
1123lydxml_env_netconf_eventtime_validate(const struct lyd_node *node)
1124{
1125 LY_ERR rc = LY_SUCCESS;
1126 struct ly_ctx *ctx = (struct ly_ctx *)LYD_CTX(node);
Michal Vaskoc636ea42022-09-16 10:20:31 +02001127 struct lysc_ctx cctx;
Michal Vasko51de7b72022-04-29 09:50:22 +02001128 const struct lys_module *mod;
1129 LY_ARRAY_COUNT_TYPE u;
1130 struct ly_err_item *err = NULL;
Michal Vaskoab36a7e2022-04-29 10:25:56 +02001131 struct lysp_type *type_p = NULL;
Michal Vasko51de7b72022-04-29 09:50:22 +02001132 struct lysc_pattern **patterns = NULL;
1133 const char *value;
1134
Michal Vaskoc636ea42022-09-16 10:20:31 +02001135 LYSC_CTX_INIT_CTX(cctx, ctx);
1136
Michal Vasko51de7b72022-04-29 09:50:22 +02001137 /* get date-and-time parsed type */
1138 mod = ly_ctx_get_module_latest(ctx, "ietf-yang-types");
Michal Vaskoab36a7e2022-04-29 10:25:56 +02001139 assert(mod);
Michal Vasko51de7b72022-04-29 09:50:22 +02001140 LY_ARRAY_FOR(mod->parsed->typedefs, u) {
1141 if (!strcmp(mod->parsed->typedefs[u].name, "date-and-time")) {
1142 type_p = &mod->parsed->typedefs[u].type;
1143 break;
1144 }
1145 }
1146 assert(type_p);
1147
1148 /* compile patterns */
1149 assert(type_p->patterns);
1150 LY_CHECK_GOTO(rc = lys_compile_type_patterns(&cctx, type_p->patterns, NULL, &patterns), cleanup);
1151
1152 /* validate */
1153 value = lyd_get_value(node);
1154 rc = lyplg_type_validate_patterns(patterns, value, strlen(value), &err);
1155
1156cleanup:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001157 FREE_ARRAY(&cctx.free_ctx, patterns, lysc_pattern_free);
Michal Vasko51de7b72022-04-29 09:50:22 +02001158 if (rc && err) {
1159 LOGVAL_ERRITEM(ctx, err);
1160 ly_err_free(err);
1161 LOGVAL(ctx, LYVE_DATA, "Invalid \"eventTime\" in the notification.");
1162 }
1163 return rc;
1164}
1165
1166/**
Michal Vaskoe0665742021-02-11 11:08:44 +01001167 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
1168 *
1169 * @param[in] xmlctx XML parser context.
1170 * @param[out] evnp Parsed envelope(s) (opaque node).
1171 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1172 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1173 * @return LY_SUCCESS on success.
1174 * @return LY_ERR value on error.
1175 */
1176static LY_ERR
1177lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1178{
1179 LY_ERR rc = LY_SUCCESS, r;
1180 struct lyd_node *child;
1181
1182 assert(envp && !*envp);
1183
Michal Vasko50375272022-04-26 12:07:46 +02001184 if (xmlctx->status != LYXML_ELEMENT) {
1185 /* nothing to parse */
1186 assert(xmlctx->status == LYXML_END);
1187 goto cleanup;
1188 }
1189
Michal Vaskoe0665742021-02-11 11:08:44 +01001190 /* parse "notification" */
1191 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001192 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1193
1194 /* parse "eventTime" */
1195 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
1196 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +01001197 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
1198 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001199 r = LY_EVALID;
1200 }
1201 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1202
1203 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001204 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +01001205
1206 /* validate value */
Michal Vasko51de7b72022-04-29 09:50:22 +02001207 r = lydxml_env_netconf_eventtime_validate(child);
1208 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001209
1210 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +01001211 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1212 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +01001213 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001214 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001215 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001216 goto cleanup;
1217 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001218 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1219
1220 /* NETCONF notification */
1221 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
1222 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001223
1224cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001225 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +01001226 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001227 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001228 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001229 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001230}
Michal Vasko79135ae2020-12-16 10:08:35 +01001231
Michal Vaskoe0665742021-02-11 11:08:44 +01001232/**
1233 * @brief Parse an XML element as an opaque node subtree.
1234 *
1235 * @param[in] xmlctx XML parser context.
1236 * @param[in] parent Parent to append nodes to.
1237 * @return LY_ERR value.
1238 */
1239static LY_ERR
1240lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001241{
Michal Vaskoe0665742021-02-11 11:08:44 +01001242 LY_ERR rc = LY_SUCCESS;
1243 const struct lyxml_ns *ns;
1244 struct lyd_attr *attr = NULL;
1245 struct lyd_node *child = NULL;
1246 const char *name, *prefix;
1247 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001248
Michal Vaskoe0665742021-02-11 11:08:44 +01001249 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001250
Michal Vaskoe0665742021-02-11 11:08:44 +01001251 name = xmlctx->name;
1252 name_len = xmlctx->name_len;
1253 prefix = xmlctx->prefix;
1254 prefix_len = xmlctx->prefix_len;
1255 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1256 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001257 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001258 return LY_EVALID;
1259 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001260
Michal Vaskoe0665742021-02-11 11:08:44 +01001261 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001262
Michal Vaskoe0665742021-02-11 11:08:44 +01001263 /* create attributes */
1264 if (xmlctx->status == LYXML_ATTRIBUTE) {
1265 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1266 }
1267
1268 /* create node */
1269 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1270 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +02001271 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001272 LY_CHECK_GOTO(rc, cleanup);
1273
1274 /* assign atributes */
1275 ((struct lyd_node_opaq *)child)->attr = attr;
1276 attr = NULL;
1277
1278 /* parser next element */
1279 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1280
1281 /* parse all the descendants */
1282 while (xmlctx->status == LYXML_ELEMENT) {
1283 rc = lydxml_opaq_r(xmlctx, child);
1284 LY_CHECK_GOTO(rc, cleanup);
1285 }
1286
1287 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001288 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001289
1290cleanup:
1291 lyd_free_attr_siblings(xmlctx->ctx, attr);
1292 if (rc) {
1293 lyd_free_tree(child);
1294 }
1295 return rc;
1296}
1297
1298/**
1299 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1300 *
1301 * @param[in] xmlctx XML parser context.
1302 * @param[in] parent Parent to append nodes to.
1303 * @return LY_ERR value.
1304 */
1305static LY_ERR
1306lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1307{
1308 LY_ERR r;
1309 struct lyd_node *child, *iter;
Michal Vaskoe0665742021-02-11 11:08:44 +01001310 ly_bool no_dup;
1311
1312 /* there must be some child */
1313 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1314 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1315 return LY_EVALID;
1316 }
1317
1318 while (xmlctx->status == LYXML_ELEMENT) {
1319 child = NULL;
1320
1321 /*
1322 * session-id
1323 */
1324 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1325 if (r == LY_SUCCESS) {
1326 no_dup = 1;
1327 goto check_child;
1328 } else if (r != LY_ENOT) {
1329 goto error;
1330 }
1331
1332 /*
1333 * bad-attribute
1334 */
1335 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1336 if (r == LY_SUCCESS) {
1337 no_dup = 1;
1338 goto check_child;
1339 } else if (r != LY_ENOT) {
1340 goto error;
1341 }
1342
1343 /*
1344 * bad-element
1345 */
1346 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1347 if (r == LY_SUCCESS) {
1348 no_dup = 1;
1349 goto check_child;
1350 } else if (r != LY_ENOT) {
1351 goto error;
1352 }
1353
1354 /*
1355 * bad-namespace
1356 */
1357 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1358 if (r == LY_SUCCESS) {
1359 no_dup = 1;
1360 goto check_child;
1361 } else if (r != LY_ENOT) {
1362 goto error;
1363 }
1364
1365 if (r == LY_ENOT) {
1366 assert(xmlctx->status == LYXML_ELEMENT);
1367
Michal Vasko845ba392022-06-16 07:52:13 +02001368 /* custom elements, parse all the siblings */
1369 while (xmlctx->status == LYXML_ELEMENT) {
1370 LY_CHECK_GOTO(r = lydxml_opaq_r(xmlctx, parent), error);
1371 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1372 }
Michal Vasko6398eaf2022-01-10 10:12:30 +01001373 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001374 }
1375
1376check_child:
1377 /* check for duplicates */
1378 if (no_dup) {
1379 LY_LIST_FOR(lyd_child(parent), iter) {
1380 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1381 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1382 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1383 ((struct lyd_node_opaq *)child)->name.name);
1384 r = LY_EVALID;
1385 goto error;
1386 }
1387 }
1388 }
1389
1390 /* finish child parsing */
1391 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1392 assert(xmlctx->status == LYXML_ELEMENT);
1393 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001394 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001395 r = LY_EVALID;
1396 goto error;
1397 }
1398 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1399
1400 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001401 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001402 }
1403
1404 return LY_SUCCESS;
1405
1406error:
1407 lyd_free_tree(child);
1408 return r;
1409}
1410
1411/**
1412 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1413 *
1414 * @param[in] xmlctx XML parser context.
1415 * @param[in] parent Parent to append nodes to.
1416 * @return LY_ERR value.
1417 */
1418static LY_ERR
1419lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1420{
1421 LY_ERR r;
1422 struct lyd_node *child, *iter;
1423 const char *val;
1424 ly_bool no_dup;
1425
1426 /* there must be some child */
1427 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1428 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1429 return LY_EVALID;
1430 }
1431
1432 while (xmlctx->status == LYXML_ELEMENT) {
1433 child = NULL;
1434
1435 /*
1436 * error-type
1437 */
1438 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1439 if (r == LY_SUCCESS) {
1440 val = ((struct lyd_node_opaq *)child)->value;
1441 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1442 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1443 ((struct lyd_node_opaq *)child)->name.name);
1444 r = LY_EVALID;
1445 goto error;
1446 }
1447
1448 no_dup = 1;
1449 goto check_child;
1450 } else if (r != LY_ENOT) {
1451 goto error;
1452 }
1453
1454 /*
1455 * error-tag
1456 */
1457 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1458 if (r == LY_SUCCESS) {
1459 val = ((struct lyd_node_opaq *)child)->value;
1460 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1461 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1462 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1463 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1464 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1465 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1466 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1467 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1468 ((struct lyd_node_opaq *)child)->name.name);
1469 r = LY_EVALID;
1470 goto error;
1471 }
1472
1473 no_dup = 1;
1474 goto check_child;
1475 } else if (r != LY_ENOT) {
1476 goto error;
1477 }
1478
1479 /*
1480 * error-severity
1481 */
1482 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1483 if (r == LY_SUCCESS) {
1484 val = ((struct lyd_node_opaq *)child)->value;
1485 if (strcmp(val, "error") && strcmp(val, "warning")) {
1486 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1487 ((struct lyd_node_opaq *)child)->name.name);
1488 r = LY_EVALID;
1489 goto error;
1490 }
1491
1492 no_dup = 1;
1493 goto check_child;
1494 } else if (r != LY_ENOT) {
1495 goto error;
1496 }
1497
1498 /*
1499 * error-app-tag
1500 */
1501 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1502 if (r == LY_SUCCESS) {
1503 no_dup = 1;
1504 goto check_child;
1505 } else if (r != LY_ENOT) {
1506 goto error;
1507 }
1508
1509 /*
1510 * error-path
1511 */
1512 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1513 if (r == LY_SUCCESS) {
1514 no_dup = 1;
1515 goto check_child;
1516 } else if (r != LY_ENOT) {
1517 goto error;
1518 }
1519
1520 /*
1521 * error-message
1522 */
1523 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1524 if (r == LY_SUCCESS) {
1525 no_dup = 1;
1526 goto check_child;
1527 } else if (r != LY_ENOT) {
1528 goto error;
1529 }
1530
1531 /* error-info */
1532 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1533 if (r == LY_SUCCESS) {
1534 /* parse all the descendants */
1535 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1536
1537 no_dup = 0;
1538 goto check_child;
1539 } else if (r != LY_ENOT) {
1540 goto error;
1541 }
1542
1543 if (r == LY_ENOT) {
1544 assert(xmlctx->status == LYXML_ELEMENT);
1545 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001546 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001547 r = LY_EVALID;
1548 goto error;
1549 }
1550
1551check_child:
1552 /* check for duplicates */
1553 if (no_dup) {
1554 LY_LIST_FOR(lyd_child(parent), iter) {
1555 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1556 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1557 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1558 ((struct lyd_node_opaq *)child)->name.name);
1559 r = LY_EVALID;
1560 goto error;
1561 }
1562 }
1563 }
1564
1565 /* finish child parsing */
1566 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1567 assert(xmlctx->status == LYXML_ELEMENT);
1568 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001569 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001570 r = LY_EVALID;
1571 goto error;
1572 }
1573 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1574
1575 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001576 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001577 }
1578
1579 return LY_SUCCESS;
1580
1581error:
1582 lyd_free_tree(child);
1583 return r;
1584}
1585
1586/**
1587 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1588 *
1589 * @param[in] xmlctx XML parser context.
1590 * @param[out] evnp Parsed envelope(s) (opaque node).
1591 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1592 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1593 * @return LY_SUCCESS on success.
1594 * @return LY_ERR value on error.
1595 */
1596static LY_ERR
1597lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1598{
1599 LY_ERR rc = LY_SUCCESS, r;
1600 struct lyd_node *child = NULL;
1601 const char *parsed_elem = NULL;
1602
1603 assert(envp && !*envp);
1604
Michal Vasko50375272022-04-26 12:07:46 +02001605 if (xmlctx->status != LYXML_ELEMENT) {
1606 /* nothing to parse */
1607 assert(xmlctx->status == LYXML_END);
1608 goto cleanup;
1609 }
1610
Michal Vaskoe0665742021-02-11 11:08:44 +01001611 /* parse "rpc-reply" */
1612 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001613 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1614
1615 /* there must be some child */
1616 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1617 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1618 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001619 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001620 }
1621
Michal Vaskoe0665742021-02-11 11:08:44 +01001622 /* try to parse "ok" */
1623 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1624 if (r == LY_SUCCESS) {
1625 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001626 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001627
1628 /* finish child parsing */
1629 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1630 assert(xmlctx->status == LYXML_ELEMENT);
1631 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001632 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001633 rc = LY_EVALID;
1634 goto cleanup;
1635 }
1636 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1637
1638 /* success */
1639 parsed_elem = "ok";
1640 goto finish;
1641 } else if (r != LY_ENOT) {
1642 rc = r;
1643 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001644 }
1645
Michal Vaskoe0665742021-02-11 11:08:44 +01001646 /* try to parse all "rpc-error" elements */
1647 while (xmlctx->status == LYXML_ELEMENT) {
1648 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1649 if (r == LY_ENOT) {
1650 break;
1651 } else if (r) {
1652 rc = r;
1653 goto cleanup;
1654 }
1655
1656 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001657 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001658
1659 /* parse all children of "rpc-error" */
1660 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1661
1662 /* finish child parsing */
1663 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1664 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1665
1666 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001667 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001668
1669finish:
1670 if (parsed_elem) {
1671 /* NETCONF rpc-reply with no data */
1672 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1673 assert(xmlctx->status == LYXML_ELEMENT);
1674 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001675 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001676 rc = LY_EVALID;
1677 goto cleanup;
1678 }
1679 }
1680
1681 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001682 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001683 *close_elem = 1;
1684
1685cleanup:
1686 if (rc) {
1687 lyd_free_tree(*envp);
1688 *envp = NULL;
1689 }
1690 return rc;
1691}
1692
Michal Vasko2552ea32020-12-08 15:32:34 +01001693LY_ERR
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +01001694lyd_parse_xml_netconf(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
Radek Krejcif16e2542021-02-17 15:39:23 +01001695 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +01001696 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001697{
Michal Vaskoe0665742021-02-11 11:08:44 +01001698 LY_ERR rc = LY_SUCCESS;
1699 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001700 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001701 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001702
Michal Vaskoe0665742021-02-11 11:08:44 +01001703 assert(ctx && in && lydctx_p);
1704 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1705 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001706
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +01001707 assert((data_type == LYD_TYPE_RPC_NETCONF) || (data_type == LYD_TYPE_NOTIF_NETCONF) ||
1708 (data_type == LYD_TYPE_REPLY_NETCONF));
1709 assert(!(parse_opts & LYD_PARSE_SUBTREE));
1710
Michal Vaskoe0665742021-02-11 11:08:44 +01001711 /* init context */
1712 lydctx = calloc(1, sizeof *lydctx);
1713 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1714 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1715 lydctx->parse_opts = parse_opts;
1716 lydctx->val_opts = val_opts;
1717 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001718 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001719
Michal Vaskoe0665742021-02-11 11:08:44 +01001720 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001721 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001722 assert(!parent);
Michal Vaskod71c2d42022-04-29 09:50:44 +02001723 rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem);
1724 if (rc == LY_ENOT) {
1725 LOGVAL(ctx, LYVE_DATA, "Missing NETCONF <rpc> envelope or in incorrect namespace.");
1726 }
1727 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001728 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001729 case LYD_TYPE_NOTIF_NETCONF:
1730 assert(!parent);
Michal Vaskod71c2d42022-04-29 09:50:44 +02001731 rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem);
1732 if (rc == LY_ENOT) {
1733 LOGVAL(ctx, LYVE_DATA, "Missing NETCONF <notification> envelope or in incorrect namespace.");
1734 }
1735 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001736 break;
1737 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001738 assert(parent);
Michal Vaskod71c2d42022-04-29 09:50:44 +02001739 rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem);
1740 if (rc == LY_ENOT) {
1741 LOGVAL(ctx, LYVE_DATA, "Missing NETCONF <rpc-reply> envelope or in incorrect namespace.");
1742 }
1743 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001744 break;
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +01001745 default:
1746 LOGINT(ctx);
1747 rc = LY_EINT;
1748 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +01001749 }
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +01001750
Michal Vaskoe0665742021-02-11 11:08:44 +01001751 lydctx->int_opts = int_opts;
1752
1753 /* find the operation node if it exists already */
1754 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1755
1756 /* parse XML data */
1757 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1758 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1759 parsed_data_nodes = 1;
1760
1761 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1762 break;
1763 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001764 }
1765
Michal Vaskoe0665742021-02-11 11:08:44 +01001766 /* close all opened elements */
1767 for (i = 0; i < close_elem; ++i) {
1768 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1769 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001770 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1771 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001772 rc = LY_EVALID;
1773 goto cleanup;
1774 }
1775
1776 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001777 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001778
1779 /* check final state */
1780 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1781 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1782 rc = LY_EVALID;
1783 goto cleanup;
1784 }
Michal Vaskoc939fdd2022-01-03 11:35:13 +01001785 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
Michal Vaskoe0665742021-02-11 11:08:44 +01001786 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1787 rc = LY_EVALID;
1788 goto cleanup;
1789 }
1790
1791 if (!parsed_data_nodes) {
1792 /* no data nodes were parsed */
1793 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001794 }
1795
1796cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001797 /* there should be no unres stored if validation should be skipped */
1798 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoddd76592022-01-17 13:34:48 +01001799 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001800
1801 if (rc) {
1802 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1803 } else {
1804 *lydctx_p = (struct lyd_ctx *)lydctx;
1805
1806 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1807 lyxml_ctx_free(lydctx->xmlctx);
1808 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001809 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001810 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001811}