blob: 776379a2f5a8b22087b0460c41801ae2f76ec77c [file] [log] [blame]
Michal Vasko90932a92020-02-12 14:33:03 +01001/**
2 * @file parser_json.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief JSON data parser for libyang
5 *
Radek Krejci1798aae2020-07-14 13:26:06 +02006 * Copyright (c) 2020 CESNET, z.s.p.o.
Michal Vasko90932a92020-02-12 14:33:03 +01007 *
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
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
Michal Vasko90932a92020-02-12 14:33:03 +010016
Radek Krejci1798aae2020-07-14 13:26:06 +020017#include <assert.h>
Radek Krejci47fab892020-11-05 17:02:41 +010018#include <stdint.h>
Michal Vasko90932a92020-02-12 14:33:03 +010019#include <stdlib.h>
20#include <string.h>
21
Radek Krejci535ea9f2020-05-29 16:01:05 +020022#include "common.h"
Michal Vasko90932a92020-02-12 14:33:03 +010023#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010024#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020025#include "in_internal.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020026#include "json.h"
Radek Krejci47fab892020-11-05 17:02:41 +010027#include "log.h"
28#include "parser_data.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020029#include "parser_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010030#include "set.h"
31#include "tree.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020032#include "tree_data.h"
33#include "tree_data_internal.h"
34#include "tree_schema.h"
Radek Krejci47fab892020-11-05 17:02:41 +010035#include "tree_schema_internal.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020036#include "validation.h"
Michal Vasko90932a92020-02-12 14:33:03 +010037
38/**
Radek Krejci1798aae2020-07-14 13:26:06 +020039 * @brief Internal context for JSON YANG data parser.
40 *
41 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
42 */
43struct lyd_json_ctx {
44 uint32_t parse_options; /**< various @ref dataparseroptions. */
45 uint32_t validate_options; /**< various @ref datavalidationoptions. */
46 uint32_t int_opts; /**< internal data parser options */
47 uint32_t path_len; /**< used bytes in the path buffer */
48 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko49c39d82020-11-06 17:20:27 +010049 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
50 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
51 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci1798aae2020-07-14 13:26:06 +020052 struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
53
54 /* callbacks */
55 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020056
57 struct lyjson_ctx *jsonctx; /**< JSON context */
58};
59
60/**
61 * @brief Free the JSON data parser context.
62 *
63 * JSON implementation of lyd_ctx_free_clb().
64 */
65static void
66lyd_json_ctx_free(struct lyd_ctx *lydctx)
67{
68 struct lyd_json_ctx *ctx = (struct lyd_json_ctx *)lydctx;
69
70 if (lydctx) {
71 lyd_ctx_free(lydctx);
72 lyjson_ctx_free(ctx->jsonctx);
73 free(ctx);
74 }
75}
76
77/**
Radek Krejci1798aae2020-07-14 13:26:06 +020078 * @brief Parse JSON member-name as [\@][prefix:][name]
79 *
Michal Vaskocabe0702020-08-12 10:14:36 +020080 * \@ - metadata flag, maps to 1 in @p is_meta_p
Radek Krejci1798aae2020-07-14 13:26:06 +020081 * prefix - name of the module of the data node
82 * name - name of the data node
83 *
84 * All the output parameter are mandatory. Function only parse the member-name, all the appropriate checks are up to the caller.
85 *
86 * @param[in] value String to parse
87 * @param[in] value_len Length of the @p str.
88 * @param[out] name_p Pointer to the beginning of the parsed name.
89 * @param[out] name_len_p Pointer to the length of the parsed name.
90 * @param[out] prefix_p Pointer to the beginning of the parsed prefix. If the member-name does not contain prefix, result is NULL.
91 * @param[out] prefix_len_p Pointer to the length of the parsed prefix. If the member-name does not contain prefix, result is 0.
Michal Vaskocabe0702020-08-12 10:14:36 +020092 * @param[out] is_meta_p Pointer to the metadata flag, set to 1 if the member-name contains \@, 0 otherwise.
Radek Krejci1798aae2020-07-14 13:26:06 +020093 */
94static void
Michal Vaskocabe0702020-08-12 10:14:36 +020095lydjson_parse_name(const char *value, size_t value_len, const char **name_p, size_t *name_len_p, const char **prefix_p,
Radek Krejci857189e2020-09-01 13:26:36 +020096 size_t *prefix_len_p, ly_bool *is_meta_p)
Radek Krejci1798aae2020-07-14 13:26:06 +020097{
98 const char *name, *prefix = NULL;
99 size_t name_len, prefix_len = 0;
Radek Krejci857189e2020-09-01 13:26:36 +0200100 ly_bool is_meta = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200101
102 name = memchr(value, ':', value_len);
103 if (name != NULL) {
104 prefix = value;
105 if (*prefix == '@') {
Michal Vaskocabe0702020-08-12 10:14:36 +0200106 is_meta = 1;
Radek Krejci1798aae2020-07-14 13:26:06 +0200107 prefix++;
108 }
109 prefix_len = name - prefix;
110 name++;
Michal Vaskocabe0702020-08-12 10:14:36 +0200111 name_len = value_len - (prefix_len + 1) - is_meta;
Radek Krejci1798aae2020-07-14 13:26:06 +0200112 } else {
113 name = value;
114 if (name[0] == '@') {
Michal Vaskocabe0702020-08-12 10:14:36 +0200115 is_meta = 1;
Radek Krejci1798aae2020-07-14 13:26:06 +0200116 name++;
117 }
Michal Vaskocabe0702020-08-12 10:14:36 +0200118 name_len = value_len - is_meta;
Michal Vasko90932a92020-02-12 14:33:03 +0100119 }
120
Radek Krejci1798aae2020-07-14 13:26:06 +0200121 *name_p = name;
122 *name_len_p = name_len;
123 *prefix_p = prefix;
124 *prefix_len_p = prefix_len;
Michal Vaskocabe0702020-08-12 10:14:36 +0200125 *is_meta_p = is_meta;
Radek Krejci1798aae2020-07-14 13:26:06 +0200126}
127
128/**
129 * @brief Get correct prefix (module_name) inside the @p node.
130 *
131 * @param[in] node Data node to get inherited prefix.
132 * @param[in] local_prefix Local prefix to replace the inherited prefix.
133 * @param[in] local_prefix_len Length of the @p local_prefix string. In case of 0, the inherited prefix is taken.
134 * @param[out] prefix_p Pointer to the resulting prefix string, Note that the result can be NULL in case of no local prefix
135 * and no context @p node to get inherited prefix.
136 * @param[out] prefix_len_p Pointer to the length of the resulting @p prefix_p string. Note that the result can be 0 in case
137 * of no local prefix and no context @p node to get inherited prefix.
138 * @return LY_ERR value.
139 */
140static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200141lydjson_get_node_prefix(struct lyd_node *node, const char *local_prefix, size_t local_prefix_len, const char **prefix_p,
Radek Krejci0f969882020-08-21 16:56:47 +0200142 size_t *prefix_len_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200143{
144 struct lyd_node_opaq *onode;
145 const char *module_name = NULL;
146
147 assert(prefix_p && prefix_len_p);
148
149 if (local_prefix_len) {
150 *prefix_p = local_prefix;
151 *prefix_len_p = local_prefix_len;
152 return LY_SUCCESS;
153 }
154
155 *prefix_p = NULL;
156 while (node) {
157 if (node->schema) {
158 *prefix_p = node->schema->module->name;
159 break;
160 }
Michal Vasko22df3f02020-08-24 13:29:22 +0200161 onode = (struct lyd_node_opaq *)node;
Radek Krejci1798aae2020-07-14 13:26:06 +0200162 if (onode->prefix.module_name) {
163 *prefix_p = onode->prefix.module_name;
164 break;
165 } else if (onode->prefix.id) {
166 *prefix_p = onode->prefix.id;
167 break;
168 }
Michal Vasko22df3f02020-08-24 13:29:22 +0200169 node = (struct lyd_node *)node->parent;
Radek Krejci1798aae2020-07-14 13:26:06 +0200170 }
171 *prefix_len_p = ly_strlen(module_name);
172
173 return LY_SUCCESS;
174}
175
176/**
177 * @brief Get schema node corresponding to the input parameters.
178 *
179 * @param[in] lydctx JSON data parser context.
180 * @param[in] is_attr Flag if the reference to the node is an attribute, for logging only.
181 * @param[in] prefix Requested node's prefix (module name).
182 * @param[in] prefix_len Length of the @p prefix.
183 * @param[in] name Requested node's name.
184 * @param[in] name_len Length of the @p name.
185 * @param[in] parent Parent of the node beeing processed, can be NULL in case of top-level. Also the opaq node with LYD_NODE_OPAQ_ISENVELOPE hint
186 * is accepted for searching top-level nodes.
187 * @param[out] snode_p Pointer to the found schema node corresponding to the input parameters.
188 * @return LY_SUCCES on success, note that even in this case the returned value of @p snode_p can be NULL, so the data are expected to be parsed as opaq.
189 * @return LY_EVALID on failure, error message is logged
190 * @return LY_ENOT in case the input data are expected to be skipped
191 */
192static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +0200193lydjson_get_snode(const struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *prefix, size_t prefix_len, const char *name,
Radek Krejci0f969882020-08-21 16:56:47 +0200194 size_t name_len, const struct lyd_node_inner *parent, const struct lysc_node **snode_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200195{
196 struct lys_module *mod = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100197 uint32_t getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200198
199 /* init return value */
200 *snode_p = NULL;
201
202 /* get the element module */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200203 if (prefix_len || (parent && !parent->schema && (((struct lyd_node_opaq *)parent)->hints & LYD_NODEHINT_ENVELOPE))) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200204 if (!prefix_len) {
205 /* opaq parent (envelope) - the second part of the condition */
Michal Vasko22df3f02020-08-24 13:29:22 +0200206 lydjson_get_node_prefix((struct lyd_node *)parent, NULL, 0, &prefix, &prefix_len);
Radek Krejci1798aae2020-07-14 13:26:06 +0200207 }
208 mod = ly_ctx_get_module_implemented2(lydctx->jsonctx->ctx, prefix, prefix_len);
209 } else if (parent) {
210 if (parent->schema) {
211 mod = parent->schema->module;
212 }
213 } else {
214 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, parent, LYVE_SYNTAX_JSON, "Top-level JSON object member \"%.*s\" must be namespace-qualified.",
Michal Vasko69730152020-10-09 16:30:07 +0200215 is_attr ? name_len + 1 : name_len, is_attr ? name - 1 : name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200216 return LY_EVALID;
217 }
218 if (!mod) {
219 if (lydctx->parse_options & LYD_PARSE_STRICT) {
220 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, parent, LYVE_REFERENCE, "No module named \"%.*s\" in the context.", prefix_len, prefix);
221 return LY_EVALID;
222 }
223 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
224 return LY_ENOT;
225 }
226 }
227
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200228 if (parent && !parent->schema && (((struct lyd_node_opaq *)parent)->hints & LYD_NODEHINT_ENVELOPE)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200229 /* ignore the envelope parent when searchinf for the schema node */
230 parent = NULL;
231 }
232
233 /* get the schema node */
234 if (mod && (!parent || parent->schema)) {
235 *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
236 if (!*snode_p) {
237 if (lydctx->parse_options & LYD_PARSE_STRICT) {
238 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, parent, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
Michal Vasko69730152020-10-09 16:30:07 +0200239 name_len, name, mod->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200240 return LY_EVALID;
241 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
242 /* skip element with children */
243 return LY_ENOT;
244 }
245 } else {
246 /* check that schema node is valid and can be used */
247 LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode_p));
248 }
249 }
250
251 return LY_SUCCESS;
252}
253
254/**
255 * @brief Skip the currently open JSON object/array
256 * @param[in] jsonctx JSON context with the input data to skip.
257 * @return LY_ERR value.
258 */
259static LY_ERR
260lydjson_data_skip(struct lyjson_ctx *jsonctx)
261{
262 enum LYJSON_PARSER_STATUS status, current;
263 size_t sublevels = 1;
264
265 status = lyjson_ctx_status(jsonctx, 0);
266
267 /* skip after the content */
268 do {
269 LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
270 if (current == status) {
271 sublevels++;
272 } else if (current == status + 1) {
273 sublevels--;
274 }
275 } while (current != status + 1 && sublevels);
276 /* open the next sibling */
277 LY_CHECK_RET(lyjson_ctx_next(jsonctx, NULL));
278
279 return LY_SUCCESS;
280}
281
282/**
283 * @brief Go through the @p value and find all possible prefixes and store them in @p val_prefs_p [sized array](@ref sizedarrays).
284 *
285 * @param[in] ctx libyang context
286 * @param[in] value Pointer to the beginning of the value to check.
287 * @param[in] value_len Length of the string to examine in @p value.
288 * @param[out] val_prefs_p Pointer to the resulting [sized array](@ref sizedarrays) of found prefixes. NULL in case there are no prefixes.
289 * @return LY_EMEM on memory allocation failure.
290 * @return LY_SUCCESS on success, empty @p val_prefs_p (NULL) is valid result if there are no possible prefixes
291 */
292static LY_ERR
293lydjson_get_value_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len, struct ly_prefix **val_prefs_p)
294{
295 LY_ERR ret;
296 LY_ARRAY_COUNT_TYPE u;
297 uint32_t c;
298 const char *start, *stop;
299 struct ly_prefix *prefixes = NULL;
300 size_t len;
301
302 for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
303 size_t bytes;
304 ly_getutf8(&stop, &c, &bytes);
305 if (is_yangidentstartchar(c)) {
306 for (ly_getutf8(&stop, &c, &bytes);
307 is_yangidentchar(c) && (size_t)(stop - value) < value_len;
Radek Krejci1e008d22020-08-17 11:37:37 +0200308 ly_getutf8(&stop, &c, &bytes)) {}
Radek Krejci1798aae2020-07-14 13:26:06 +0200309 stop = stop - bytes;
310 if (*stop == ':') {
311 /* we have a possible prefix */
312 struct ly_prefix *p = NULL;
313
314 len = stop - start;
315
316 /* check whether we do not already have this prefix stored */
317 LY_ARRAY_FOR(prefixes, u) {
318 if (!ly_strncmp(prefixes[u].id, start, len)) {
319 p = &prefixes[u];
320 break;
321 }
322 }
323 if (!p) {
324 LY_ARRAY_NEW_GOTO(ctx, prefixes, p, ret, error);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200325 LY_CHECK_GOTO(ret = lydict_insert(ctx, start, len, &p->id), error);
326 LY_CHECK_GOTO(ret = lydict_insert(ctx, start, len, &p->module_name), error);
Radek Krejci1798aae2020-07-14 13:26:06 +0200327 } /* else the prefix already present */
328 }
329 stop = stop + bytes;
330 }
331 }
332
333 *val_prefs_p = prefixes;
334 return LY_SUCCESS;
335
336error:
337 LY_ARRAY_FOR(prefixes, u) {
338 lydict_remove(ctx, prefixes[u].id);
339 lydict_remove(ctx, prefixes[u].module_name);
340 }
341 LY_ARRAY_FREE(prefixes);
342 return ret;
343}
344
345/**
346 * @brief Check that the input data are parseable as the @p list.
347 *
348 * Checks for all the list's keys. Function does not revert the context state.
349 *
350 * @param[in] jsonctx JSON parser context.
351 * @param[in] list List schema node corresponding to the input data object.
352 * @return LY_SUCCESS in case the data are ok for the @p list
353 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance.
354 */
355static LY_ERR
356lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list)
357{
358 LY_ERR ret = LY_SUCCESS;
359 enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx, 0);
360 struct ly_set key_set = {0};
361 const struct lysc_node *snode;
362 uint32_t i, status_count;
363
364 assert(list && (list->nodetype == LYS_LIST));
365 assert(status == LYJSON_OBJECT);
366
367 /* get all keys into a set (keys do not have if-features or anything) */
368 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100369 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200370 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200371 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200372 }
373
374 if (status != LYJSON_OBJECT_EMPTY) {
375 status_count = jsonctx->status.count;
376
377 while (key_set.count && status != LYJSON_OBJECT_CLOSED) {
378 const char *name, *prefix;
379 size_t name_len, prefix_len;
Radek Krejci857189e2020-09-01 13:26:36 +0200380 ly_bool is_attr;
Radek Krejci1798aae2020-07-14 13:26:06 +0200381
382 /* match the key */
383 snode = NULL;
384 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
385
386 if (!is_attr && !prefix) {
387 for (i = 0; i < key_set.count; ++i) {
388 snode = (const struct lysc_node *)key_set.objs[i];
389 if (!ly_strncmp(snode->name, name, name_len)) {
390 break;
391 }
392 }
393 /* go into the item to a) process it as a key or b) start skipping it as another list child */
394 ret = lyjson_ctx_next(jsonctx, &status);
395 LY_CHECK_GOTO(ret, cleanup);
396
397 if (snode) {
398 /* we have the key, validate the value */
399 if (status < LYJSON_NUMBER) {
400 /* not a terminal */
401 ret = LY_ENOT;
402 goto cleanup;
403 }
404
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200405 ret = _lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_PREF_JSON, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200406 LY_CHECK_GOTO(ret, cleanup);
407
408 /* key with a valid value, remove from the set */
409 ly_set_rm_index(&key_set, i, NULL);
410 }
411 } else {
412 /* start skipping the member we are not interested in */
413 ret = lyjson_ctx_next(jsonctx, &status);
414 LY_CHECK_GOTO(ret, cleanup);
415 }
416 /* move to the next child */
417 while (status_count < jsonctx->status.count) {
418 ret = lyjson_ctx_next(jsonctx, &status);
419 LY_CHECK_GOTO(ret, cleanup);
420 }
421 }
422 }
423
424 if (key_set.count) {
425 /* some keys are missing/did not validate */
426 ret = LY_ENOT;
427 }
428
429cleanup:
430 ly_set_erase(&key_set, NULL);
431 return ret;
432}
433
434/**
435 * @brief Get the hint for the data type parsers according to the current JSON parser context.
436 *
437 * @param[in] lydctx JSON data parser context. The context is supposed to be on a value.
438 * @param[in,out] status Pointer to the current context status,
439 * in some circumstances the function manipulates with the context so the status is updated.
440 * @param[out] type_hint_p Pointer to the variable to store the result.
441 * @return LY_SUCCESS in case of success.
442 * @return LY_EINVAL in case of invalid context status not referring to a value.
443 */
444static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200445lydjson_value_type_hint(struct lyd_json_ctx *lydctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200446{
447 *type_hint_p = 0;
448
449 if (*status_p == LYJSON_ARRAY) {
450 /* only [null] */
451 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
452 LY_CHECK_RET(*status_p != LYJSON_NULL, LY_EINVAL);
453
454 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
455 LY_CHECK_RET(lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_ARRAY_CLOSED, LY_EINVAL);
456
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200457 *type_hint_p = LYD_VALHINT_EMPTY;
Radek Krejci1798aae2020-07-14 13:26:06 +0200458 } else if (*status_p == LYJSON_STRING) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200459 *type_hint_p = LYD_VALHINT_STRING | LYD_VALHINT_NUM64;
Radek Krejci1798aae2020-07-14 13:26:06 +0200460 } else if (*status_p == LYJSON_NUMBER) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200461 *type_hint_p = LYD_VALHINT_DECNUM;
Michal Vasko69730152020-10-09 16:30:07 +0200462 } else if ((*status_p == LYJSON_FALSE) || (*status_p == LYJSON_TRUE)) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200463 *type_hint_p = LYD_VALHINT_BOOLEAN;
Radek Krejci1798aae2020-07-14 13:26:06 +0200464 } else if (*status_p == LYJSON_NULL) {
465 *type_hint_p = 0;
466 } else {
467 return LY_EINVAL;
468 }
469
470 return LY_SUCCESS;
471}
472
473/**
474 * @brief Check in advance if the input data are parsable according to the provided @p snode.
475 *
476 * Note that the checks are done only in case the LYD_PARSE_OPAQ is allowed. Otherwise the same checking
477 * is naturally done when the data are really parsed.
478 *
479 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
480 * as before calling, despite it is necessary to process input data for checking.
481 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
482 * @param[out] type_hint_p Pointer to a variable to store detected value type hint in case of leaf or leaf-list.
483 * @return LY_SUCCESS in case the data are ok for the @p snode or the LYD_PARSE_OPAQ is not enabled.
484 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance
485 * @return LY_EINVAL in case of invalid leaf JSON encoding
486 * and they are expected to be parsed as opaq nodes.
487 */
488static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200489lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, uint32_t *type_hint_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200490{
491 LY_ERR ret = LY_SUCCESS;
492 struct lyjson_ctx *jsonctx = lydctx->jsonctx;
493 enum LYJSON_PARSER_STATUS status;
494
495 assert(snode);
Radek Krejci1798aae2020-07-14 13:26:06 +0200496
Michal Vasko32ac9942020-08-12 14:35:12 +0200497 if (!(snode->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
498 /* can always be parsed as a data node if we have the schema node */
499 return LY_SUCCESS;
500 }
501
502 if (lydctx->parse_options & LYD_PARSE_OPAQ) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200503 /* backup parser */
504 lyjson_ctx_backup(jsonctx);
505 status = lyjson_ctx_status(jsonctx, 0);
506
Michal Vasko32ac9942020-08-12 14:35:12 +0200507 /* check if the node is parseable. if not, NULL the snode to announce that it is supposed to be parsed
508 * as an opaq node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200509 switch (snode->nodetype) {
510 case LYS_LEAFLIST:
511 case LYS_LEAF:
512 /* value may not be valid in which case we parse it as an opaque node */
513 ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
514 if (ret) {
515 break;
516 }
517
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200518 if (_lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_PREF_JSON, NULL)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200519 ret = LY_ENOT;
520 }
521 break;
522 case LYS_LIST:
523 /* lists may not have all its keys */
524 if (lydjson_check_list(jsonctx, snode)) {
525 /* invalid list, parse as opaque if it missing/has invalid some keys */
526 ret = LY_ENOT;
527 }
Michal Vasko32ac9942020-08-12 14:35:12 +0200528 break;
Radek Krejci1798aae2020-07-14 13:26:06 +0200529 }
530
531 /* restore parser */
532 lyjson_ctx_restore(jsonctx);
Michal Vasko32ac9942020-08-12 14:35:12 +0200533 } else if (snode->nodetype & LYD_NODE_TERM) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200534 status = lyjson_ctx_status(jsonctx, 0);
535 ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
536 }
537
538 return ret;
539}
540
541/**
542 * @brief Join the forward-referencing metadata with their target data nodes.
543 *
544 * Note that JSON encoding for YANG data allows forward-referencing metadata only for leafs/leaf-lists.
545 *
546 * @param[in] lydctx JSON data parser context.
547 * @param[in,out] first_p Pointer to the first sibling node variable (top-level or in a particular parent node)
548 * as a starting point to search for the metadata's target data node
549 * @return LY_SUCCESS on success
550 * @return LY_EVALID in case there are some metadata with unresolved target data node instance
551 */
552static LY_ERR
553lydjson_metadata_finish(struct lyd_json_ctx *lydctx, struct lyd_node **first_p)
554{
555 LY_ERR ret = LY_SUCCESS;
556 struct lyd_node *node, *attr, *next, *start = *first_p, *meta_iter;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200557 uint64_t instance = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200558 const char *prev = NULL;
559
560 /* finish linking metadata */
561 LY_LIST_FOR_SAFE(*first_p, next, attr) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200562 struct lyd_node_opaq *meta_container = (struct lyd_node_opaq *)attr;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200563 uint64_t match = 0;
Radek Krejci857189e2020-09-01 13:26:36 +0200564 ly_bool is_attr;
Radek Krejci1798aae2020-07-14 13:26:06 +0200565 const char *name, *prefix;
566 size_t name_len, prefix_len;
567 const struct lysc_node *snode;
568
Michal Vasko69730152020-10-09 16:30:07 +0200569 if (attr->schema || (meta_container->name[0] != '@')) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200570 /* not an opaq metadata node */
571 continue;
572 }
573
574 if (prev != meta_container->name) {
575 /* metas' names are stored in dictionary, so checking pointers must works */
576 lydict_remove(lydctx->jsonctx->ctx, prev);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200577 LY_CHECK_GOTO(ret = lydict_insert(lydctx->jsonctx->ctx, meta_container->name, 0, &prev), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200578 instance = 1;
579 } else {
580 instance++;
581 }
582
583 /* find the correspnding data node */
584 LY_LIST_FOR(start, node) {
585 if (!node->schema) {
586 /* opaq node - we are going to put into it just a generic attribute. */
Michal Vasko22df3f02020-08-24 13:29:22 +0200587 if (strcmp(&meta_container->name[1], ((struct lyd_node_opaq *)node)->name)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200588 continue;
589 }
590
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200591 if (((struct lyd_node_opaq *)node)->hints & LYD_NODEHINT_LIST) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200592 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, node, LYVE_SYNTAX,
Michal Vasko69730152020-10-09 16:30:07 +0200593 "Metadata container references a sibling list node %s.", ((struct lyd_node_opaq *)node)->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200594 ret = LY_EVALID;
595 goto cleanup;
596 }
597
598 /* match */
599 match++;
600 if (match != instance) {
601 continue;
602 }
603
604 LY_LIST_FOR(meta_container->child, meta_iter) {
605 /* convert opaq node to a attribute of the opaq node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200606 struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
Radek Krejci1798aae2020-07-14 13:26:06 +0200607 struct ly_prefix *val_prefs = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200608 ly_bool dynamic = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200609
610 /* get value prefixes */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200611 LY_CHECK_GOTO(ret = lydjson_get_value_prefixes(lydctx->jsonctx->ctx, lydctx->jsonctx->value,
612 lydctx->jsonctx->value_len, &val_prefs), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200613
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200614 ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, meta->name, strlen(meta->name), meta->value,
615 ly_strlen(meta->value), &dynamic, LYD_JSON, meta->hints, val_prefs, meta->prefix.id,
616 ly_strlen(meta->prefix.id), meta->prefix.module_name, ly_strlen(meta->prefix.module_name));
Radek Krejci1798aae2020-07-14 13:26:06 +0200617 LY_CHECK_GOTO(ret, cleanup);
618 }
619
620 /* done */
621 break;
622 } else {
623 /* this is the second time we are resolving the schema node, so it must succeed,
624 * but remember that snode can be still NULL */
625 lydjson_parse_name(meta_container->name, strlen(meta_container->name), &name, &name_len, &prefix, &prefix_len, &is_attr);
626 assert(is_attr);
627 ret = lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, (*first_p)->parent, &snode);
628 assert(ret == LY_SUCCESS);
629
630 if (snode != node->schema) {
631 continue;
632 }
633
634 /* match */
635 match++;
636 if (match != instance) {
637 continue;
638 }
639
640 LY_LIST_FOR(meta_container->child, meta_iter) {
641 /* convert opaq node to a metadata of the node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200642 struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
Radek Krejci1798aae2020-07-14 13:26:06 +0200643 struct lys_module *mod = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200644 ly_bool dynamic = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200645
646 mod = ly_ctx_get_module_implemented(lydctx->jsonctx->ctx, meta->prefix.id);
647 if (mod) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200648 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod,
Michal Vasko69730152020-10-09 16:30:07 +0200649 meta->name, strlen(meta->name), meta->value, ly_strlen(meta->value),
650 &dynamic, LY_PREF_JSON, NULL, meta->hints);
Radek Krejci1798aae2020-07-14 13:26:06 +0200651 LY_CHECK_GOTO(ret, cleanup);
652 } else if (lydctx->parse_options & LYD_PARSE_STRICT) {
653 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200654 "Unknown (or not implemented) YANG module \"%s\" for metadata \"%s%s%s\".",
655 meta->prefix.id, meta->prefix.id, ly_strlen(meta->prefix.id) ? ":" : "", meta->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200656 ret = LY_EVALID;
657 goto cleanup;
658 }
659 }
660 /* add/correct flags */
Michal Vasko49c39d82020-11-06 17:20:27 +0100661 lyd_parse_set_data_flags(node, &lydctx->node_when, &node->meta, lydctx->parse_options);
Radek Krejci1798aae2020-07-14 13:26:06 +0200662
663 /* done */
664 break;
665 }
666 }
667
668 if (match != instance) {
669 /* there is no corresponding data node for the metadata */
670 if (instance > 1) {
671 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, *first_p ? (*first_p)->parent : NULL, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200672 "Missing %d%s JSON data instance to be coupled with %s metadata.", instance,
673 instance == 2 ? "nd" : (instance == 3 ? "rd" : "th"), meta_container->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200674 } else {
675 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, *first_p ? (*first_p)->parent : NULL, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200676 "Missing JSON data instance to be coupled with %s metadata.", meta_container->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200677 }
678 ret = LY_EVALID;
679 } else {
680 /* remove the opaq attr */
681 if (attr == (*first_p)) {
682 *first_p = attr->next;
683 }
684 lyd_free_tree(attr);
685 }
686 }
687
688cleanup:
689 lydict_remove(lydctx->jsonctx->ctx, prev);
690
691 return ret;
692}
693
694/**
695 * @brief Parse a metadata member.
696 *
697 * @param[in] lydctx JSON data parser context.
698 * @param[in] snode Schema node of the metadata parent.
699 * @param[in] node Parent node in case the metadata is not forward-referencing (only LYD_NODE_TERM)
700 * so the data node does not exists. In such a case the metadata is stored in the context for the later
701 * processing by lydjson_metadata_finish().
702 * @return LY_SUCCESS on success
703 * @return Various LY_ERR values in case of failure.
704 */
705static LY_ERR
706lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node)
707{
708 LY_ERR ret = LY_SUCCESS;
709 enum LYJSON_PARSER_STATUS status;
710 const char *expected;
Radek Krejci857189e2020-09-01 13:26:36 +0200711 ly_bool in_parent = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200712 const char *name, *prefix = NULL;
713 size_t name_len, prefix_len = 0;
714 struct lys_module *mod;
715 struct lyd_meta *meta = NULL;
716 const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
Radek Krejci857189e2020-09-01 13:26:36 +0200717 ly_bool is_attr = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200718 struct lyd_node *prev = node;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200719 uint32_t instance = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200720 uint16_t nodetype;
721
722 assert(snode || node);
723
724 nodetype = snode ? snode->nodetype : LYS_CONTAINER;
725
726 /* move to the second item in the name/X pair */
727 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
728 LY_CHECK_GOTO(ret, cleanup);
729
730 /* check attribute encoding */
731 switch (nodetype) {
732 case LYS_LEAFLIST:
733 expected = "@name/array of objects/nulls";
734
735 LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
736
737next_entry:
738 instance++;
739
740 /* move into array / next entry */
741 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
742 LY_CHECK_GOTO(ret, cleanup);
743
744 if (status == LYJSON_ARRAY_CLOSED) {
745 /* we are done, move after the array */
746 ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
747 goto cleanup;
748 }
749 LY_CHECK_GOTO(status != LYJSON_OBJECT && status != LYJSON_NULL, representation_error);
750
Michal Vasko69730152020-10-09 16:30:07 +0200751 if (!node || (node->schema != prev->schema)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200752 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, prev->parent, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200753 "Missing JSON data instance no. %u of %s:%s to be coupled with metadata.",
754 instance, prev->schema->module->name, prev->schema->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200755 ret = LY_EVALID;
756 goto cleanup;
757 }
758
759 if (status == LYJSON_NULL) {
760 /* continue with the next entry in the leaf-list array */
761 prev = node;
762 node = node->next;
763 goto next_entry;
764 }
765 break;
766 case LYS_LEAF:
767 case LYS_ANYXML:
768 expected = "@name/object";
769
770 LY_CHECK_GOTO(status != LYJSON_OBJECT && (nodetype != LYS_LEAFLIST || status != LYJSON_NULL), representation_error);
771 break;
772 case LYS_CONTAINER:
773 case LYS_LIST:
774 case LYS_ANYDATA:
775 case LYS_NOTIF:
776 case LYS_ACTION:
777 case LYS_RPC:
778 in_parent = 1;
779 expected = "@/object";
780 LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
781 break;
Radek Krejci8f5fad22020-09-15 16:50:54 +0200782 default:
783 LOGINT_RET(ctx);
Radek Krejci1798aae2020-07-14 13:26:06 +0200784 }
785
786 /* process all the members inside a single metadata object */
787 assert(status == LYJSON_OBJECT);
788
789 while (status != LYJSON_OBJECT_CLOSED) {
790 lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
791 if (!prefix) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200792 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +0200793 "Metadata in JSON must be namespace-qualified, missing prefix for \"%.*s\".",
794 lydctx->jsonctx->value_len, lydctx->jsonctx->value);
Radek Krejci1798aae2020-07-14 13:26:06 +0200795 ret = LY_EVALID;
796 goto cleanup;
797 } else if (is_attr) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200798 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +0200799 "Invalid format of the Metadata identifier in JSON, unexpected '@' in \"%.*s\"",
800 lydctx->jsonctx->value_len, lydctx->jsonctx->value);
Radek Krejci1798aae2020-07-14 13:26:06 +0200801 ret = LY_EVALID;
802 goto cleanup;
803 }
804
805 /* get the element module */
806 mod = ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
807 if (!mod) {
808 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200809 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200810 "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
811 prefix_len, prefix, name_len, name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200812 ret = LY_EVALID;
813 goto cleanup;
814 }
815 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
816 /* skip element with children */
817 ret = lydjson_data_skip(lydctx->jsonctx);
818 LY_CHECK_GOTO(ret, cleanup);
819 status = lyjson_ctx_status(lydctx->jsonctx, 0);
820 /* end of the item */
821 continue;
822 }
823 }
824
825 /* get the value */
826 ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
827 LY_CHECK_GOTO(ret, cleanup);
828
829 if (node->schema) {
830 /* create metadata */
831 meta = NULL;
Michal Vasko22df3f02020-08-24 13:29:22 +0200832 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, &meta, mod, name, name_len, lydctx->jsonctx->value,
Michal Vasko69730152020-10-09 16:30:07 +0200833 lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_PREF_JSON, NULL,
834 LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200835 LY_CHECK_GOTO(ret, cleanup);
836
837 /* add/correct flags */
Michal Vasko49c39d82020-11-06 17:20:27 +0100838 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_options);
Radek Krejci1798aae2020-07-14 13:26:06 +0200839 } else {
840 /* create attribute */
841 struct ly_prefix *val_prefs = NULL;
842 const char *module_name;
843 size_t module_name_len;
844
845 lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
846
847 /* get value prefixes */
848 LY_CHECK_GOTO(ret = lydjson_get_value_prefixes(lydctx->jsonctx->ctx, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &val_prefs), cleanup);
849
850 /* attr2 is always changed to the created attribute */
851 ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len,
Michal Vasko69730152020-10-09 16:30:07 +0200852 &lydctx->jsonctx->dynamic, LYD_JSON, 0, val_prefs, prefix, prefix_len, module_name, module_name_len);
Radek Krejci1798aae2020-07-14 13:26:06 +0200853 LY_CHECK_GOTO(ret, cleanup);
854 }
855 /* next member */
856 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
857 LY_CHECK_GOTO(ret, cleanup);
858 }
859
860 if (nodetype == LYS_LEAFLIST) {
861 /* continue by processing another metadata object for the following
862 * leaf-list instance since they are allways instantiated in JSON array */
863 prev = node;
864 node = node->next;
865 goto next_entry;
866 }
867
868 /* move after the metadata */
869 ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
870 LY_CHECK_GOTO(ret, cleanup);
871
872cleanup:
873 return ret;
874
875representation_error:
Michal Vasko22df3f02020-08-24 13:29:22 +0200876 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +0200877 "The attribute(s) of %s \"%s\" is expected to be represented as JSON %s, but input data contains @%s/%s.",
878 lys_nodetype2str(nodetype), node->schema ? node->schema->name : ((struct lyd_node_opaq *)node)->name,
879 expected, lyjson_token2str(status), in_parent ? "" : "name");
Radek Krejci1798aae2020-07-14 13:26:06 +0200880
881 return LY_EVALID;
882}
883
884/**
885 * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing to the first child node.
886 *
887 * @param[in] parent Parent node to insert to, can be NULL in case of top-level (or provided first_p).
888 * @param[in, out] first_p Pointer to the first sibling node in case of top-level.
889 * @param[in, out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
890 */
891static void
892lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p)
893{
894 if (*node_p) {
895 /* insert, keep first pointer correct */
896 lyd_insert_node((struct lyd_node *)parent, first_p, *node_p);
897 if (first_p) {
898 if (parent) {
899 *first_p = parent->child;
900 } else {
901 while ((*first_p)->prev->next) {
902 *first_p = (*first_p)->prev;
903 }
904 }
905 }
906 *node_p = NULL;
907 }
908}
909
910static LY_ERR lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p);
911
912/**
913 * @brief Parse opaq node from the input.
914 *
915 * In case of processing array, the whole array is being processed and the resulting @p node_p is the last item of the array.
916 *
917 * @param[in] lydctx JSON data parser context.
918 * @param[in] name Name of the opaq node to create.
919 * @param[in] name_len Length of the @p name string.
920 * @param[in] prefix Prefix of the opaq node to create.
921 * @param[in] prefix_len Length of the @p prefx string.
922 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
923 * but must be set if @p first is not.
924 * @param[in,out] status_p Pointer to the current status of the parser context,
925 * since the function manipulates with the context and process the input, the status can be updated.
926 * @param[in,out] status_inner_p In case of processing JSON array, this parameter points to a standalone
927 * context status of the array content. Otherwise, it is supposed to be the same as @p status_p.
928 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
929 * @param[out] node_p Pointer to the created opaq node.
930 * @return LY_ERR value.
931 */
932static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200933lydjson_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
Radek Krejci0f969882020-08-21 16:56:47 +0200934 struct lyd_node_inner *parent, enum LYJSON_PARSER_STATUS *status_p,
935 enum LYJSON_PARSER_STATUS *status_inner_p, struct lyd_node **first_p, struct lyd_node **node_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200936{
937 LY_ERR ret = LY_SUCCESS;
938 const char *value = NULL, *module_name;
939 size_t value_len = 0, module_name_len = 0;
940 struct ly_prefix *val_prefs = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200941 ly_bool dynamic = 0;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200942 uint32_t type_hint = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200943
Michal Vasko69730152020-10-09 16:30:07 +0200944 if ((*status_inner_p != LYJSON_OBJECT) && (*status_inner_p != LYJSON_OBJECT_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200945 /* prepare for creating opaq node with a value */
946 value = lydctx->jsonctx->value;
947 value_len = lydctx->jsonctx->value_len;
948 dynamic = lydctx->jsonctx->dynamic;
949 lydctx->jsonctx->dynamic = 0;
950
951 LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
952
953 if (value) {
954 /* get value prefixes */
955 LY_CHECK_RET(lydjson_get_value_prefixes(lydctx->jsonctx->ctx, value, value_len, &val_prefs));
956 }
957 }
958
959 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200960 lydjson_get_node_prefix((struct lyd_node *)parent, prefix, prefix_len, &module_name, &module_name_len);
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200961 ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, value, value_len, &dynamic, LYD_JSON, type_hint,
962 val_prefs, prefix, prefix_len, module_name, module_name_len, node_p);
Radek Krejci1798aae2020-07-14 13:26:06 +0200963 if (dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200964 free((char *)value);
Radek Krejci1798aae2020-07-14 13:26:06 +0200965 }
Radek Krejcid46e46a2020-09-15 14:22:42 +0200966 LY_CHECK_RET(ret);
Radek Krejci1798aae2020-07-14 13:26:06 +0200967
Michal Vasko69730152020-10-09 16:30:07 +0200968 if ((*status_p == LYJSON_OBJECT) || (*status_p == LYJSON_OBJECT_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200969 /* process children */
970 while (*status_p != LYJSON_OBJECT_CLOSED && *status_p != LYJSON_OBJECT_EMPTY) {
971 LY_CHECK_RET(lydjson_subtree_r(lydctx, (struct lyd_node_inner *)(*node_p), lyd_node_children_p(*node_p)));
972 *status_p = lyjson_ctx_status(lydctx->jsonctx, 0);
973 }
Michal Vasko69730152020-10-09 16:30:07 +0200974 } else if ((*status_p == LYJSON_ARRAY) || (*status_p == LYJSON_ARRAY_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200975 /* process another instance of the same node */
976 /* but first mark the node to be expected a list or a leaf-list */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200977 ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST;
Radek Krejci1798aae2020-07-14 13:26:06 +0200978
Michal Vasko69730152020-10-09 16:30:07 +0200979 if ((*status_inner_p == LYJSON_OBJECT) || (*status_inner_p == LYJSON_OBJECT_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200980 /* but first process children of the object in the array */
981 while (*status_inner_p != LYJSON_OBJECT_CLOSED && *status_inner_p != LYJSON_OBJECT_EMPTY) {
982 LY_CHECK_RET(lydjson_subtree_r(lydctx, (struct lyd_node_inner *)(*node_p), lyd_node_children_p(*node_p)));
983 *status_inner_p = lyjson_ctx_status(lydctx->jsonctx, 0);
984 }
985 }
986
987 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
988
989 /* continue with the next instance */
990 if (*status_inner_p != LYJSON_ARRAY_CLOSED) {
991 assert(node_p);
992 lydjson_maintain_children(parent, first_p, node_p);
993 return lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_p, status_inner_p, first_p, node_p);
994 }
995 }
996
997 /* finish linking metadata */
998 LY_CHECK_RET(lydjson_metadata_finish(lydctx, lyd_node_children_p(*node_p)));
999
1000 /* move after the item */
1001 return lyjson_ctx_next(lydctx->jsonctx, status_p);
1002}
1003
1004/**
1005 * @brief Process the attribute container (starting by @)
1006 *
1007 * @param[in] lydctx JSON data parser context.
1008 * @param[in] attr_node The data node referenced by the attribute container, if already known.
1009 * @param[in] snode The schema node of the data node referenced by the attribute container, if known.
1010 * @param[in] name Name of the opaq node to create.
1011 * @param[in] name_len Length of the @p name string.
1012 * @param[in] prefix Prefix of the opaq node to create.
1013 * @param[in] prefix_len Length of the @p prefx string.
1014 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
1015 * but must be set if @p first is not.
1016 * @param[in,out] status_p Pointer to the current status of the parser context,
1017 * since the function manipulates with the context and process the input, the status can be updated.
1018 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
1019 * @param[out] node_p Pointer to the created opaq node.
1020 * @return LY_ERR value.
1021 */
1022static LY_ERR
1023lydjson_parse_attribute(struct lyd_json_ctx *lydctx, struct lyd_node *attr_node, const struct lysc_node *snode,
Radek Krejci0f969882020-08-21 16:56:47 +02001024 const char *name, size_t name_len, const char *prefix, size_t prefix_len,
1025 struct lyd_node_inner *parent, enum LYJSON_PARSER_STATUS *status_p, struct lyd_node **first_p,
1026 struct lyd_node **node_p)
Radek Krejci1798aae2020-07-14 13:26:06 +02001027{
1028 LY_ERR ret = LY_SUCCESS;
1029 enum LYJSON_PARSER_STATUS status_inner;
1030
1031 /* parse as an attribute to a node */
1032 if (!attr_node && snode) {
1033 /* try to find the instance */
1034 for (struct lyd_node *iter = *first_p; iter; iter = iter->next) {
1035 if (iter->schema == snode) {
1036 attr_node = iter;
1037 break;
1038 }
1039 }
1040 }
1041 if (!attr_node) {
1042 /* parse just as an opaq node with the name beginning with @,
1043 * later we have to check that it belongs to a standard node
1044 * and it is supposed to be converted to a metadata */
1045 uint32_t prev_opts;
1046
1047 /* move into metadata */
1048 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
1049
1050 if (*status_p == LYJSON_ARRAY) {
1051 /* move into the array */
1052 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, &status_inner));
1053 } else {
1054 /* just a flag to pass correct parameters into lydjson_parse_opaq() */
1055 status_inner = LYJSON_ERROR;
1056 }
1057
1058 /* backup parser options to parse unknown metadata as opaq nodes and try to resolve them later */
1059 prev_opts = lydctx->parse_options;
1060 lydctx->parse_options &= ~LYD_PARSE_STRICT;
1061 lydctx->parse_options |= LYD_PARSE_OPAQ;
1062
1063 ret = lydjson_parse_opaq(lydctx, prefix ? prefix - 1 : name - 1, prefix ? prefix_len + name_len + 2 : name_len + 1,
Michal Vasko69730152020-10-09 16:30:07 +02001064 NULL, 0, parent, status_p, status_inner == LYJSON_ERROR ? status_p : &status_inner, first_p, node_p);
Radek Krejci1798aae2020-07-14 13:26:06 +02001065
1066 /* restore the parser options */
1067 lydctx->parse_options = prev_opts;
1068 } else {
1069 ret = lydjson_metadata(lydctx, snode, attr_node);
1070 }
1071
1072 return ret;
1073}
1074
1075/**
Michal Vasko32ac9942020-08-12 14:35:12 +02001076 * @brief Parse a single instance of a node.
1077 *
1078 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
1079 * as before calling, despite it is necessary to process input data for checking.
1080 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
1081 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
1082 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
1083 * @param[in] name Parsed JSON node name.
1084 * @param[in] name_len Lenght of @p name.
1085 * @param[in] prefix Parsed JSON node prefix.
1086 * @param[in] prefix_len Length of @p prefix.
1087 * @param[in,out] status JSON parser status, is updated.
1088 * @param[out] node Parsed data (or opaque) node.
1089 * @return LY_SUCCESS if a node was successfully parsed,
1090 * @return LY_EINVAL in case of invalid JSON encoding,
1091 * @return LY_ERR on other errors.
1092 */
1093static LY_ERR
1094lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p,
Radek Krejci0f969882020-08-21 16:56:47 +02001095 const struct lysc_node *snode, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
1096 enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
Michal Vasko32ac9942020-08-12 14:35:12 +02001097{
1098 LY_ERR ret;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001099 uint32_t type_hints = 0;
Michal Vasko32ac9942020-08-12 14:35:12 +02001100 uint32_t prev_opts;
1101 struct lyd_node *tree = NULL;
1102
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001103 ret = lydjson_data_check_opaq(lydctx, snode, &type_hints);
Michal Vasko32ac9942020-08-12 14:35:12 +02001104 if (ret == LY_SUCCESS) {
1105 assert(snode->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER | LYD_NODE_ANY));
1106 if (snode->nodetype & LYD_NODE_TERM) {
1107 /* create terminal node */
1108 ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, lydctx->jsonctx->value,
Michal Vasko69730152020-10-09 16:30:07 +02001109 lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_PREF_JSON, NULL,
1110 type_hints, node);
Michal Vasko32ac9942020-08-12 14:35:12 +02001111 LY_CHECK_RET(ret);
1112
1113 /* move JSON parser */
1114 ret = lyjson_ctx_next(lydctx->jsonctx, status);
1115 LY_CHECK_RET(ret);
1116 } else if (snode->nodetype & LYD_NODE_INNER) {
1117 /* create inner node */
1118 LY_CHECK_RET(*status != LYJSON_OBJECT && *status != LYJSON_OBJECT_EMPTY, LY_EINVAL);
1119
1120 ret = lyd_create_inner(snode, node);
1121 LY_CHECK_RET(ret);
1122
1123 /* process children */
1124 while (*status != LYJSON_OBJECT_CLOSED && *status != LYJSON_OBJECT_EMPTY) {
1125 ret = lydjson_subtree_r(lydctx, (struct lyd_node_inner *)*node, lyd_node_children_p(*node));
1126 LY_CHECK_RET(ret);
1127 *status = lyjson_ctx_status(lydctx->jsonctx, 0);
1128 }
1129
1130 /* finish linking metadata */
1131 ret = lydjson_metadata_finish(lydctx, lyd_node_children_p(*node));
1132 LY_CHECK_RET(ret);
1133
1134 if (snode->nodetype == LYS_LIST) {
1135 /* check all keys exist */
1136 ret = lyd_parse_check_keys(*node);
1137 LY_CHECK_RET(ret);
1138 }
1139
1140 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
1141 /* new node validation, autodelete CANNOT occur, all nodes are new */
1142 ret = lyd_validate_new(lyd_node_children_p(*node), snode, NULL, NULL);
1143 LY_CHECK_RET(ret);
1144
1145 /* add any missing default children */
Michal Vasko49c39d82020-11-06 17:20:27 +01001146 ret = lyd_new_implicit_r(*node, lyd_node_children_p(*node), NULL, NULL, &lydctx->node_types,
1147 &lydctx->node_when, (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ?
Michal Vasko69730152020-10-09 16:30:07 +02001148 LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vasko32ac9942020-08-12 14:35:12 +02001149 LY_CHECK_RET(ret);
1150 }
1151
1152 /* move JSON parser */
1153 ret = lyjson_ctx_next(lydctx->jsonctx, status);
1154 LY_CHECK_RET(ret);
1155 } else if (snode->nodetype & LYD_NODE_ANY) {
1156 /* create any node */
1157 LY_CHECK_RET(*status != LYJSON_OBJECT && *status != LYJSON_OBJECT_EMPTY, LY_EINVAL);
1158
1159 /* parse any data tree with correct options */
1160 /* first backup the current options and then make the parser to process data as opaq nodes */
1161 prev_opts = lydctx->parse_options;
1162 lydctx->parse_options &= ~LYD_PARSE_STRICT;
1163 lydctx->parse_options |= LYD_PARSE_OPAQ;
1164
1165 /* process the anydata content */
1166 while (*status != LYJSON_OBJECT_CLOSED && *status != LYJSON_OBJECT_EMPTY) {
1167 ret = lydjson_subtree_r(lydctx, NULL, &tree);
1168 LY_CHECK_RET(ret);
1169 *status = lyjson_ctx_status(lydctx->jsonctx, 0);
1170 }
1171
1172 /* restore parser options */
1173 lydctx->parse_options = prev_opts;
1174
1175 /* finish linking metadata */
1176 ret = lydjson_metadata_finish(lydctx, &tree);
1177 LY_CHECK_RET(ret);
1178
1179 ret = lyd_create_any(snode, tree, LYD_ANYDATA_DATATREE, node);
1180 LY_CHECK_RET(ret);
1181 }
1182 } else if (ret == LY_ENOT) {
1183 /* parse it again as an opaq node */
1184 ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent,
Michal Vasko69730152020-10-09 16:30:07 +02001185 status, status, first_p, node);
Michal Vasko32ac9942020-08-12 14:35:12 +02001186 LY_CHECK_RET(ret);
1187
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001188 if (snode->nodetype == LYS_LIST) {
1189 ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LIST;
1190 } else if (snode->nodetype == LYS_LEAFLIST) {
1191 ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LEAFLIST;
Michal Vasko32ac9942020-08-12 14:35:12 +02001192 }
1193 }
1194
1195 return ret;
1196}
1197
1198/**
Michal Vaskoa5da3292020-08-12 13:10:50 +02001199 * @brief Parse JSON subtree. All leaf-list and list instances of a node are considered one subtree.
Radek Krejci1798aae2020-07-14 13:26:06 +02001200 *
1201 * @param[in] lydctx JSON data parser context.
1202 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
1203 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
1204 * @return LY_ERR value.
1205 */
1206static LY_ERR
1207lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
1208{
1209 LY_ERR ret = LY_SUCCESS;
1210 enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx, 0);
1211 enum LYJSON_PARSER_STATUS status_inner = 0;
1212 const char *name, *prefix = NULL;
1213 size_t name_len, prefix_len = 0;
Radek Krejci857189e2020-09-01 13:26:36 +02001214 ly_bool is_meta = 0;
Michal Vaskocabe0702020-08-12 10:14:36 +02001215 const struct lysc_node *snode = NULL;
Michal Vasko32ac9942020-08-12 14:35:12 +02001216 struct lyd_node *node = NULL, *attr_node = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001217 const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
1218 const char *expected = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001219
1220 assert(parent || first_p);
1221 assert(status == LYJSON_OBJECT);
1222
1223 /* process the node name */
Michal Vaskocabe0702020-08-12 10:14:36 +02001224 lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_meta);
Radek Krejci1798aae2020-07-14 13:26:06 +02001225
Michal Vaskocabe0702020-08-12 10:14:36 +02001226 if (!is_meta || name_len || prefix_len) {
1227 /* get the schema node */
1228 ret = lydjson_get_snode(lydctx, is_meta, prefix, prefix_len, name, name_len, parent, &snode);
1229 if (ret == LY_ENOT) {
1230 /* skip element with children */
1231 ret = lydjson_data_skip(lydctx->jsonctx);
1232 LY_CHECK_GOTO(ret, cleanup);
1233 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1234 /* nothing for now, continue with another call of lydjson_subtree_r() */
Radek Krejci1798aae2020-07-14 13:26:06 +02001235 goto cleanup;
1236 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001237 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001238
Michal Vaskocabe0702020-08-12 10:14:36 +02001239 if (!snode) {
1240 /* we will not be parsing it as metadata */
1241 is_meta = 0;
1242 }
1243 }
1244
1245 if (is_meta) {
1246 /* parse as metadata */
1247 if (!name_len && !prefix_len) {
1248 /* parent's metadata without a name - use the schema from the parent */
1249 if (!parent) {
1250 LOGVAL(ctx, LY_VLOG_LYD, NULL, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +02001251 "Invalid metadata format - \"@\" can be used only inside anydata, container or list entries.");
Michal Vaskocabe0702020-08-12 10:14:36 +02001252 ret = LY_EVALID;
1253 goto cleanup;
1254 }
1255 attr_node = (struct lyd_node *)parent;
1256 snode = attr_node->schema;
1257 }
1258 ret = lydjson_parse_attribute(lydctx, attr_node, snode, name, name_len, prefix, prefix_len, parent, &status,
Michal Vasko69730152020-10-09 16:30:07 +02001259 first_p, &node);
Michal Vaskocabe0702020-08-12 10:14:36 +02001260 LY_CHECK_GOTO(ret, cleanup);
1261 } else if (!snode) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001262 /* parse as an opaq node */
1263 assert((lydctx->parse_options & LYD_PARSE_OPAQ) || (lydctx->int_opts));
1264
1265 /* move to the second item in the name/X pair */
1266 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1267 LY_CHECK_GOTO(ret, cleanup);
1268
1269 if (status == LYJSON_ARRAY) {
1270 /* move into the array */
1271 ret = lyjson_ctx_next(lydctx->jsonctx, &status_inner);
1272 LY_CHECK_GOTO(ret, cleanup);
1273 } else {
1274 /* just a flag to pass correct parameters into lydjson_parse_opaq() */
1275 status_inner = LYJSON_ERROR;
1276 }
1277
1278 ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len,
Michal Vasko69730152020-10-09 16:30:07 +02001279 parent, &status, status_inner == LYJSON_ERROR ? &status : &status_inner, first_p, &node);
Radek Krejci1798aae2020-07-14 13:26:06 +02001280 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskocabe0702020-08-12 10:14:36 +02001281 } else {
Michal Vasko32ac9942020-08-12 14:35:12 +02001282 /* parse as a standard lyd_node but it can still turn out to be an opaque node */
Radek Krejci1798aae2020-07-14 13:26:06 +02001283
1284 /* move to the second item in the name/X pair */
1285 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1286 LY_CHECK_GOTO(ret, cleanup);
1287
1288 /* first check the expected representation according to the nodetype and then continue with the content */
1289 switch (snode->nodetype) {
1290 case LYS_LEAFLIST:
Michal Vasko32ac9942020-08-12 14:35:12 +02001291 case LYS_LIST:
1292 if (snode->nodetype == LYS_LEAFLIST) {
1293 expected = "name/array of values";
1294 } else {
1295 expected = "name/array of objects";
1296 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001297
1298 LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
1299
1300 /* move into array */
1301 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1302 LY_CHECK_GOTO(ret, cleanup);
1303
Michal Vasko32ac9942020-08-12 14:35:12 +02001304 /* process all the values/objects */
1305 do {
1306 lydjson_maintain_children(parent, first_p, &node);
Radek Krejci1798aae2020-07-14 13:26:06 +02001307
Michal Vasko32ac9942020-08-12 14:35:12 +02001308 ret = lydjson_parse_instance(lydctx, parent, first_p, snode, name, name_len, prefix, prefix_len,
Michal Vasko69730152020-10-09 16:30:07 +02001309 &status, &node);
Michal Vasko32ac9942020-08-12 14:35:12 +02001310 if (ret == LY_EINVAL) {
1311 goto representation_error;
1312 } else if (ret) {
1313 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001314 }
Michal Vasko32ac9942020-08-12 14:35:12 +02001315 } while (status != LYJSON_ARRAY_CLOSED);
Radek Krejci1798aae2020-07-14 13:26:06 +02001316
Michal Vasko32ac9942020-08-12 14:35:12 +02001317 /* move after the array */
1318 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1319 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001320
1321 break;
Michal Vasko32ac9942020-08-12 14:35:12 +02001322 case LYS_LEAF:
Radek Krejci1798aae2020-07-14 13:26:06 +02001323 case LYS_CONTAINER:
1324 case LYS_NOTIF:
1325 case LYS_ACTION:
1326 case LYS_RPC:
Michal Vasko32ac9942020-08-12 14:35:12 +02001327 case LYS_ANYDATA:
1328 case LYS_ANYXML:
1329 if (snode->nodetype == LYS_LEAF) {
1330 if (status == LYJSON_ARRAY) {
1331 expected = "name/[null]";
1332 } else {
1333 expected = "name/value";
1334 }
1335 } else {
Radek Krejci1798aae2020-07-14 13:26:06 +02001336 expected = "name/object";
1337 }
1338
Michal Vasko32ac9942020-08-12 14:35:12 +02001339 /* process the value/object */
1340 ret = lydjson_parse_instance(lydctx, parent, first_p, snode, name, name_len, prefix, prefix_len, &status, &node);
1341 if (ret == LY_EINVAL) {
1342 goto representation_error;
1343 } else if (ret) {
1344 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001345 }
1346
Michal Vasko32ac9942020-08-12 14:35:12 +02001347 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001348 /* rememeber the RPC/action/notification */
1349 lydctx->op_node = node;
1350 }
1351
1352 break;
Radek Krejci1798aae2020-07-14 13:26:06 +02001353 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001354 }
1355
Michal Vasko32ac9942020-08-12 14:35:12 +02001356 /* finally connect the parsed node */
Radek Krejci1798aae2020-07-14 13:26:06 +02001357 lydjson_maintain_children(parent, first_p, &node);
1358
1359cleanup:
1360 lyd_free_tree(node);
1361 return ret;
1362
1363representation_error:
1364 LOGVAL(ctx, LY_VLOG_LYD, parent, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +02001365 "The %s \"%s\" is expected to be represented as JSON %s, but input data contains name/%s.",
1366 lys_nodetype2str(snode->nodetype), snode->name, expected, lyjson_token2str(status));
Radek Krejci1798aae2020-07-14 13:26:06 +02001367
1368 ret = LY_EVALID;
1369 goto cleanup;
1370}
1371
1372/**
1373 * @brief Common start of JSON parser processing different types of the input data.
1374 *
1375 * @param[in] ctx libyang context
1376 * @param[in] in Input structure.
1377 * @param[in] parse_options Options for parser, see @ref dataparseroptions.
1378 * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
1379 * @param[out] lydctx_p Data parser context to finish validation.
1380 * @return LY_ERR value.
1381 */
1382static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001383lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_options, uint32_t validate_options,
Radek Krejci0f969882020-08-21 16:56:47 +02001384 struct lyd_json_ctx **lydctx_p)
Radek Krejci1798aae2020-07-14 13:26:06 +02001385{
1386 LY_ERR ret = LY_SUCCESS;
1387 struct lyd_json_ctx *lydctx;
1388 size_t i, line = 1;
1389
Radek Krejci1798aae2020-07-14 13:26:06 +02001390 /* init context */
1391 lydctx = calloc(1, sizeof *lydctx);
1392 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1393 lydctx->parse_options = parse_options;
1394 lydctx->validate_options = validate_options;
1395 lydctx->free = lyd_json_ctx_free;
Radek Krejci1798aae2020-07-14 13:26:06 +02001396
Radek Krejci284f31f2020-09-18 15:40:29 +02001397 /* starting top-level */
1398 for (i = 0; in->current[i] != '\0' && is_jsonws(in->current[i]); i++) {
1399 if (in->current[i] == 0x0a) { /* new line */
1400 line++;
Michal Vasko61d76362020-10-07 10:47:30 +02001401 }
Radek Krejci284f31f2020-09-18 15:40:29 +02001402 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001403
Radek Krejci284f31f2020-09-18 15:40:29 +02001404 LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
1405 if (lyjson_ctx_status(lydctx->jsonctx, 0) == LYJSON_END) {
1406 /* empty data input */
1407 *lydctx_p = lydctx;
1408 return LY_SUCCESS;
1409 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001410 *lydctx_p = lydctx;
1411 return LY_SUCCESS;
1412}
1413
1414LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001415lyd_parse_json_data(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_options, uint32_t validate_options,
Radek Krejci0f969882020-08-21 16:56:47 +02001416 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejci1798aae2020-07-14 13:26:06 +02001417{
1418 LY_ERR ret = LY_SUCCESS;
1419 struct lyd_json_ctx *lydctx = NULL;
1420 enum LYJSON_PARSER_STATUS status;
1421
1422 assert(tree_p);
1423 *tree_p = NULL;
1424
1425 ret = lyd_parse_json_init(ctx, in, parse_options, validate_options, &lydctx);
Radek Krejci284f31f2020-09-18 15:40:29 +02001426 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001427
1428 status = lyjson_ctx_status(lydctx->jsonctx, 0);
Michal Vasko48cec8c2020-10-20 16:38:07 +02001429 LY_CHECK_GOTO(status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
1430 assert((status == LYJSON_OBJECT));
Radek Krejci1798aae2020-07-14 13:26:06 +02001431
1432 /* read subtree(s) */
1433 while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
1434 ret = lydjson_subtree_r(lydctx, NULL, tree_p);
1435 LY_CHECK_GOTO(ret, cleanup);
1436
1437 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1438 }
1439
1440 /* finish linking metadata */
1441 ret = lydjson_metadata_finish(lydctx, tree_p);
1442 LY_CHECK_GOTO(ret, cleanup);
1443
1444cleanup:
1445 /* there should be no unresolved types stored */
Michal Vasko49c39d82020-11-06 17:20:27 +01001446 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1447 !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001448
1449 if (ret) {
1450 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1451 lyd_free_all(*tree_p);
1452 *tree_p = NULL;
1453 } else {
1454 *lydctx_p = (struct lyd_ctx *)lydctx;
1455 }
1456
1457 return ret;
1458}
1459
1460/**
1461 * @brief Parse optional JSON envelope around the Notification data, including the eventTime data.
1462 *
1463 * @param[in] jsonctx JSON parser context
1464 * @param[out] envp_p Pointer to the created envelope opaq container.
1465 * @return LY_SUCCESS if the envelope present and successfully parsed.
1466 * @return LY_ENOT in case there is not the expected envelope.
1467 * @return LY_ERR in case of parsing failure.
1468 */
1469static LY_ERR
1470lydjson_notif_envelope(struct lyjson_ctx *jsonctx, struct lyd_node **envp_p)
1471{
1472 LY_ERR ret = LY_ENOT, r;
1473 const char *name, *prefix, *value = NULL;
1474 size_t name_len, prefix_len, value_len;
Radek Krejci857189e2020-09-01 13:26:36 +02001475 ly_bool is_attr, dynamic = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +02001476 enum LYJSON_PARSER_STATUS status;
1477 struct lyd_node *et;
1478
1479 *envp_p = NULL;
1480
1481 /* backup the context */
1482 lyjson_ctx_backup(jsonctx);
1483
1484 /* "notification" envelope */
1485 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
1486 LY_CHECK_GOTO(is_attr, cleanup);
1487 LY_CHECK_GOTO(prefix_len != 13 || strncmp(prefix, "ietf-restconf", 13), cleanup);
1488 LY_CHECK_GOTO(name_len != 12 || strncmp(name, "notification", name_len), cleanup);
1489
1490 r = lyjson_ctx_next(jsonctx, &status);
1491 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
1492 LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
1493
1494 /* "eventTime" child */
1495 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
1496 LY_CHECK_GOTO(prefix_len || is_attr, cleanup);
1497 LY_CHECK_GOTO(name_len != 9 || strncmp(name, "eventTime", name_len), cleanup);
1498
1499 /* go for the data */
1500 r = lyjson_ctx_next(jsonctx, &status);
1501 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
1502 LY_CHECK_GOTO(status != LYJSON_STRING, cleanup);
1503
1504 value = jsonctx->value;
1505 value_len = jsonctx->value_len;
1506 dynamic = jsonctx->dynamic;
1507 jsonctx->dynamic = 0;
1508
1509 r = lyjson_ctx_next(jsonctx, &status);
1510 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
1511 LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
1512 /* now the notificationContent is expected, which will be parsed by the caller */
1513
1514 /* create notification envelope */
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001515 ret = lyd_create_opaq(jsonctx->ctx, "notification", 12, "", 0, NULL, LYD_JSON, LYD_NODEHINT_ENVELOPE, NULL, NULL,
Michal Vasko69730152020-10-09 16:30:07 +02001516 0, "ietf-restconf", 13, envp_p);
Radek Krejci1798aae2020-07-14 13:26:06 +02001517 LY_CHECK_GOTO(ret, cleanup);
1518 /* create notification envelope */
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001519 ret = lyd_create_opaq(jsonctx->ctx, "eventTime", 9, value, value_len, &dynamic, LYD_JSON, LYD_VALHINT_STRING, NULL,
Michal Vasko69730152020-10-09 16:30:07 +02001520 NULL, 0, "ietf-restconf", 13, &et);
Radek Krejci1798aae2020-07-14 13:26:06 +02001521 LY_CHECK_GOTO(ret, cleanup);
1522 /* insert eventTime into notification */
1523 lyd_insert_node(*envp_p, NULL, et);
1524
1525 ret = LY_SUCCESS;
1526cleanup:
1527 if (ret) {
1528 /* restore the context */
1529 lyjson_ctx_restore(jsonctx);
1530 if (dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +02001531 free((char *)value);
Radek Krejci1798aae2020-07-14 13:26:06 +02001532 }
1533 }
1534 return ret;
1535}
1536
1537LY_ERR
1538lyd_parse_json_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
1539{
1540 LY_ERR ret = LY_SUCCESS;
1541 struct lyd_json_ctx *lydctx = NULL;
1542 struct lyd_node *ntf_e = NULL;
1543 struct lyd_node *tree = NULL;
1544 enum LYJSON_PARSER_STATUS status;
1545
1546 /* init */
1547 ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
1548 LY_CHECK_GOTO(ret || !lydctx, cleanup);
1549 lydctx->int_opts = LYD_INTOPT_NOTIF;
1550
1551 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1552 assert(status == LYJSON_OBJECT);
1553
1554 /* parse "notification" and "eventTime", if present */
1555 ret = lydjson_notif_envelope(lydctx->jsonctx, &ntf_e);
1556 if (ret == LY_ENOT) {
1557 ret = LY_SUCCESS;
1558 } else if (ret) {
1559 goto cleanup;
1560 }
1561
Michal Vaskocf770e22020-08-12 13:21:43 +02001562 /* read subtree */
1563 ret = lydjson_subtree_r(lydctx, NULL, &tree);
1564 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001565
1566 /* finish linking metadata */
1567 ret = lydjson_metadata_finish(lydctx, &tree);
1568 LY_CHECK_GOTO(ret, cleanup);
1569
1570 /* make sure we have parsed some notification */
1571 if (!lydctx->op_node) {
1572 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1573 ret = LY_EVALID;
1574 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02001575 } else if (lydctx->jsonctx->in->current[0] && (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_OBJECT_CLOSED)) {
Michal Vaskocf770e22020-08-12 13:21:43 +02001576 LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02001577 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +02001578 ret = LY_EVALID;
1579 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001580 }
1581
1582 if (ntf_e) {
1583 /* finish notification envelope */
1584 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1585 LY_CHECK_GOTO(ret, cleanup);
1586 if (status == LYJSON_END) {
1587 LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LY_VCODE_EOF);
1588 ret = LY_EVALID;
1589 goto cleanup;
1590 } else if (status != LYJSON_OBJECT_CLOSED) {
1591 LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LYVE_SYNTAX, "Unexpected sibling member \"%.*s\" of \"notification\".",
Michal Vasko69730152020-10-09 16:30:07 +02001592 lydctx->jsonctx->value_len, lydctx->jsonctx->value);
Radek Krejci1798aae2020-07-14 13:26:06 +02001593 ret = LY_EVALID;
1594 goto cleanup;
1595 }
1596 }
1597
1598 if (ntf_p) {
1599 *ntf_p = lydctx->op_node;
1600 }
1601 assert(tree);
Radek Krejci1798aae2020-07-14 13:26:06 +02001602 if (ntf_e) {
1603 /* connect to the notification */
Michal Vasko4189c0f2020-08-13 09:05:22 +02001604 lyd_insert_node(ntf_e, NULL, tree);
1605 tree = ntf_e;
1606 }
1607 if (tree_p) {
1608 *tree_p = tree;
Radek Krejci1798aae2020-07-14 13:26:06 +02001609 }
1610
1611cleanup:
1612 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +01001613 assert(!lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count && !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001614
1615 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1616 if (ret) {
1617 lyd_free_all(tree);
1618 lyd_free_tree(ntf_e);
1619 }
1620 return ret;
1621}
1622
1623/**
1624 * @brief Parse optional JSON envelope around the processed content.
1625 *
1626 * @param[in] jsonctx JSON parser context
1627 * @param[in] parent Parent node (some other envelope).
1628 * @param[in] module_key Name of the module where the envelope element is expected.
1629 * @param[in] object_id Name of the envelope object.
1630 * @param[out] envp_p Pointer to the created envelope opaq container.
1631 * @return LY_SUCCESS if the envelope present and successfully parsed.
1632 * @return LY_ENOT in case there is not the expected envelope.
1633 * @return LY_ERR in case of parsing failure.
1634 */
1635static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +02001636lydjson_object_envelope(struct lyjson_ctx *jsonctx, struct lyd_node *parent, const char *module_key,
Radek Krejci0f969882020-08-21 16:56:47 +02001637 const char *object_id, struct lyd_node **envp_p)
Radek Krejci1798aae2020-07-14 13:26:06 +02001638{
1639 LY_ERR ret = LY_ENOT, r;
1640 const char *name, *prefix;
1641 size_t name_len, prefix_len;
Radek Krejci857189e2020-09-01 13:26:36 +02001642 ly_bool is_attr;
Radek Krejci1798aae2020-07-14 13:26:06 +02001643 enum LYJSON_PARSER_STATUS status;
1644
1645 *envp_p = NULL;
1646
1647 /* "id" envelope */
1648 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
1649 LY_CHECK_GOTO(is_attr, cleanup);
1650 LY_CHECK_GOTO(lydjson_get_node_prefix(parent, prefix, prefix_len, &prefix, &prefix_len), cleanup);
1651 LY_CHECK_GOTO(prefix_len != strlen(module_key) || strncmp(prefix, module_key, prefix_len), cleanup);
1652 LY_CHECK_GOTO(name_len != strlen(object_id) || strncmp(name, object_id, name_len), cleanup);
1653
1654 r = lyjson_ctx_next(jsonctx, &status);
1655 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
1656 LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
1657
1658 /* create the object envelope */
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001659 ret = lyd_create_opaq(jsonctx->ctx, object_id, strlen(object_id), "", 0, NULL, LYD_JSON, LYD_NODEHINT_ENVELOPE,
Michal Vasko69730152020-10-09 16:30:07 +02001660 NULL, NULL, 0, module_key, ly_strlen(module_key), envp_p);
Radek Krejci1798aae2020-07-14 13:26:06 +02001661 LY_CHECK_GOTO(ret, cleanup);
1662
1663 if (parent) {
1664 lyd_insert_node(parent, NULL, *envp_p);
1665 }
1666
1667 ret = LY_SUCCESS;
1668cleanup:
1669 return ret;
1670}
1671
1672static LY_ERR
1673lydjson_object_envelope_close(struct lyjson_ctx *jsonctx, const char *object_id)
1674{
1675 enum LYJSON_PARSER_STATUS status;
1676
1677 LY_CHECK_RET(lyjson_ctx_next(jsonctx, &status));
1678 if (status == LYJSON_END) {
1679 LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LY_VCODE_EOF);
1680 return LY_EVALID;
1681 } else if (status != LYJSON_OBJECT_CLOSED) {
1682 LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LYVE_SYNTAX, "Unexpected sibling member \"%.*s\" of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02001683 jsonctx->value_len, jsonctx->value, object_id);
Radek Krejci1798aae2020-07-14 13:26:06 +02001684 return LY_EVALID;
1685 }
1686 return LY_SUCCESS;
1687}
1688
1689LY_ERR
1690lyd_parse_json_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
1691{
1692 LY_ERR ret = LY_SUCCESS;
1693 struct lyd_json_ctx *lydctx = NULL;
1694 struct lyd_node *rpc_e = NULL, *act_e = NULL;
1695 struct lyd_node *tree = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001696
1697 /* init */
1698 ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
1699 LY_CHECK_GOTO(ret || !lydctx, cleanup);
1700 lydctx->int_opts = LYD_INTOPT_RPC;
1701
1702 /* process envelope(s), if present */
1703
1704 /* process rpc */
1705 ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc", &rpc_e);
1706 if (ret == LY_ENOT) {
1707 ret = LY_SUCCESS;
1708 goto parse_content;
1709 } else if (ret) {
1710 goto cleanup;
1711 }
1712 /* process action */
1713 ret = lydjson_object_envelope(lydctx->jsonctx, rpc_e, "yang", "action", &act_e);
1714 if (ret == LY_ENOT) {
1715 ret = LY_SUCCESS;
1716 goto parse_content;
1717 } else if (ret) {
1718 goto cleanup;
1719 }
1720
1721parse_content:
Radek Krejci2b18bf12020-11-06 11:20:20 +01001722 assert(lyjson_ctx_status(lydctx->jsonctx, 0) == LYJSON_OBJECT);
Radek Krejci1798aae2020-07-14 13:26:06 +02001723
1724 /* read subtree(s) */
Michal Vasko22df3f02020-08-24 13:29:22 +02001725 ret = lydjson_subtree_r(lydctx, act_e ? (struct lyd_node_inner *)act_e : (struct lyd_node_inner *)rpc_e, &tree);
Michal Vaskocf770e22020-08-12 13:21:43 +02001726 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001727
1728 /* finish linking metadata */
1729 ret = lydjson_metadata_finish(lydctx, &tree);
1730 LY_CHECK_GOTO(ret, cleanup);
1731
1732 /* make sure we have parsed some operation */
1733 if (!lydctx->op_node) {
1734 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the %s node.",
Michal Vasko69730152020-10-09 16:30:07 +02001735 act_e ? "action" : (rpc_e ? "rpc" : "rpc/action"));
Radek Krejci1798aae2020-07-14 13:26:06 +02001736 ret = LY_EVALID;
1737 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02001738 } else if (lydctx->jsonctx->in->current[0] && (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_OBJECT_CLOSED)) {
Michal Vaskocf770e22020-08-12 13:21:43 +02001739 LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02001740 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +02001741 ret = LY_EVALID;
1742 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001743 }
1744
1745 if (act_e) {
1746 /* finish action envelope */
1747 ret = lydjson_object_envelope_close(lydctx->jsonctx, "action");
1748 LY_CHECK_GOTO(ret, cleanup);
1749 if (lydctx->op_node->schema->nodetype != LYS_ACTION) {
1750 LOGVAL(ctx, LY_VLOG_LYD, lydctx->op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
Michal Vasko69730152020-10-09 16:30:07 +02001751 lys_nodetype2str(lydctx->op_node->schema->nodetype));
Radek Krejci1798aae2020-07-14 13:26:06 +02001752 ret = LY_EVALID;
1753 goto cleanup;
1754 }
1755 }
1756 if (rpc_e) {
1757 /* finish rpc envelope */
1758 ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc");
1759 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko69730152020-10-09 16:30:07 +02001760 if (!act_e && (lydctx->op_node->schema->nodetype != LYS_RPC)) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001761 LOGVAL(ctx, LY_VLOG_LYD, lydctx->op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
Michal Vasko69730152020-10-09 16:30:07 +02001762 lys_nodetype2str(lydctx->op_node->schema->nodetype));
Radek Krejci1798aae2020-07-14 13:26:06 +02001763 ret = LY_EVALID;
1764 goto cleanup;
1765 }
1766 }
1767
1768 if (op_p) {
1769 *op_p = lydctx->op_node;
1770 }
1771 assert(tree);
1772 if (tree_p) {
1773 if (rpc_e) {
1774 *tree_p = rpc_e;
1775 } else if (act_e) {
1776 *tree_p = act_e;
1777 } else {
1778 *tree_p = tree;
1779 }
1780 }
1781
1782cleanup:
1783 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +01001784 assert(!lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count && !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001785
1786 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1787 if (ret) {
1788 lyd_free_all(tree);
1789 lyd_free_tree(act_e);
1790 lyd_free_tree(rpc_e);
1791 }
1792 return ret;
1793}
1794
1795LY_ERR
1796lyd_parse_json_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
1797{
1798 LY_ERR ret = LY_SUCCESS;
1799 struct lyd_json_ctx *lydctx = NULL;
Michal Vasko4189c0f2020-08-13 09:05:22 +02001800 struct lyd_node *rpcr_e = NULL, *tree, *req_op, *rep_op = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001801 enum LYJSON_PARSER_STATUS status;
1802
1803 /* init */
Michal Vaskob7be7a82020-08-20 09:09:04 +02001804 ret = lyd_parse_json_init(LYD_CTX(request), in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
Radek Krejci1798aae2020-07-14 13:26:06 +02001805 LY_CHECK_GOTO(ret || !lydctx, cleanup);
1806 lydctx->int_opts = LYD_INTOPT_REPLY;
1807
1808 /* find request OP */
1809 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
1810 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1811 break;
1812 }
1813 LYD_TREE_DFS_END(request, req_op);
1814 }
1815 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +02001816 LOGERR(LYD_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
Radek Krejci1798aae2020-07-14 13:26:06 +02001817 ret = LY_EINVAL;
1818 goto cleanup;
1819 }
1820
1821 /* duplicate request OP with parents */
1822 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
1823
1824 /* parse "rpc-reply", if any */
1825 ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc-reply", &rpcr_e);
1826 if (ret == LY_ENOT) {
1827 ret = LY_SUCCESS;
1828 } else if (ret) {
1829 goto cleanup;
1830 }
1831
1832 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1833 assert(status == LYJSON_OBJECT);
1834
1835 /* read subtree(s) */
1836 while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
Michal Vasko22df3f02020-08-24 13:29:22 +02001837 ret = lydjson_subtree_r(lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op));
Radek Krejci1798aae2020-07-14 13:26:06 +02001838 LY_CHECK_GOTO(ret, cleanup);
1839
1840 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1841 }
1842
1843 /* finish linking metadata */
1844 ret = lydjson_metadata_finish(lydctx, lyd_node_children_p(rep_op));
1845 LY_CHECK_GOTO(ret, cleanup);
1846
1847 if (rpcr_e) {
1848 /* finish rpc-reply envelope */
1849 ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc-reply");
1850 LY_CHECK_GOTO(ret, cleanup);
1851 }
1852
1853 if (op_p) {
1854 *op_p = rep_op;
1855 }
Radek Krejcia1c1e542020-09-29 16:06:52 +02001856 for (tree = rep_op; tree->parent; tree = lyd_parent(tree)) {}
Radek Krejci1798aae2020-07-14 13:26:06 +02001857 if (rpcr_e) {
1858 /* connect to the operation */
Michal Vasko4189c0f2020-08-13 09:05:22 +02001859 lyd_insert_node(rpcr_e, NULL, tree);
1860 tree = rpcr_e;
1861 }
1862 if (tree_p) {
1863 *tree_p = tree;
Radek Krejci1798aae2020-07-14 13:26:06 +02001864 }
1865
1866cleanup:
1867 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +01001868 assert(!lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count && !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001869
1870 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1871 if (ret) {
1872 lyd_free_all(rep_op);
1873 lyd_free_tree(rpcr_e);
1874 }
1875 return ret;
Michal Vasko90932a92020-02-12 14:33:03 +01001876}