blob: 241ce99d31b3d2deaaf47340c60b1b116e86145a [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;
Michal Vaskoad92b672020-11-12 13:11:31 +0100162 if (onode->name.module_name) {
163 *prefix_p = onode->name.module_name;
Radek Krejci1798aae2020-07-14 13:26:06 +0200164 break;
Michal Vaskoad92b672020-11-12 13:11:31 +0100165 } else if (onode->name.prefix) {
166 *prefix_p = onode->name.prefix;
Radek Krejci1798aae2020-07-14 13:26:06 +0200167 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.
Michal Vasko2552ea32020-12-08 15:32:34 +0100185 * @param[in] parent Parent of the node being processed, can be NULL in case of top-level.
Radek Krejci1798aae2020-07-14 13:26:06 +0200186 * @param[out] snode_p Pointer to the found schema node corresponding to the input parameters.
187 * @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.
188 * @return LY_EVALID on failure, error message is logged
189 * @return LY_ENOT in case the input data are expected to be skipped
190 */
191static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +0200192lydjson_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 +0200193 size_t name_len, const struct lyd_node_inner *parent, const struct lysc_node **snode_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200194{
195 struct lys_module *mod = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100196 uint32_t getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200197
198 /* init return value */
199 *snode_p = NULL;
200
201 /* get the element module */
Michal Vasko2552ea32020-12-08 15:32:34 +0100202 if (prefix_len) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200203 mod = ly_ctx_get_module_implemented2(lydctx->jsonctx->ctx, prefix, prefix_len);
204 } else if (parent) {
205 if (parent->schema) {
206 mod = parent->schema->module;
207 }
208 } else {
209 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 +0200210 is_attr ? name_len + 1 : name_len, is_attr ? name - 1 : name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200211 return LY_EVALID;
212 }
213 if (!mod) {
214 if (lydctx->parse_options & LYD_PARSE_STRICT) {
215 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, parent, LYVE_REFERENCE, "No module named \"%.*s\" in the context.", prefix_len, prefix);
216 return LY_EVALID;
217 }
218 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
219 return LY_ENOT;
220 }
221 }
222
Radek Krejci1798aae2020-07-14 13:26:06 +0200223 /* get the schema node */
224 if (mod && (!parent || parent->schema)) {
225 *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
226 if (!*snode_p) {
227 if (lydctx->parse_options & LYD_PARSE_STRICT) {
228 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 +0200229 name_len, name, mod->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200230 return LY_EVALID;
231 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
232 /* skip element with children */
233 return LY_ENOT;
234 }
235 } else {
236 /* check that schema node is valid and can be used */
237 LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode_p));
238 }
239 }
240
241 return LY_SUCCESS;
242}
243
244/**
245 * @brief Skip the currently open JSON object/array
246 * @param[in] jsonctx JSON context with the input data to skip.
247 * @return LY_ERR value.
248 */
249static LY_ERR
250lydjson_data_skip(struct lyjson_ctx *jsonctx)
251{
252 enum LYJSON_PARSER_STATUS status, current;
253 size_t sublevels = 1;
254
255 status = lyjson_ctx_status(jsonctx, 0);
256
257 /* skip after the content */
258 do {
259 LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
260 if (current == status) {
261 sublevels++;
262 } else if (current == status + 1) {
263 sublevels--;
264 }
Radek Krejci79856c42020-11-19 11:44:08 +0100265 } while (current != status + 1 || sublevels);
Radek Krejci1798aae2020-07-14 13:26:06 +0200266 /* open the next sibling */
267 LY_CHECK_RET(lyjson_ctx_next(jsonctx, NULL));
268
269 return LY_SUCCESS;
270}
271
272/**
Radek Krejci1798aae2020-07-14 13:26:06 +0200273 * @brief Check that the input data are parseable as the @p list.
274 *
275 * Checks for all the list's keys. Function does not revert the context state.
276 *
277 * @param[in] jsonctx JSON parser context.
278 * @param[in] list List schema node corresponding to the input data object.
279 * @return LY_SUCCESS in case the data are ok for the @p list
280 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance.
281 */
282static LY_ERR
283lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list)
284{
285 LY_ERR ret = LY_SUCCESS;
286 enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx, 0);
287 struct ly_set key_set = {0};
288 const struct lysc_node *snode;
289 uint32_t i, status_count;
290
291 assert(list && (list->nodetype == LYS_LIST));
292 assert(status == LYJSON_OBJECT);
293
294 /* get all keys into a set (keys do not have if-features or anything) */
295 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100296 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200297 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200298 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200299 }
300
301 if (status != LYJSON_OBJECT_EMPTY) {
302 status_count = jsonctx->status.count;
303
304 while (key_set.count && status != LYJSON_OBJECT_CLOSED) {
305 const char *name, *prefix;
306 size_t name_len, prefix_len;
Radek Krejci857189e2020-09-01 13:26:36 +0200307 ly_bool is_attr;
Radek Krejci1798aae2020-07-14 13:26:06 +0200308
309 /* match the key */
310 snode = NULL;
311 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
312
313 if (!is_attr && !prefix) {
314 for (i = 0; i < key_set.count; ++i) {
315 snode = (const struct lysc_node *)key_set.objs[i];
316 if (!ly_strncmp(snode->name, name, name_len)) {
317 break;
318 }
319 }
320 /* go into the item to a) process it as a key or b) start skipping it as another list child */
321 ret = lyjson_ctx_next(jsonctx, &status);
322 LY_CHECK_GOTO(ret, cleanup);
323
324 if (snode) {
325 /* we have the key, validate the value */
326 if (status < LYJSON_NUMBER) {
327 /* not a terminal */
328 ret = LY_ENOT;
329 goto cleanup;
330 }
331
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200332 ret = _lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_PREF_JSON, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200333 LY_CHECK_GOTO(ret, cleanup);
334
335 /* key with a valid value, remove from the set */
336 ly_set_rm_index(&key_set, i, NULL);
337 }
338 } else {
339 /* start skipping the member we are not interested in */
340 ret = lyjson_ctx_next(jsonctx, &status);
341 LY_CHECK_GOTO(ret, cleanup);
342 }
343 /* move to the next child */
344 while (status_count < jsonctx->status.count) {
345 ret = lyjson_ctx_next(jsonctx, &status);
346 LY_CHECK_GOTO(ret, cleanup);
347 }
348 }
349 }
350
351 if (key_set.count) {
352 /* some keys are missing/did not validate */
353 ret = LY_ENOT;
354 }
355
356cleanup:
357 ly_set_erase(&key_set, NULL);
358 return ret;
359}
360
361/**
362 * @brief Get the hint for the data type parsers according to the current JSON parser context.
363 *
364 * @param[in] lydctx JSON data parser context. The context is supposed to be on a value.
365 * @param[in,out] status Pointer to the current context status,
366 * in some circumstances the function manipulates with the context so the status is updated.
367 * @param[out] type_hint_p Pointer to the variable to store the result.
368 * @return LY_SUCCESS in case of success.
369 * @return LY_EINVAL in case of invalid context status not referring to a value.
370 */
371static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200372lydjson_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 +0200373{
374 *type_hint_p = 0;
375
376 if (*status_p == LYJSON_ARRAY) {
377 /* only [null] */
378 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
379 LY_CHECK_RET(*status_p != LYJSON_NULL, LY_EINVAL);
380
381 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
382 LY_CHECK_RET(lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_ARRAY_CLOSED, LY_EINVAL);
383
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200384 *type_hint_p = LYD_VALHINT_EMPTY;
Radek Krejci1798aae2020-07-14 13:26:06 +0200385 } else if (*status_p == LYJSON_STRING) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200386 *type_hint_p = LYD_VALHINT_STRING | LYD_VALHINT_NUM64;
Radek Krejci1798aae2020-07-14 13:26:06 +0200387 } else if (*status_p == LYJSON_NUMBER) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200388 *type_hint_p = LYD_VALHINT_DECNUM;
Michal Vasko69730152020-10-09 16:30:07 +0200389 } else if ((*status_p == LYJSON_FALSE) || (*status_p == LYJSON_TRUE)) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200390 *type_hint_p = LYD_VALHINT_BOOLEAN;
Radek Krejci1798aae2020-07-14 13:26:06 +0200391 } else if (*status_p == LYJSON_NULL) {
392 *type_hint_p = 0;
393 } else {
394 return LY_EINVAL;
395 }
396
397 return LY_SUCCESS;
398}
399
400/**
401 * @brief Check in advance if the input data are parsable according to the provided @p snode.
402 *
403 * Note that the checks are done only in case the LYD_PARSE_OPAQ is allowed. Otherwise the same checking
404 * is naturally done when the data are really parsed.
405 *
406 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
407 * as before calling, despite it is necessary to process input data for checking.
408 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
409 * @param[out] type_hint_p Pointer to a variable to store detected value type hint in case of leaf or leaf-list.
410 * @return LY_SUCCESS in case the data are ok for the @p snode or the LYD_PARSE_OPAQ is not enabled.
411 * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance
412 * @return LY_EINVAL in case of invalid leaf JSON encoding
413 * and they are expected to be parsed as opaq nodes.
414 */
415static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200416lydjson_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 +0200417{
418 LY_ERR ret = LY_SUCCESS;
419 struct lyjson_ctx *jsonctx = lydctx->jsonctx;
420 enum LYJSON_PARSER_STATUS status;
421
422 assert(snode);
Radek Krejci1798aae2020-07-14 13:26:06 +0200423
Michal Vasko32ac9942020-08-12 14:35:12 +0200424 if (!(snode->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
425 /* can always be parsed as a data node if we have the schema node */
426 return LY_SUCCESS;
427 }
428
429 if (lydctx->parse_options & LYD_PARSE_OPAQ) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200430 /* backup parser */
431 lyjson_ctx_backup(jsonctx);
432 status = lyjson_ctx_status(jsonctx, 0);
433
Michal Vasko32ac9942020-08-12 14:35:12 +0200434 /* check if the node is parseable. if not, NULL the snode to announce that it is supposed to be parsed
435 * as an opaq node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200436 switch (snode->nodetype) {
437 case LYS_LEAFLIST:
438 case LYS_LEAF:
439 /* value may not be valid in which case we parse it as an opaque node */
440 ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
441 if (ret) {
442 break;
443 }
444
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200445 if (_lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_PREF_JSON, NULL)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200446 ret = LY_ENOT;
447 }
448 break;
449 case LYS_LIST:
450 /* lists may not have all its keys */
451 if (lydjson_check_list(jsonctx, snode)) {
452 /* invalid list, parse as opaque if it missing/has invalid some keys */
453 ret = LY_ENOT;
454 }
Michal Vasko32ac9942020-08-12 14:35:12 +0200455 break;
Radek Krejci1798aae2020-07-14 13:26:06 +0200456 }
457
458 /* restore parser */
459 lyjson_ctx_restore(jsonctx);
Michal Vasko32ac9942020-08-12 14:35:12 +0200460 } else if (snode->nodetype & LYD_NODE_TERM) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200461 status = lyjson_ctx_status(jsonctx, 0);
462 ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
463 }
464
465 return ret;
466}
467
468/**
469 * @brief Join the forward-referencing metadata with their target data nodes.
470 *
471 * Note that JSON encoding for YANG data allows forward-referencing metadata only for leafs/leaf-lists.
472 *
473 * @param[in] lydctx JSON data parser context.
474 * @param[in,out] first_p Pointer to the first sibling node variable (top-level or in a particular parent node)
475 * as a starting point to search for the metadata's target data node
476 * @return LY_SUCCESS on success
477 * @return LY_EVALID in case there are some metadata with unresolved target data node instance
478 */
479static LY_ERR
480lydjson_metadata_finish(struct lyd_json_ctx *lydctx, struct lyd_node **first_p)
481{
482 LY_ERR ret = LY_SUCCESS;
483 struct lyd_node *node, *attr, *next, *start = *first_p, *meta_iter;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200484 uint64_t instance = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200485 const char *prev = NULL;
486
487 /* finish linking metadata */
488 LY_LIST_FOR_SAFE(*first_p, next, attr) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200489 struct lyd_node_opaq *meta_container = (struct lyd_node_opaq *)attr;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200490 uint64_t match = 0;
Radek Krejci857189e2020-09-01 13:26:36 +0200491 ly_bool is_attr;
Radek Krejci1798aae2020-07-14 13:26:06 +0200492 const char *name, *prefix;
493 size_t name_len, prefix_len;
494 const struct lysc_node *snode;
495
Michal Vaskoad92b672020-11-12 13:11:31 +0100496 if (attr->schema || (meta_container->name.name[0] != '@')) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200497 /* not an opaq metadata node */
498 continue;
499 }
500
Michal Vaskoad92b672020-11-12 13:11:31 +0100501 if (prev != meta_container->name.name) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200502 /* metas' names are stored in dictionary, so checking pointers must works */
503 lydict_remove(lydctx->jsonctx->ctx, prev);
Michal Vaskoad92b672020-11-12 13:11:31 +0100504 LY_CHECK_GOTO(ret = lydict_insert(lydctx->jsonctx->ctx, meta_container->name.name, 0, &prev), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200505 instance = 1;
506 } else {
507 instance++;
508 }
509
510 /* find the correspnding data node */
511 LY_LIST_FOR(start, node) {
512 if (!node->schema) {
513 /* opaq node - we are going to put into it just a generic attribute. */
Michal Vaskoad92b672020-11-12 13:11:31 +0100514 if (strcmp(&meta_container->name.name[1], ((struct lyd_node_opaq *)node)->name.name)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200515 continue;
516 }
517
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200518 if (((struct lyd_node_opaq *)node)->hints & LYD_NODEHINT_LIST) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200519 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, node, LYVE_SYNTAX,
Michal Vaskoad92b672020-11-12 13:11:31 +0100520 "Metadata container references a sibling list node %s.", ((struct lyd_node_opaq *)node)->name.name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200521 ret = LY_EVALID;
522 goto cleanup;
523 }
524
525 /* match */
526 match++;
527 if (match != instance) {
528 continue;
529 }
530
531 LY_LIST_FOR(meta_container->child, meta_iter) {
532 /* convert opaq node to a attribute of the opaq node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200533 struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
Radek Krejcibb27df32020-11-13 15:39:16 +0100534
Michal Vaskoad92b672020-11-12 13:11:31 +0100535 ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, meta->name.name, strlen(meta->name.name),
536 meta->name.prefix, ly_strlen(meta->name.prefix), meta->name.module_name,
537 ly_strlen(meta->name.module_name), meta->value, ly_strlen(meta->value), NULL, LY_PREF_JSON,
538 NULL, meta->hints);
Radek Krejci1798aae2020-07-14 13:26:06 +0200539 LY_CHECK_GOTO(ret, cleanup);
540 }
541
542 /* done */
543 break;
544 } else {
545 /* this is the second time we are resolving the schema node, so it must succeed,
546 * but remember that snode can be still NULL */
Michal Vaskoad92b672020-11-12 13:11:31 +0100547 lydjson_parse_name(meta_container->name.name, strlen(meta_container->name.name), &name, &name_len,
548 &prefix, &prefix_len, &is_attr);
Radek Krejci1798aae2020-07-14 13:26:06 +0200549 assert(is_attr);
550 ret = lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, (*first_p)->parent, &snode);
551 assert(ret == LY_SUCCESS);
552
553 if (snode != node->schema) {
554 continue;
555 }
556
557 /* match */
558 match++;
559 if (match != instance) {
560 continue;
561 }
562
563 LY_LIST_FOR(meta_container->child, meta_iter) {
564 /* convert opaq node to a metadata of the node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200565 struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
Radek Krejci1798aae2020-07-14 13:26:06 +0200566 struct lys_module *mod = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200567 ly_bool dynamic = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200568
Michal Vaskoad92b672020-11-12 13:11:31 +0100569 mod = ly_ctx_get_module_implemented(lydctx->jsonctx->ctx, meta->name.prefix);
Radek Krejci1798aae2020-07-14 13:26:06 +0200570 if (mod) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200571 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod,
Michal Vaskoad92b672020-11-12 13:11:31 +0100572 meta->name.name, strlen(meta->name.name), meta->value, ly_strlen(meta->value),
Michal Vasko69730152020-10-09 16:30:07 +0200573 &dynamic, LY_PREF_JSON, NULL, meta->hints);
Radek Krejci1798aae2020-07-14 13:26:06 +0200574 LY_CHECK_GOTO(ret, cleanup);
575 } else if (lydctx->parse_options & LYD_PARSE_STRICT) {
576 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200577 "Unknown (or not implemented) YANG module \"%s\" for metadata \"%s%s%s\".",
Michal Vaskoad92b672020-11-12 13:11:31 +0100578 meta->name.prefix, meta->name.prefix, ly_strlen(meta->name.prefix) ? ":" : "", meta->name.name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200579 ret = LY_EVALID;
580 goto cleanup;
581 }
582 }
583 /* add/correct flags */
Michal Vasko49c39d82020-11-06 17:20:27 +0100584 lyd_parse_set_data_flags(node, &lydctx->node_when, &node->meta, lydctx->parse_options);
Radek Krejci1798aae2020-07-14 13:26:06 +0200585
586 /* done */
587 break;
588 }
589 }
590
591 if (match != instance) {
592 /* there is no corresponding data node for the metadata */
593 if (instance > 1) {
594 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, *first_p ? (*first_p)->parent : NULL, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200595 "Missing %d%s JSON data instance to be coupled with %s metadata.", instance,
Michal Vaskoad92b672020-11-12 13:11:31 +0100596 instance == 2 ? "nd" : (instance == 3 ? "rd" : "th"), meta_container->name.name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200597 } else {
598 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, *first_p ? (*first_p)->parent : NULL, LYVE_REFERENCE,
Michal Vaskoad92b672020-11-12 13:11:31 +0100599 "Missing JSON data instance to be coupled with %s metadata.", meta_container->name.name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200600 }
601 ret = LY_EVALID;
602 } else {
603 /* remove the opaq attr */
604 if (attr == (*first_p)) {
605 *first_p = attr->next;
606 }
607 lyd_free_tree(attr);
608 }
609 }
610
611cleanup:
612 lydict_remove(lydctx->jsonctx->ctx, prev);
613
614 return ret;
615}
616
617/**
618 * @brief Parse a metadata member.
619 *
620 * @param[in] lydctx JSON data parser context.
621 * @param[in] snode Schema node of the metadata parent.
622 * @param[in] node Parent node in case the metadata is not forward-referencing (only LYD_NODE_TERM)
623 * so the data node does not exists. In such a case the metadata is stored in the context for the later
624 * processing by lydjson_metadata_finish().
625 * @return LY_SUCCESS on success
626 * @return Various LY_ERR values in case of failure.
627 */
628static LY_ERR
629lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node)
630{
631 LY_ERR ret = LY_SUCCESS;
632 enum LYJSON_PARSER_STATUS status;
633 const char *expected;
Radek Krejci857189e2020-09-01 13:26:36 +0200634 ly_bool in_parent = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200635 const char *name, *prefix = NULL;
636 size_t name_len, prefix_len = 0;
637 struct lys_module *mod;
638 struct lyd_meta *meta = NULL;
639 const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
Radek Krejci857189e2020-09-01 13:26:36 +0200640 ly_bool is_attr = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200641 struct lyd_node *prev = node;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200642 uint32_t instance = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200643 uint16_t nodetype;
644
645 assert(snode || node);
646
647 nodetype = snode ? snode->nodetype : LYS_CONTAINER;
648
649 /* move to the second item in the name/X pair */
650 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
651 LY_CHECK_GOTO(ret, cleanup);
652
653 /* check attribute encoding */
654 switch (nodetype) {
655 case LYS_LEAFLIST:
656 expected = "@name/array of objects/nulls";
657
658 LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
659
660next_entry:
661 instance++;
662
663 /* move into array / next entry */
664 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
665 LY_CHECK_GOTO(ret, cleanup);
666
667 if (status == LYJSON_ARRAY_CLOSED) {
668 /* we are done, move after the array */
669 ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
670 goto cleanup;
671 }
672 LY_CHECK_GOTO(status != LYJSON_OBJECT && status != LYJSON_NULL, representation_error);
673
Michal Vasko69730152020-10-09 16:30:07 +0200674 if (!node || (node->schema != prev->schema)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200675 LOGVAL(lydctx->jsonctx->ctx, LY_VLOG_LYD, prev->parent, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200676 "Missing JSON data instance no. %u of %s:%s to be coupled with metadata.",
677 instance, prev->schema->module->name, prev->schema->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200678 ret = LY_EVALID;
679 goto cleanup;
680 }
681
682 if (status == LYJSON_NULL) {
683 /* continue with the next entry in the leaf-list array */
684 prev = node;
685 node = node->next;
686 goto next_entry;
687 }
688 break;
689 case LYS_LEAF:
690 case LYS_ANYXML:
691 expected = "@name/object";
692
693 LY_CHECK_GOTO(status != LYJSON_OBJECT && (nodetype != LYS_LEAFLIST || status != LYJSON_NULL), representation_error);
694 break;
695 case LYS_CONTAINER:
696 case LYS_LIST:
697 case LYS_ANYDATA:
698 case LYS_NOTIF:
699 case LYS_ACTION:
700 case LYS_RPC:
701 in_parent = 1;
702 expected = "@/object";
703 LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
704 break;
Radek Krejci8f5fad22020-09-15 16:50:54 +0200705 default:
706 LOGINT_RET(ctx);
Radek Krejci1798aae2020-07-14 13:26:06 +0200707 }
708
709 /* process all the members inside a single metadata object */
710 assert(status == LYJSON_OBJECT);
711
712 while (status != LYJSON_OBJECT_CLOSED) {
713 lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
714 if (!prefix) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200715 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +0200716 "Metadata in JSON must be namespace-qualified, missing prefix for \"%.*s\".",
717 lydctx->jsonctx->value_len, lydctx->jsonctx->value);
Radek Krejci1798aae2020-07-14 13:26:06 +0200718 ret = LY_EVALID;
719 goto cleanup;
720 } else if (is_attr) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200721 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +0200722 "Invalid format of the Metadata identifier in JSON, unexpected '@' in \"%.*s\"",
723 lydctx->jsonctx->value_len, lydctx->jsonctx->value);
Radek Krejci1798aae2020-07-14 13:26:06 +0200724 ret = LY_EVALID;
725 goto cleanup;
726 }
727
728 /* get the element module */
729 mod = ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
730 if (!mod) {
731 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200732 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200733 "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
734 prefix_len, prefix, name_len, name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200735 ret = LY_EVALID;
736 goto cleanup;
737 }
738 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
739 /* skip element with children */
740 ret = lydjson_data_skip(lydctx->jsonctx);
741 LY_CHECK_GOTO(ret, cleanup);
742 status = lyjson_ctx_status(lydctx->jsonctx, 0);
743 /* end of the item */
744 continue;
745 }
746 }
747
748 /* get the value */
749 ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
750 LY_CHECK_GOTO(ret, cleanup);
751
752 if (node->schema) {
753 /* create metadata */
754 meta = NULL;
Michal Vasko22df3f02020-08-24 13:29:22 +0200755 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 +0200756 lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_PREF_JSON, NULL,
757 LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200758 LY_CHECK_GOTO(ret, cleanup);
759
760 /* add/correct flags */
Michal Vasko49c39d82020-11-06 17:20:27 +0100761 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_options);
Radek Krejci1798aae2020-07-14 13:26:06 +0200762 } else {
763 /* create attribute */
Radek Krejci1798aae2020-07-14 13:26:06 +0200764 const char *module_name;
765 size_t module_name_len;
766
767 lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
768
Radek Krejci1798aae2020-07-14 13:26:06 +0200769 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100770 ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name,
771 module_name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic,
772 LY_PREF_JSON, NULL, 0);
Radek Krejci1798aae2020-07-14 13:26:06 +0200773 LY_CHECK_GOTO(ret, cleanup);
774 }
775 /* next member */
776 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
777 LY_CHECK_GOTO(ret, cleanup);
778 }
779
780 if (nodetype == LYS_LEAFLIST) {
781 /* continue by processing another metadata object for the following
782 * leaf-list instance since they are allways instantiated in JSON array */
783 prev = node;
784 node = node->next;
785 goto next_entry;
786 }
787
788 /* move after the metadata */
789 ret = lyjson_ctx_next(lydctx->jsonctx, NULL);
790 LY_CHECK_GOTO(ret, cleanup);
791
792cleanup:
793 return ret;
794
795representation_error:
Michal Vasko22df3f02020-08-24 13:29:22 +0200796 LOGVAL(ctx, LY_VLOG_LYD, (void *)node, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +0200797 "The attribute(s) of %s \"%s\" is expected to be represented as JSON %s, but input data contains @%s/%s.",
Michal Vaskoad92b672020-11-12 13:11:31 +0100798 lys_nodetype2str(nodetype), node->schema ? node->schema->name : ((struct lyd_node_opaq *)node)->name.name,
Michal Vasko69730152020-10-09 16:30:07 +0200799 expected, lyjson_token2str(status), in_parent ? "" : "name");
Radek Krejci1798aae2020-07-14 13:26:06 +0200800
801 return LY_EVALID;
802}
803
804/**
805 * @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.
806 *
807 * @param[in] parent Parent node to insert to, can be NULL in case of top-level (or provided first_p).
808 * @param[in, out] first_p Pointer to the first sibling node in case of top-level.
809 * @param[in, out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
810 */
811static void
812lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p)
813{
814 if (*node_p) {
815 /* insert, keep first pointer correct */
816 lyd_insert_node((struct lyd_node *)parent, first_p, *node_p);
817 if (first_p) {
818 if (parent) {
819 *first_p = parent->child;
820 } else {
821 while ((*first_p)->prev->next) {
822 *first_p = (*first_p)->prev;
823 }
824 }
825 }
826 *node_p = NULL;
827 }
828}
829
830static LY_ERR lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p);
831
832/**
833 * @brief Parse opaq node from the input.
834 *
835 * In case of processing array, the whole array is being processed and the resulting @p node_p is the last item of the array.
836 *
837 * @param[in] lydctx JSON data parser context.
838 * @param[in] name Name of the opaq node to create.
839 * @param[in] name_len Length of the @p name string.
840 * @param[in] prefix Prefix of the opaq node to create.
841 * @param[in] prefix_len Length of the @p prefx string.
842 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
843 * but must be set if @p first is not.
844 * @param[in,out] status_p Pointer to the current status of the parser context,
845 * since the function manipulates with the context and process the input, the status can be updated.
846 * @param[in,out] status_inner_p In case of processing JSON array, this parameter points to a standalone
847 * context status of the array content. Otherwise, it is supposed to be the same as @p status_p.
848 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
849 * @param[out] node_p Pointer to the created opaq node.
850 * @return LY_ERR value.
851 */
852static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200853lydjson_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 +0200854 struct lyd_node_inner *parent, enum LYJSON_PARSER_STATUS *status_p,
855 enum LYJSON_PARSER_STATUS *status_inner_p, struct lyd_node **first_p, struct lyd_node **node_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200856{
857 LY_ERR ret = LY_SUCCESS;
858 const char *value = NULL, *module_name;
859 size_t value_len = 0, module_name_len = 0;
Radek Krejci857189e2020-09-01 13:26:36 +0200860 ly_bool dynamic = 0;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200861 uint32_t type_hint = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200862
Michal Vasko69730152020-10-09 16:30:07 +0200863 if ((*status_inner_p != LYJSON_OBJECT) && (*status_inner_p != LYJSON_OBJECT_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200864 /* prepare for creating opaq node with a value */
865 value = lydctx->jsonctx->value;
866 value_len = lydctx->jsonctx->value_len;
867 dynamic = lydctx->jsonctx->dynamic;
868 lydctx->jsonctx->dynamic = 0;
869
870 LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
Radek Krejci1798aae2020-07-14 13:26:06 +0200871 }
872
873 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200874 lydjson_get_node_prefix((struct lyd_node *)parent, prefix, prefix_len, &module_name, &module_name_len);
Michal Vasko501af032020-11-11 20:27:44 +0100875 ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name, module_name_len, value,
876 value_len, &dynamic, LY_PREF_JSON, NULL, type_hint, node_p);
Radek Krejci1798aae2020-07-14 13:26:06 +0200877 if (dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200878 free((char *)value);
Radek Krejci1798aae2020-07-14 13:26:06 +0200879 }
Radek Krejcid46e46a2020-09-15 14:22:42 +0200880 LY_CHECK_RET(ret);
Radek Krejci1798aae2020-07-14 13:26:06 +0200881
Michal Vasko69730152020-10-09 16:30:07 +0200882 if ((*status_p == LYJSON_OBJECT) || (*status_p == LYJSON_OBJECT_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200883 /* process children */
884 while (*status_p != LYJSON_OBJECT_CLOSED && *status_p != LYJSON_OBJECT_EMPTY) {
885 LY_CHECK_RET(lydjson_subtree_r(lydctx, (struct lyd_node_inner *)(*node_p), lyd_node_children_p(*node_p)));
886 *status_p = lyjson_ctx_status(lydctx->jsonctx, 0);
887 }
Michal Vasko69730152020-10-09 16:30:07 +0200888 } else if ((*status_p == LYJSON_ARRAY) || (*status_p == LYJSON_ARRAY_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200889 /* process another instance of the same node */
890 /* but first mark the node to be expected a list or a leaf-list */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200891 ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST;
Radek Krejci1798aae2020-07-14 13:26:06 +0200892
Michal Vasko69730152020-10-09 16:30:07 +0200893 if ((*status_inner_p == LYJSON_OBJECT) || (*status_inner_p == LYJSON_OBJECT_EMPTY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200894 /* but first process children of the object in the array */
895 while (*status_inner_p != LYJSON_OBJECT_CLOSED && *status_inner_p != LYJSON_OBJECT_EMPTY) {
896 LY_CHECK_RET(lydjson_subtree_r(lydctx, (struct lyd_node_inner *)(*node_p), lyd_node_children_p(*node_p)));
897 *status_inner_p = lyjson_ctx_status(lydctx->jsonctx, 0);
898 }
899 }
900
901 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
902
903 /* continue with the next instance */
904 if (*status_inner_p != LYJSON_ARRAY_CLOSED) {
905 assert(node_p);
906 lydjson_maintain_children(parent, first_p, node_p);
907 return lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_p, status_inner_p, first_p, node_p);
908 }
909 }
910
911 /* finish linking metadata */
912 LY_CHECK_RET(lydjson_metadata_finish(lydctx, lyd_node_children_p(*node_p)));
913
914 /* move after the item */
915 return lyjson_ctx_next(lydctx->jsonctx, status_p);
916}
917
918/**
919 * @brief Process the attribute container (starting by @)
920 *
921 * @param[in] lydctx JSON data parser context.
922 * @param[in] attr_node The data node referenced by the attribute container, if already known.
923 * @param[in] snode The schema node of the data node referenced by the attribute container, if known.
924 * @param[in] name Name of the opaq node to create.
925 * @param[in] name_len Length of the @p name string.
926 * @param[in] prefix Prefix of the opaq node to create.
927 * @param[in] prefix_len Length of the @p prefx string.
928 * @param[in] parent Data parent of the opaq node to create, can be NULL in case of top level,
929 * but must be set if @p first is not.
930 * @param[in,out] status_p Pointer to the current status of the parser context,
931 * since the function manipulates with the context and process the input, the status can be updated.
932 * @param[in,out] first_p First top-level/parent sibling, must be set if @p parent is not.
933 * @param[out] node_p Pointer to the created opaq node.
934 * @return LY_ERR value.
935 */
936static LY_ERR
937lydjson_parse_attribute(struct lyd_json_ctx *lydctx, struct lyd_node *attr_node, const struct lysc_node *snode,
Radek Krejci0f969882020-08-21 16:56:47 +0200938 const char *name, size_t name_len, const char *prefix, size_t prefix_len,
939 struct lyd_node_inner *parent, enum LYJSON_PARSER_STATUS *status_p, struct lyd_node **first_p,
940 struct lyd_node **node_p)
Radek Krejci1798aae2020-07-14 13:26:06 +0200941{
942 LY_ERR ret = LY_SUCCESS;
943 enum LYJSON_PARSER_STATUS status_inner;
944
945 /* parse as an attribute to a node */
946 if (!attr_node && snode) {
947 /* try to find the instance */
948 for (struct lyd_node *iter = *first_p; iter; iter = iter->next) {
949 if (iter->schema == snode) {
950 attr_node = iter;
951 break;
952 }
953 }
954 }
955 if (!attr_node) {
956 /* parse just as an opaq node with the name beginning with @,
957 * later we have to check that it belongs to a standard node
958 * and it is supposed to be converted to a metadata */
959 uint32_t prev_opts;
960
961 /* move into metadata */
962 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
963
964 if (*status_p == LYJSON_ARRAY) {
965 /* move into the array */
966 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, &status_inner));
967 } else {
968 /* just a flag to pass correct parameters into lydjson_parse_opaq() */
969 status_inner = LYJSON_ERROR;
970 }
971
972 /* backup parser options to parse unknown metadata as opaq nodes and try to resolve them later */
973 prev_opts = lydctx->parse_options;
974 lydctx->parse_options &= ~LYD_PARSE_STRICT;
975 lydctx->parse_options |= LYD_PARSE_OPAQ;
976
977 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 +0200978 NULL, 0, parent, status_p, status_inner == LYJSON_ERROR ? status_p : &status_inner, first_p, node_p);
Radek Krejci1798aae2020-07-14 13:26:06 +0200979
980 /* restore the parser options */
981 lydctx->parse_options = prev_opts;
982 } else {
983 ret = lydjson_metadata(lydctx, snode, attr_node);
984 }
985
986 return ret;
987}
988
989/**
Michal Vasko32ac9942020-08-12 14:35:12 +0200990 * @brief Parse a single instance of a node.
991 *
992 * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
993 * as before calling, despite it is necessary to process input data for checking.
994 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
995 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
996 * @param[in] snode Schema node corresponding to the member currently being processed in the context.
997 * @param[in] name Parsed JSON node name.
998 * @param[in] name_len Lenght of @p name.
999 * @param[in] prefix Parsed JSON node prefix.
1000 * @param[in] prefix_len Length of @p prefix.
1001 * @param[in,out] status JSON parser status, is updated.
1002 * @param[out] node Parsed data (or opaque) node.
1003 * @return LY_SUCCESS if a node was successfully parsed,
1004 * @return LY_EINVAL in case of invalid JSON encoding,
1005 * @return LY_ERR on other errors.
1006 */
1007static LY_ERR
1008lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p,
Radek Krejci0f969882020-08-21 16:56:47 +02001009 const struct lysc_node *snode, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
1010 enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
Michal Vasko32ac9942020-08-12 14:35:12 +02001011{
1012 LY_ERR ret;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001013 uint32_t type_hints = 0;
Michal Vasko32ac9942020-08-12 14:35:12 +02001014 uint32_t prev_opts;
1015 struct lyd_node *tree = NULL;
1016
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001017 ret = lydjson_data_check_opaq(lydctx, snode, &type_hints);
Michal Vasko32ac9942020-08-12 14:35:12 +02001018 if (ret == LY_SUCCESS) {
1019 assert(snode->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER | LYD_NODE_ANY));
1020 if (snode->nodetype & LYD_NODE_TERM) {
1021 /* create terminal node */
1022 ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, lydctx->jsonctx->value,
Michal Vasko69730152020-10-09 16:30:07 +02001023 lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_PREF_JSON, NULL,
1024 type_hints, node);
Michal Vasko32ac9942020-08-12 14:35:12 +02001025 LY_CHECK_RET(ret);
1026
1027 /* move JSON parser */
1028 ret = lyjson_ctx_next(lydctx->jsonctx, status);
1029 LY_CHECK_RET(ret);
1030 } else if (snode->nodetype & LYD_NODE_INNER) {
1031 /* create inner node */
1032 LY_CHECK_RET(*status != LYJSON_OBJECT && *status != LYJSON_OBJECT_EMPTY, LY_EINVAL);
1033
1034 ret = lyd_create_inner(snode, node);
1035 LY_CHECK_RET(ret);
1036
1037 /* process children */
1038 while (*status != LYJSON_OBJECT_CLOSED && *status != LYJSON_OBJECT_EMPTY) {
1039 ret = lydjson_subtree_r(lydctx, (struct lyd_node_inner *)*node, lyd_node_children_p(*node));
1040 LY_CHECK_RET(ret);
1041 *status = lyjson_ctx_status(lydctx->jsonctx, 0);
1042 }
1043
1044 /* finish linking metadata */
1045 ret = lydjson_metadata_finish(lydctx, lyd_node_children_p(*node));
1046 LY_CHECK_RET(ret);
1047
1048 if (snode->nodetype == LYS_LIST) {
1049 /* check all keys exist */
1050 ret = lyd_parse_check_keys(*node);
1051 LY_CHECK_RET(ret);
1052 }
1053
1054 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
1055 /* new node validation, autodelete CANNOT occur, all nodes are new */
1056 ret = lyd_validate_new(lyd_node_children_p(*node), snode, NULL, NULL);
1057 LY_CHECK_RET(ret);
1058
1059 /* add any missing default children */
Michal Vasko49c39d82020-11-06 17:20:27 +01001060 ret = lyd_new_implicit_r(*node, lyd_node_children_p(*node), NULL, NULL, &lydctx->node_types,
1061 &lydctx->node_when, (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ?
Michal Vasko69730152020-10-09 16:30:07 +02001062 LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vasko32ac9942020-08-12 14:35:12 +02001063 LY_CHECK_RET(ret);
1064 }
1065
1066 /* move JSON parser */
1067 ret = lyjson_ctx_next(lydctx->jsonctx, status);
1068 LY_CHECK_RET(ret);
1069 } else if (snode->nodetype & LYD_NODE_ANY) {
1070 /* create any node */
1071 LY_CHECK_RET(*status != LYJSON_OBJECT && *status != LYJSON_OBJECT_EMPTY, LY_EINVAL);
1072
1073 /* parse any data tree with correct options */
1074 /* first backup the current options and then make the parser to process data as opaq nodes */
1075 prev_opts = lydctx->parse_options;
1076 lydctx->parse_options &= ~LYD_PARSE_STRICT;
1077 lydctx->parse_options |= LYD_PARSE_OPAQ;
1078
1079 /* process the anydata content */
1080 while (*status != LYJSON_OBJECT_CLOSED && *status != LYJSON_OBJECT_EMPTY) {
1081 ret = lydjson_subtree_r(lydctx, NULL, &tree);
1082 LY_CHECK_RET(ret);
1083 *status = lyjson_ctx_status(lydctx->jsonctx, 0);
1084 }
1085
1086 /* restore parser options */
1087 lydctx->parse_options = prev_opts;
1088
1089 /* finish linking metadata */
1090 ret = lydjson_metadata_finish(lydctx, &tree);
1091 LY_CHECK_RET(ret);
1092
Michal Vasko366a4a12020-12-04 16:23:57 +01001093 ret = lyd_create_any(snode, tree, LYD_ANYDATA_DATATREE, 1, node);
Michal Vasko32ac9942020-08-12 14:35:12 +02001094 LY_CHECK_RET(ret);
1095 }
1096 } else if (ret == LY_ENOT) {
1097 /* parse it again as an opaq node */
1098 ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent,
Michal Vasko69730152020-10-09 16:30:07 +02001099 status, status, first_p, node);
Michal Vasko32ac9942020-08-12 14:35:12 +02001100 LY_CHECK_RET(ret);
1101
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001102 if (snode->nodetype == LYS_LIST) {
1103 ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LIST;
1104 } else if (snode->nodetype == LYS_LEAFLIST) {
1105 ((struct lyd_node_opaq *)*node)->hints |= LYD_NODEHINT_LEAFLIST;
Michal Vasko32ac9942020-08-12 14:35:12 +02001106 }
1107 }
1108
1109 return ret;
1110}
1111
1112/**
Michal Vaskoa5da3292020-08-12 13:10:50 +02001113 * @brief Parse JSON subtree. All leaf-list and list instances of a node are considered one subtree.
Radek Krejci1798aae2020-07-14 13:26:06 +02001114 *
1115 * @param[in] lydctx JSON data parser context.
1116 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
1117 * @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
1118 * @return LY_ERR value.
1119 */
1120static LY_ERR
1121lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
1122{
1123 LY_ERR ret = LY_SUCCESS;
1124 enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx, 0);
1125 enum LYJSON_PARSER_STATUS status_inner = 0;
1126 const char *name, *prefix = NULL;
1127 size_t name_len, prefix_len = 0;
Radek Krejci857189e2020-09-01 13:26:36 +02001128 ly_bool is_meta = 0;
Michal Vaskocabe0702020-08-12 10:14:36 +02001129 const struct lysc_node *snode = NULL;
Michal Vasko32ac9942020-08-12 14:35:12 +02001130 struct lyd_node *node = NULL, *attr_node = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001131 const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
1132 const char *expected = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001133
1134 assert(parent || first_p);
1135 assert(status == LYJSON_OBJECT);
1136
1137 /* process the node name */
Michal Vaskocabe0702020-08-12 10:14:36 +02001138 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 +02001139
Michal Vaskocabe0702020-08-12 10:14:36 +02001140 if (!is_meta || name_len || prefix_len) {
1141 /* get the schema node */
1142 ret = lydjson_get_snode(lydctx, is_meta, prefix, prefix_len, name, name_len, parent, &snode);
1143 if (ret == LY_ENOT) {
1144 /* skip element with children */
1145 ret = lydjson_data_skip(lydctx->jsonctx);
1146 LY_CHECK_GOTO(ret, cleanup);
1147 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1148 /* nothing for now, continue with another call of lydjson_subtree_r() */
Radek Krejci1798aae2020-07-14 13:26:06 +02001149 goto cleanup;
1150 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001151 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001152
Michal Vaskocabe0702020-08-12 10:14:36 +02001153 if (!snode) {
1154 /* we will not be parsing it as metadata */
1155 is_meta = 0;
1156 }
1157 }
1158
1159 if (is_meta) {
1160 /* parse as metadata */
1161 if (!name_len && !prefix_len) {
1162 /* parent's metadata without a name - use the schema from the parent */
1163 if (!parent) {
1164 LOGVAL(ctx, LY_VLOG_LYD, NULL, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +02001165 "Invalid metadata format - \"@\" can be used only inside anydata, container or list entries.");
Michal Vaskocabe0702020-08-12 10:14:36 +02001166 ret = LY_EVALID;
1167 goto cleanup;
1168 }
1169 attr_node = (struct lyd_node *)parent;
1170 snode = attr_node->schema;
1171 }
1172 ret = lydjson_parse_attribute(lydctx, attr_node, snode, name, name_len, prefix, prefix_len, parent, &status,
Michal Vasko69730152020-10-09 16:30:07 +02001173 first_p, &node);
Michal Vaskocabe0702020-08-12 10:14:36 +02001174 LY_CHECK_GOTO(ret, cleanup);
1175 } else if (!snode) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001176 /* parse as an opaq node */
1177 assert((lydctx->parse_options & LYD_PARSE_OPAQ) || (lydctx->int_opts));
1178
1179 /* move to the second item in the name/X pair */
1180 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1181 LY_CHECK_GOTO(ret, cleanup);
1182
1183 if (status == LYJSON_ARRAY) {
1184 /* move into the array */
1185 ret = lyjson_ctx_next(lydctx->jsonctx, &status_inner);
1186 LY_CHECK_GOTO(ret, cleanup);
1187 } else {
1188 /* just a flag to pass correct parameters into lydjson_parse_opaq() */
1189 status_inner = LYJSON_ERROR;
1190 }
1191
1192 ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len,
Michal Vasko69730152020-10-09 16:30:07 +02001193 parent, &status, status_inner == LYJSON_ERROR ? &status : &status_inner, first_p, &node);
Radek Krejci1798aae2020-07-14 13:26:06 +02001194 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskocabe0702020-08-12 10:14:36 +02001195 } else {
Michal Vasko32ac9942020-08-12 14:35:12 +02001196 /* parse as a standard lyd_node but it can still turn out to be an opaque node */
Radek Krejci1798aae2020-07-14 13:26:06 +02001197
1198 /* move to the second item in the name/X pair */
1199 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1200 LY_CHECK_GOTO(ret, cleanup);
1201
1202 /* first check the expected representation according to the nodetype and then continue with the content */
1203 switch (snode->nodetype) {
1204 case LYS_LEAFLIST:
Michal Vasko32ac9942020-08-12 14:35:12 +02001205 case LYS_LIST:
1206 if (snode->nodetype == LYS_LEAFLIST) {
1207 expected = "name/array of values";
1208 } else {
1209 expected = "name/array of objects";
1210 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001211
1212 LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
1213
1214 /* move into array */
1215 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1216 LY_CHECK_GOTO(ret, cleanup);
1217
Michal Vasko32ac9942020-08-12 14:35:12 +02001218 /* process all the values/objects */
1219 do {
1220 lydjson_maintain_children(parent, first_p, &node);
Radek Krejci1798aae2020-07-14 13:26:06 +02001221
Michal Vasko32ac9942020-08-12 14:35:12 +02001222 ret = lydjson_parse_instance(lydctx, parent, first_p, snode, name, name_len, prefix, prefix_len,
Michal Vasko69730152020-10-09 16:30:07 +02001223 &status, &node);
Michal Vasko32ac9942020-08-12 14:35:12 +02001224 if (ret == LY_EINVAL) {
1225 goto representation_error;
1226 } else if (ret) {
1227 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001228 }
Michal Vasko32ac9942020-08-12 14:35:12 +02001229 } while (status != LYJSON_ARRAY_CLOSED);
Radek Krejci1798aae2020-07-14 13:26:06 +02001230
Michal Vasko32ac9942020-08-12 14:35:12 +02001231 /* move after the array */
1232 ret = lyjson_ctx_next(lydctx->jsonctx, &status);
1233 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001234
1235 break;
Michal Vasko32ac9942020-08-12 14:35:12 +02001236 case LYS_LEAF:
Radek Krejci1798aae2020-07-14 13:26:06 +02001237 case LYS_CONTAINER:
1238 case LYS_NOTIF:
1239 case LYS_ACTION:
1240 case LYS_RPC:
Michal Vasko32ac9942020-08-12 14:35:12 +02001241 case LYS_ANYDATA:
1242 case LYS_ANYXML:
1243 if (snode->nodetype == LYS_LEAF) {
1244 if (status == LYJSON_ARRAY) {
1245 expected = "name/[null]";
1246 } else {
1247 expected = "name/value";
1248 }
1249 } else {
Radek Krejci1798aae2020-07-14 13:26:06 +02001250 expected = "name/object";
1251 }
1252
Michal Vasko32ac9942020-08-12 14:35:12 +02001253 /* process the value/object */
1254 ret = lydjson_parse_instance(lydctx, parent, first_p, snode, name, name_len, prefix, prefix_len, &status, &node);
1255 if (ret == LY_EINVAL) {
1256 goto representation_error;
1257 } else if (ret) {
1258 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001259 }
1260
Michal Vasko32ac9942020-08-12 14:35:12 +02001261 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001262 /* rememeber the RPC/action/notification */
1263 lydctx->op_node = node;
1264 }
1265
1266 break;
Radek Krejci1798aae2020-07-14 13:26:06 +02001267 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001268 }
1269
Michal Vasko32ac9942020-08-12 14:35:12 +02001270 /* finally connect the parsed node */
Radek Krejci1798aae2020-07-14 13:26:06 +02001271 lydjson_maintain_children(parent, first_p, &node);
1272
1273cleanup:
1274 lyd_free_tree(node);
1275 return ret;
1276
1277representation_error:
1278 LOGVAL(ctx, LY_VLOG_LYD, parent, LYVE_SYNTAX_JSON,
Michal Vasko69730152020-10-09 16:30:07 +02001279 "The %s \"%s\" is expected to be represented as JSON %s, but input data contains name/%s.",
1280 lys_nodetype2str(snode->nodetype), snode->name, expected, lyjson_token2str(status));
Radek Krejci1798aae2020-07-14 13:26:06 +02001281
1282 ret = LY_EVALID;
1283 goto cleanup;
1284}
1285
1286/**
1287 * @brief Common start of JSON parser processing different types of the input data.
1288 *
1289 * @param[in] ctx libyang context
1290 * @param[in] in Input structure.
1291 * @param[in] parse_options Options for parser, see @ref dataparseroptions.
1292 * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
1293 * @param[out] lydctx_p Data parser context to finish validation.
Radek Krejcicd5f6222020-11-12 08:54:13 +01001294 * @param[out] status Storage for the current context's status
Radek Krejci1798aae2020-07-14 13:26:06 +02001295 * @return LY_ERR value.
1296 */
1297static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001298lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_options, uint32_t validate_options,
Radek Krejcicd5f6222020-11-12 08:54:13 +01001299 struct lyd_json_ctx **lydctx_p, enum LYJSON_PARSER_STATUS *status)
Radek Krejci1798aae2020-07-14 13:26:06 +02001300{
1301 LY_ERR ret = LY_SUCCESS;
1302 struct lyd_json_ctx *lydctx;
1303 size_t i, line = 1;
1304
Radek Krejcicd5f6222020-11-12 08:54:13 +01001305 assert(lydctx_p);
1306 assert(status);
1307
Radek Krejci1798aae2020-07-14 13:26:06 +02001308 /* init context */
1309 lydctx = calloc(1, sizeof *lydctx);
1310 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1311 lydctx->parse_options = parse_options;
1312 lydctx->validate_options = validate_options;
1313 lydctx->free = lyd_json_ctx_free;
Radek Krejci1798aae2020-07-14 13:26:06 +02001314
Radek Krejci284f31f2020-09-18 15:40:29 +02001315 /* starting top-level */
1316 for (i = 0; in->current[i] != '\0' && is_jsonws(in->current[i]); i++) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001317 if (in->current[i] == '\n') {
1318 /* new line */
Radek Krejci284f31f2020-09-18 15:40:29 +02001319 line++;
Michal Vasko61d76362020-10-07 10:47:30 +02001320 }
Radek Krejci284f31f2020-09-18 15:40:29 +02001321 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001322
Radek Krejci284f31f2020-09-18 15:40:29 +02001323 LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
Radek Krejcicd5f6222020-11-12 08:54:13 +01001324 *status = lyjson_ctx_status(lydctx->jsonctx, 0);
Radek Krejcibb27df32020-11-13 15:39:16 +01001325 if ((*status == LYJSON_END) || (*status == LYJSON_OBJECT_EMPTY) || (*status == LYJSON_OBJECT)) {
Radek Krejci284f31f2020-09-18 15:40:29 +02001326 *lydctx_p = lydctx;
1327 return LY_SUCCESS;
Radek Krejcicd5f6222020-11-12 08:54:13 +01001328 } else {
1329 /* expecting top-level object */
1330 LOGVAL(ctx, LY_VLOG_LINE, &line, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.",
1331 lyjson_token2str(*status));
1332 *lydctx_p = NULL;
Michal Vasko93509012020-11-13 10:26:09 +01001333 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
Radek Krejcicd5f6222020-11-12 08:54:13 +01001334 return LY_EVALID;
Radek Krejci284f31f2020-09-18 15:40:29 +02001335 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001336}
1337
1338LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001339lyd_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 +02001340 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejci1798aae2020-07-14 13:26:06 +02001341{
1342 LY_ERR ret = LY_SUCCESS;
1343 struct lyd_json_ctx *lydctx = NULL;
1344 enum LYJSON_PARSER_STATUS status;
1345
1346 assert(tree_p);
1347 *tree_p = NULL;
1348
Radek Krejcicd5f6222020-11-12 08:54:13 +01001349 ret = lyd_parse_json_init(ctx, in, parse_options, validate_options, &lydctx, &status);
1350 LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001351
Radek Krejcicd5f6222020-11-12 08:54:13 +01001352 assert(status == LYJSON_OBJECT);
Radek Krejci1798aae2020-07-14 13:26:06 +02001353
1354 /* read subtree(s) */
1355 while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
1356 ret = lydjson_subtree_r(lydctx, NULL, tree_p);
1357 LY_CHECK_GOTO(ret, cleanup);
1358
1359 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1360 }
1361
1362 /* finish linking metadata */
1363 ret = lydjson_metadata_finish(lydctx, tree_p);
1364 LY_CHECK_GOTO(ret, cleanup);
1365
1366cleanup:
1367 /* there should be no unresolved types stored */
Michal Vasko49c39d82020-11-06 17:20:27 +01001368 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1369 !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001370
1371 if (ret) {
1372 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1373 lyd_free_all(*tree_p);
1374 *tree_p = NULL;
1375 } else {
1376 *lydctx_p = (struct lyd_ctx *)lydctx;
1377 }
1378
1379 return ret;
1380}
1381
Michal Vasko2552ea32020-12-08 15:32:34 +01001382#if 0
Radek Krejci1798aae2020-07-14 13:26:06 +02001383/**
1384 * @brief Parse optional JSON envelope around the Notification data, including the eventTime data.
1385 *
1386 * @param[in] jsonctx JSON parser context
1387 * @param[out] envp_p Pointer to the created envelope opaq container.
Radek Krejcicd5f6222020-11-12 08:54:13 +01001388 * @param[out] status Storage for the current context's status
Radek Krejci1798aae2020-07-14 13:26:06 +02001389 * @return LY_SUCCESS if the envelope present and successfully parsed.
1390 * @return LY_ENOT in case there is not the expected envelope.
1391 * @return LY_ERR in case of parsing failure.
1392 */
1393static LY_ERR
Radek Krejcicd5f6222020-11-12 08:54:13 +01001394lydjson_notif_envelope(struct lyjson_ctx *jsonctx, struct lyd_node **envp_p, enum LYJSON_PARSER_STATUS *status_p)
Radek Krejci1798aae2020-07-14 13:26:06 +02001395{
1396 LY_ERR ret = LY_ENOT, r;
1397 const char *name, *prefix, *value = NULL;
1398 size_t name_len, prefix_len, value_len;
Radek Krejci857189e2020-09-01 13:26:36 +02001399 ly_bool is_attr, dynamic = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +02001400 enum LYJSON_PARSER_STATUS status;
1401 struct lyd_node *et;
1402
1403 *envp_p = NULL;
1404
1405 /* backup the context */
1406 lyjson_ctx_backup(jsonctx);
1407
1408 /* "notification" envelope */
1409 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
1410 LY_CHECK_GOTO(is_attr, cleanup);
1411 LY_CHECK_GOTO(prefix_len != 13 || strncmp(prefix, "ietf-restconf", 13), cleanup);
1412 LY_CHECK_GOTO(name_len != 12 || strncmp(name, "notification", name_len), cleanup);
1413
1414 r = lyjson_ctx_next(jsonctx, &status);
1415 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
1416 LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
1417
1418 /* "eventTime" child */
1419 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
1420 LY_CHECK_GOTO(prefix_len || is_attr, cleanup);
1421 LY_CHECK_GOTO(name_len != 9 || strncmp(name, "eventTime", name_len), cleanup);
1422
1423 /* go for the data */
1424 r = lyjson_ctx_next(jsonctx, &status);
1425 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
1426 LY_CHECK_GOTO(status != LYJSON_STRING, cleanup);
1427
1428 value = jsonctx->value;
1429 value_len = jsonctx->value_len;
1430 dynamic = jsonctx->dynamic;
1431 jsonctx->dynamic = 0;
1432
1433 r = lyjson_ctx_next(jsonctx, &status);
1434 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
1435 LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
1436 /* now the notificationContent is expected, which will be parsed by the caller */
1437
1438 /* create notification envelope */
Radek Krejcif13b87b2020-12-01 22:02:17 +01001439 ret = lyd_create_opaq(jsonctx->ctx, "notification", ly_strlen_const("notification"), NULL, 0,
1440 "ietf-restconf", ly_strlen_const("ietf-restconf"), "", ly_strlen_const(""), NULL, LY_PREF_JSON, NULL,
1441 LYD_NODEHINT_ENVELOPE, envp_p);
Radek Krejci1798aae2020-07-14 13:26:06 +02001442 LY_CHECK_GOTO(ret, cleanup);
1443 /* create notification envelope */
Radek Krejcif13b87b2020-12-01 22:02:17 +01001444 ret = lyd_create_opaq(jsonctx->ctx, "eventTime", ly_strlen_const("eventTime"), NULL, 0,
1445 "ietf-restconf", ly_strlen_const("ietf-restconf"), value, value_len, &dynamic, LY_PREF_JSON, NULL,
1446 LYD_VALHINT_STRING, &et);
Radek Krejci1798aae2020-07-14 13:26:06 +02001447 LY_CHECK_GOTO(ret, cleanup);
1448 /* insert eventTime into notification */
1449 lyd_insert_node(*envp_p, NULL, et);
1450
1451 ret = LY_SUCCESS;
Radek Krejcicd5f6222020-11-12 08:54:13 +01001452 *status_p = status;
Radek Krejci1798aae2020-07-14 13:26:06 +02001453cleanup:
1454 if (ret) {
1455 /* restore the context */
1456 lyjson_ctx_restore(jsonctx);
1457 if (dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +02001458 free((char *)value);
Radek Krejci1798aae2020-07-14 13:26:06 +02001459 }
1460 }
1461 return ret;
1462}
Michal Vasko79135ae2020-12-16 10:08:35 +01001463
Michal Vasko2552ea32020-12-08 15:32:34 +01001464#endif
Radek Krejci1798aae2020-07-14 13:26:06 +02001465
1466LY_ERR
1467lyd_parse_json_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
1468{
1469 LY_ERR ret = LY_SUCCESS;
1470 struct lyd_json_ctx *lydctx = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001471 struct lyd_node *tree = NULL;
1472 enum LYJSON_PARSER_STATUS status;
1473
1474 /* init */
Radek Krejcicd5f6222020-11-12 08:54:13 +01001475 ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx, &status);
1476 LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
1477
Radek Krejci1798aae2020-07-14 13:26:06 +02001478 lydctx->int_opts = LYD_INTOPT_NOTIF;
1479
Michal Vasko2552ea32020-12-08 15:32:34 +01001480#if 0
Radek Krejci1798aae2020-07-14 13:26:06 +02001481 /* parse "notification" and "eventTime", if present */
Radek Krejcicd5f6222020-11-12 08:54:13 +01001482 ret = lydjson_notif_envelope(lydctx->jsonctx, &ntf_e, &status);
Radek Krejci1798aae2020-07-14 13:26:06 +02001483 if (ret == LY_ENOT) {
1484 ret = LY_SUCCESS;
1485 } else if (ret) {
1486 goto cleanup;
1487 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001488#endif
Radek Krejci1798aae2020-07-14 13:26:06 +02001489
Radek Krejcicd5f6222020-11-12 08:54:13 +01001490 assert(status == LYJSON_OBJECT);
1491
Michal Vaskocf770e22020-08-12 13:21:43 +02001492 /* read subtree */
1493 ret = lydjson_subtree_r(lydctx, NULL, &tree);
1494 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001495
1496 /* finish linking metadata */
1497 ret = lydjson_metadata_finish(lydctx, &tree);
1498 LY_CHECK_GOTO(ret, cleanup);
1499
1500 /* make sure we have parsed some notification */
1501 if (!lydctx->op_node) {
1502 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1503 ret = LY_EVALID;
1504 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02001505 } else if (lydctx->jsonctx->in->current[0] && (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_OBJECT_CLOSED)) {
Michal Vaskocf770e22020-08-12 13:21:43 +02001506 LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02001507 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +02001508 ret = LY_EVALID;
1509 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001510 }
1511
Radek Krejci1798aae2020-07-14 13:26:06 +02001512 if (ntf_p) {
1513 *ntf_p = lydctx->op_node;
1514 }
1515 assert(tree);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001516 if (tree_p) {
1517 *tree_p = tree;
Radek Krejci1798aae2020-07-14 13:26:06 +02001518 }
1519
1520cleanup:
1521 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +01001522 assert(!lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count && !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001523
1524 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1525 if (ret) {
1526 lyd_free_all(tree);
Radek Krejci1798aae2020-07-14 13:26:06 +02001527 }
1528 return ret;
1529}
1530
Michal Vasko2552ea32020-12-08 15:32:34 +01001531#if 0
Radek Krejci1798aae2020-07-14 13:26:06 +02001532/**
1533 * @brief Parse optional JSON envelope around the processed content.
1534 *
1535 * @param[in] jsonctx JSON parser context
1536 * @param[in] parent Parent node (some other envelope).
1537 * @param[in] module_key Name of the module where the envelope element is expected.
1538 * @param[in] object_id Name of the envelope object.
1539 * @param[out] envp_p Pointer to the created envelope opaq container.
Radek Krejcicd5f6222020-11-12 08:54:13 +01001540 * @param[out] status Storage for the current context's status
Radek Krejci1798aae2020-07-14 13:26:06 +02001541 * @return LY_SUCCESS if the envelope present and successfully parsed.
1542 * @return LY_ENOT in case there is not the expected envelope.
1543 * @return LY_ERR in case of parsing failure.
1544 */
1545static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +02001546lydjson_object_envelope(struct lyjson_ctx *jsonctx, struct lyd_node *parent, const char *module_key,
Radek Krejcicd5f6222020-11-12 08:54:13 +01001547 const char *object_id, struct lyd_node **envp_p, enum LYJSON_PARSER_STATUS *status)
Radek Krejci1798aae2020-07-14 13:26:06 +02001548{
1549 LY_ERR ret = LY_ENOT, r;
1550 const char *name, *prefix;
1551 size_t name_len, prefix_len;
Radek Krejci857189e2020-09-01 13:26:36 +02001552 ly_bool is_attr;
Radek Krejci1798aae2020-07-14 13:26:06 +02001553
1554 *envp_p = NULL;
1555
1556 /* "id" envelope */
1557 lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
1558 LY_CHECK_GOTO(is_attr, cleanup);
1559 LY_CHECK_GOTO(lydjson_get_node_prefix(parent, prefix, prefix_len, &prefix, &prefix_len), cleanup);
1560 LY_CHECK_GOTO(prefix_len != strlen(module_key) || strncmp(prefix, module_key, prefix_len), cleanup);
1561 LY_CHECK_GOTO(name_len != strlen(object_id) || strncmp(name, object_id, name_len), cleanup);
1562
Radek Krejcicd5f6222020-11-12 08:54:13 +01001563 r = lyjson_ctx_next(jsonctx, status);
Radek Krejci1798aae2020-07-14 13:26:06 +02001564 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejcicd5f6222020-11-12 08:54:13 +01001565 LY_CHECK_GOTO(*status != LYJSON_OBJECT, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001566
1567 /* create the object envelope */
Michal Vasko501af032020-11-11 20:27:44 +01001568 ret = lyd_create_opaq(jsonctx->ctx, object_id, strlen(object_id), NULL, 0, module_key, ly_strlen(module_key), "", 0,
1569 NULL, LY_PREF_JSON, NULL, LYD_NODEHINT_ENVELOPE, envp_p);
Radek Krejci1798aae2020-07-14 13:26:06 +02001570 LY_CHECK_GOTO(ret, cleanup);
1571
1572 if (parent) {
1573 lyd_insert_node(parent, NULL, *envp_p);
1574 }
1575
1576 ret = LY_SUCCESS;
1577cleanup:
1578 return ret;
1579}
1580
1581static LY_ERR
Radek Krejcicd5f6222020-11-12 08:54:13 +01001582lydjson_object_envelope_close(struct lyjson_ctx *jsonctx, const char *object_id, enum LYJSON_PARSER_STATUS *status)
Radek Krejci1798aae2020-07-14 13:26:06 +02001583{
Radek Krejcicd5f6222020-11-12 08:54:13 +01001584 LY_CHECK_RET(lyjson_ctx_next(jsonctx, status));
1585 if (*status == LYJSON_END) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001586 LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LY_VCODE_EOF);
1587 return LY_EVALID;
Radek Krejcicd5f6222020-11-12 08:54:13 +01001588 } else if (*status != LYJSON_OBJECT_CLOSED) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001589 LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LYVE_SYNTAX, "Unexpected sibling member \"%.*s\" of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02001590 jsonctx->value_len, jsonctx->value, object_id);
Radek Krejci1798aae2020-07-14 13:26:06 +02001591 return LY_EVALID;
1592 }
1593 return LY_SUCCESS;
1594}
Michal Vasko79135ae2020-12-16 10:08:35 +01001595
Michal Vasko2552ea32020-12-08 15:32:34 +01001596#endif
Radek Krejci1798aae2020-07-14 13:26:06 +02001597
1598LY_ERR
1599lyd_parse_json_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
1600{
1601 LY_ERR ret = LY_SUCCESS;
1602 struct lyd_json_ctx *lydctx = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001603 struct lyd_node *tree = NULL;
Radek Krejcicd5f6222020-11-12 08:54:13 +01001604 enum LYJSON_PARSER_STATUS status;
Radek Krejci1798aae2020-07-14 13:26:06 +02001605
1606 /* init */
Radek Krejcicd5f6222020-11-12 08:54:13 +01001607 ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx, &status);
1608 LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
1609
Radek Krejci1798aae2020-07-14 13:26:06 +02001610 lydctx->int_opts = LYD_INTOPT_RPC;
1611
Michal Vasko2552ea32020-12-08 15:32:34 +01001612#if 0
Radek Krejci1798aae2020-07-14 13:26:06 +02001613 /* process envelope(s), if present */
1614
1615 /* process rpc */
Radek Krejcicd5f6222020-11-12 08:54:13 +01001616 ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc", &rpc_e, &status);
Radek Krejci1798aae2020-07-14 13:26:06 +02001617 if (ret == LY_ENOT) {
1618 ret = LY_SUCCESS;
1619 goto parse_content;
1620 } else if (ret) {
1621 goto cleanup;
1622 }
1623 /* process action */
Radek Krejcicd5f6222020-11-12 08:54:13 +01001624 ret = lydjson_object_envelope(lydctx->jsonctx, rpc_e, "yang", "action", &act_e, &status);
Radek Krejci1798aae2020-07-14 13:26:06 +02001625 if (ret == LY_ENOT) {
1626 ret = LY_SUCCESS;
1627 goto parse_content;
1628 } else if (ret) {
1629 goto cleanup;
1630 }
1631
1632parse_content:
Michal Vasko2552ea32020-12-08 15:32:34 +01001633#endif
Radek Krejcicd5f6222020-11-12 08:54:13 +01001634 assert(status == LYJSON_OBJECT);
Radek Krejci1798aae2020-07-14 13:26:06 +02001635
1636 /* read subtree(s) */
Michal Vasko2552ea32020-12-08 15:32:34 +01001637 ret = lydjson_subtree_r(lydctx, NULL, &tree);
Michal Vaskocf770e22020-08-12 13:21:43 +02001638 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001639
1640 /* finish linking metadata */
1641 ret = lydjson_metadata_finish(lydctx, &tree);
1642 LY_CHECK_GOTO(ret, cleanup);
1643
1644 /* make sure we have parsed some operation */
1645 if (!lydctx->op_node) {
Michal Vasko2552ea32020-12-08 15:32:34 +01001646 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the rpc/action node.");
Radek Krejci1798aae2020-07-14 13:26:06 +02001647 ret = LY_EVALID;
1648 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02001649 } else if (lydctx->jsonctx->in->current[0] && (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_OBJECT_CLOSED)) {
Michal Vaskocf770e22020-08-12 13:21:43 +02001650 LOGVAL(ctx, LY_VLOG_LINE, &lydctx->jsonctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02001651 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +02001652 ret = LY_EVALID;
1653 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +02001654 }
1655
Radek Krejci1798aae2020-07-14 13:26:06 +02001656 if (op_p) {
1657 *op_p = lydctx->op_node;
1658 }
1659 assert(tree);
1660 if (tree_p) {
Michal Vasko2552ea32020-12-08 15:32:34 +01001661 *tree_p = tree;
Radek Krejci1798aae2020-07-14 13:26:06 +02001662 }
1663
1664cleanup:
1665 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +01001666 assert(!lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count && !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001667
1668 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1669 if (ret) {
1670 lyd_free_all(tree);
Radek Krejci1798aae2020-07-14 13:26:06 +02001671 }
1672 return ret;
1673}
1674
1675LY_ERR
Michal Vasko2552ea32020-12-08 15:32:34 +01001676lyd_parse_json_reply(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
Radek Krejci1798aae2020-07-14 13:26:06 +02001677{
1678 LY_ERR ret = LY_SUCCESS;
1679 struct lyd_json_ctx *lydctx = NULL;
Michal Vasko2552ea32020-12-08 15:32:34 +01001680 struct lyd_node *tree = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +02001681 enum LYJSON_PARSER_STATUS status;
1682
1683 /* init */
Michal Vasko2552ea32020-12-08 15:32:34 +01001684 ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx, &status);
Radek Krejcicd5f6222020-11-12 08:54:13 +01001685 LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
1686
Radek Krejci1798aae2020-07-14 13:26:06 +02001687 lydctx->int_opts = LYD_INTOPT_REPLY;
1688
Michal Vasko2552ea32020-12-08 15:32:34 +01001689#if 0
Radek Krejci1798aae2020-07-14 13:26:06 +02001690 /* parse "rpc-reply", if any */
Radek Krejcicd5f6222020-11-12 08:54:13 +01001691 ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc-reply", &rpcr_e, &status);
Radek Krejci1798aae2020-07-14 13:26:06 +02001692 if (ret == LY_ENOT) {
1693 ret = LY_SUCCESS;
1694 } else if (ret) {
1695 goto cleanup;
1696 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001697#endif
Radek Krejci1798aae2020-07-14 13:26:06 +02001698
Radek Krejci1798aae2020-07-14 13:26:06 +02001699 assert(status == LYJSON_OBJECT);
1700
1701 /* read subtree(s) */
1702 while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
Michal Vasko2552ea32020-12-08 15:32:34 +01001703 ret = lydjson_subtree_r(lydctx, NULL, &tree);
Radek Krejci1798aae2020-07-14 13:26:06 +02001704 LY_CHECK_GOTO(ret, cleanup);
1705
1706 status = lyjson_ctx_status(lydctx->jsonctx, 0);
1707 }
1708
1709 /* finish linking metadata */
Michal Vasko2552ea32020-12-08 15:32:34 +01001710 ret = lydjson_metadata_finish(lydctx, &tree);
Radek Krejci1798aae2020-07-14 13:26:06 +02001711 LY_CHECK_GOTO(ret, cleanup);
1712
Radek Krejci1798aae2020-07-14 13:26:06 +02001713 if (op_p) {
Michal Vasko79135ae2020-12-16 10:08:35 +01001714 *op_p = lydctx->op_node;
Michal Vasko4189c0f2020-08-13 09:05:22 +02001715 }
1716 if (tree_p) {
1717 *tree_p = tree;
Radek Krejci1798aae2020-07-14 13:26:06 +02001718 }
1719
1720cleanup:
1721 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +01001722 assert(!lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count && !lydctx->node_when.count));
Radek Krejci1798aae2020-07-14 13:26:06 +02001723
1724 lyd_json_ctx_free((struct lyd_ctx *)lydctx);
1725 if (ret) {
Michal Vasko2552ea32020-12-08 15:32:34 +01001726 lyd_free_all(tree);
Radek Krejci1798aae2020-07-14 13:26:06 +02001727 }
1728 return ret;
Michal Vasko90932a92020-02-12 14:33:03 +01001729}