blob: 070c9c35781446e1aaf5c778a2fa3fa82f54a137 [file] [log] [blame]
Michal Vasko60ea6352020-06-29 13:39:39 +02001/**
2 * @file parser_lyb.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief LYB data parser for libyang
5 *
6 * Copyright (c) 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "lyb.h"
16
17#include <assert.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020018#include <stdint.h>
Michal Vasko60ea6352020-06-29 13:39:39 +020019#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "common.h"
24#include "compat.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020025#include "context.h"
26#include "dict.h"
Radek Krejci47fab892020-11-05 17:02:41 +010027#include "hash_table.h"
28#include "in.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020029#include "in_internal.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020030#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020031#include "parser_data.h"
32#include "parser_internal.h"
Radek Krejci77114102021-03-10 15:21:57 +010033#include "set.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020034#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010035#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020036#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010037#include "tree_edit.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020038#include "tree_schema.h"
39#include "validation.h"
Michal Vasko6b5cb2a2020-11-11 19:11:21 +010040#include "xml.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020041
Radek Krejci1798aae2020-07-14 13:26:06 +020042void
43lylyb_ctx_free(struct lylyb_ctx *ctx)
44{
45 LY_ARRAY_COUNT_TYPE u;
46
47 LY_ARRAY_FREE(ctx->subtrees);
48 LY_ARRAY_FREE(ctx->models);
49
50 LY_ARRAY_FOR(ctx->sib_hts, u) {
51 lyht_free(ctx->sib_hts[u].ht);
52 }
53 LY_ARRAY_FREE(ctx->sib_hts);
54
55 free(ctx);
56}
57
58void
59lyd_lyb_ctx_free(struct lyd_ctx *lydctx)
60{
61 struct lyd_lyb_ctx *ctx = (struct lyd_lyb_ctx *)lydctx;
62
63 lyd_ctx_free(lydctx);
64 lylyb_ctx_free(ctx->lybctx);
65 free(ctx);
66}
67
Michal Vasko60ea6352020-06-29 13:39:39 +020068/**
69 * @brief Read YANG data from LYB input. Metadata are handled transparently and not returned.
70 *
71 * @param[in] buf Destination buffer.
72 * @param[in] count Number of bytes to read.
73 * @param[in] lybctx LYB context.
74 */
75static void
Radek Krejci1798aae2020-07-14 13:26:06 +020076lyb_read(uint8_t *buf, size_t count, struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +020077{
Michal Vaskofd69e1d2020-07-03 11:57:17 +020078 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +020079 struct lyd_lyb_subtree *empty;
80 size_t to_read;
81 uint8_t meta_buf[LYB_META_BYTES];
82
83 assert(lybctx);
84
85 while (1) {
86 /* check for fully-read (empty) data chunks */
87 to_read = count;
88 empty = NULL;
89 LY_ARRAY_FOR(lybctx->subtrees, u) {
90 /* we want the innermost chunks resolved first, so replace previous empty chunks,
91 * also ignore chunks that are completely finished, there is nothing for us to do */
92 if ((lybctx->subtrees[u].written <= to_read) && lybctx->subtrees[u].position) {
93 /* empty chunk, do not read more */
94 to_read = lybctx->subtrees[u].written;
95 empty = &lybctx->subtrees[u];
96 }
97 }
98
99 if (!empty && !count) {
100 break;
101 }
102
103 /* we are actually reading some data, not just finishing another chunk */
104 if (to_read) {
105 if (buf) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200106 ly_in_read(lybctx->in, buf, to_read);
107 } else {
108 ly_in_skip(lybctx->in, to_read);
Michal Vasko60ea6352020-06-29 13:39:39 +0200109 }
110
111 LY_ARRAY_FOR(lybctx->subtrees, u) {
112 /* decrease all written counters */
113 lybctx->subtrees[u].written -= to_read;
114 assert(lybctx->subtrees[u].written <= LYB_SIZE_MAX);
115 }
116 /* decrease count/buf */
117 count -= to_read;
118 if (buf) {
119 buf += to_read;
120 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200121 }
122
123 if (empty) {
124 /* read the next chunk meta information */
Michal Vasko63f3d842020-07-08 10:10:14 +0200125 ly_in_read(lybctx->in, meta_buf, LYB_META_BYTES);
Michal Vasko60ea6352020-06-29 13:39:39 +0200126 empty->written = meta_buf[0];
127 empty->inner_chunks = meta_buf[1];
128
129 /* remember whether there is a following chunk or not */
130 empty->position = (empty->written == LYB_SIZE_MAX ? 1 : 0);
Michal Vasko60ea6352020-06-29 13:39:39 +0200131 }
132 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200133}
134
135/**
136 * @brief Read a number.
137 *
138 * @param[in] num Destination buffer.
139 * @param[in] num_size Size of @p num.
140 * @param[in] bytes Number of bytes to read.
141 * @param[in] lybctx LYB context.
142 */
143static void
Radek Krejci1798aae2020-07-14 13:26:06 +0200144lyb_read_number(void *num, size_t num_size, size_t bytes, struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +0200145{
146 uint64_t buf = 0;
147
148 lyb_read((uint8_t *)&buf, bytes, lybctx);
149
150 /* correct byte order */
151 buf = le64toh(buf);
152
153 switch (num_size) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100154 case sizeof(uint8_t):
Michal Vasko60ea6352020-06-29 13:39:39 +0200155 *((uint8_t *)num) = buf;
156 break;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100157 case sizeof(uint16_t):
Michal Vasko60ea6352020-06-29 13:39:39 +0200158 *((uint16_t *)num) = buf;
159 break;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100160 case sizeof(uint32_t):
Michal Vasko60ea6352020-06-29 13:39:39 +0200161 *((uint32_t *)num) = buf;
162 break;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100163 case sizeof(uint64_t):
Michal Vasko60ea6352020-06-29 13:39:39 +0200164 *((uint64_t *)num) = buf;
165 break;
166 default:
167 LOGINT(lybctx->ctx);
168 }
169}
170
171/**
172 * @brief Read a string.
173 *
174 * @param[in] str Destination buffer, is allocated.
175 * @param[in] with_length Whether the string is preceded with its length or it ends at the end of this subtree.
176 * @param[in] lybctx LYB context.
177 * @return LY_ERR value.
178 */
179static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +0200180lyb_read_string(char **str, ly_bool with_length, struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +0200181{
Radek Krejci857189e2020-09-01 13:26:36 +0200182 ly_bool next_chunk = 0;
Michal Vasko60ea6352020-06-29 13:39:39 +0200183 size_t len = 0, cur_len;
184
185 *str = NULL;
186
187 if (with_length) {
188 lyb_read_number(&len, sizeof len, 2, lybctx);
189 } else {
190 /* read until the end of this subtree */
191 len = LYB_LAST_SUBTREE(lybctx).written;
192 if (LYB_LAST_SUBTREE(lybctx).position) {
193 next_chunk = 1;
194 }
195 }
196
197 *str = malloc((len + 1) * sizeof **str);
198 LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
199
200 lyb_read((uint8_t *)*str, len, lybctx);
201
202 while (next_chunk) {
203 cur_len = LYB_LAST_SUBTREE(lybctx).written;
204 if (LYB_LAST_SUBTREE(lybctx).position) {
205 next_chunk = 1;
206 } else {
207 next_chunk = 0;
208 }
209
210 *str = ly_realloc(*str, (len + cur_len + 1) * sizeof **str);
211 LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
212
213 lyb_read(((uint8_t *)*str) + len, cur_len, lybctx);
214
215 len += cur_len;
216 }
217
218 ((char *)*str)[len] = '\0';
219 return LY_SUCCESS;
220}
221
222/**
223 * @brief Stop the current subtree - change LYB context state.
224 *
225 * @param[in] lybctx LYB context.
226 * @return LY_ERR value.
227 */
228static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200229lyb_read_stop_subtree(struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +0200230{
231 if (LYB_LAST_SUBTREE(lybctx).written) {
232 LOGINT_RET(lybctx->ctx);
233 }
234
235 LY_ARRAY_DECREMENT(lybctx->subtrees);
236 return LY_SUCCESS;
237}
238
239/**
240 * @brief Start a new subtree - change LYB context state but also read the expected metadata.
241 *
242 * @param[in] lybctx LYB context.
243 * @return LY_ERR value.
244 */
245static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200246lyb_read_start_subtree(struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +0200247{
248 uint8_t meta_buf[LYB_META_BYTES];
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200249 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200250
Radek Krejcic7d13e32020-12-09 12:32:24 +0100251 u = LY_ARRAY_COUNT(lybctx->subtrees);
Michal Vasko60ea6352020-06-29 13:39:39 +0200252 if (u == lybctx->subtree_size) {
253 LY_ARRAY_CREATE_RET(lybctx->ctx, lybctx->subtrees, u + LYB_SUBTREE_STEP, LY_EMEM);
254 lybctx->subtree_size = u + LYB_SUBTREE_STEP;
255 }
256
Michal Vasko63f3d842020-07-08 10:10:14 +0200257 LY_CHECK_RET(ly_in_read(lybctx->in, meta_buf, LYB_META_BYTES));
Michal Vasko60ea6352020-06-29 13:39:39 +0200258
259 LY_ARRAY_INCREMENT(lybctx->subtrees);
260 LYB_LAST_SUBTREE(lybctx).written = meta_buf[0];
261 LYB_LAST_SUBTREE(lybctx).inner_chunks = meta_buf[LYB_SIZE_BYTES];
262 LYB_LAST_SUBTREE(lybctx).position = (LYB_LAST_SUBTREE(lybctx).written == LYB_SIZE_MAX ? 1 : 0);
263
Michal Vasko60ea6352020-06-29 13:39:39 +0200264 return LY_SUCCESS;
265}
266
267/**
268 * @brief Parse YANG model info.
269 *
270 * @param[in] lybctx LYB context.
271 * @param[out] mod Parsed module.
272 * @return LY_ERR value.
273 */
274static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200275lyb_parse_model(struct lylyb_ctx *lybctx, uint32_t parse_options, const struct lys_module **mod)
Michal Vasko60ea6352020-06-29 13:39:39 +0200276{
277 LY_ERR ret = LY_SUCCESS;
Radek Krejcif13b87b2020-12-01 22:02:17 +0100278 char *mod_name = NULL, mod_rev[LY_REV_SIZE];
Michal Vasko60ea6352020-06-29 13:39:39 +0200279 uint16_t rev;
280
281 /* model name */
282 ret = lyb_read_string(&mod_name, 1, lybctx);
283 LY_CHECK_GOTO(ret, cleanup);
284
285 /* revision */
286 lyb_read_number(&rev, sizeof rev, 2, lybctx);
287
288 if (!mod_name[0]) {
289 /* opaq node, no module */
290 *mod = NULL;
291 goto cleanup;
292 }
293
294 if (rev) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100295 sprintf(mod_rev, "%04u-%02u-%02u", ((rev & LYB_REV_YEAR_MASK) >> LYB_REV_YEAR_SHIFT) + LYB_REV_YEAR_OFFSET,
296 (rev & LYB_REV_MONTH_MASK) >> LYB_REV_MONTH_SHIFT, rev & LYB_REV_DAY_MASK);
Michal Vasko60ea6352020-06-29 13:39:39 +0200297 *mod = ly_ctx_get_module(lybctx->ctx, mod_name, mod_rev);
Radek Krejci1798aae2020-07-14 13:26:06 +0200298 if ((parse_options & LYD_PARSE_LYB_MOD_UPDATE) && !(*mod)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200299 /* try to use an updated module */
300 *mod = ly_ctx_get_module_implemented(lybctx->ctx, mod_name);
301 if (*mod && (!(*mod)->revision || (strcmp((*mod)->revision, mod_rev) < 0))) {
302 /* not an implemented module in a newer revision */
303 *mod = NULL;
304 }
305 }
306 } else {
307 *mod = ly_ctx_get_module_latest(lybctx->ctx, mod_name);
308 }
309 /* TODO data_clb supported?
310 if (lybctx->ctx->data_clb) {
311 if (!*mod) {
312 *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, NULL, 0, lybctx->ctx->data_clb_data);
313 } else if (!(*mod)->implemented) {
314 *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, (*mod)->ns, LY_MODCLB_NOT_IMPLEMENTED, lybctx->ctx->data_clb_data);
315 }
316 }*/
317
318 if (!*mod || !(*mod)->implemented) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200319 if (parse_options & LYD_PARSE_STRICT) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200320 if (!*mod) {
321 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, missing module \"%s%s%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200322 mod_name, rev ? "@" : "", rev ? mod_rev : "");
Michal Vasko60ea6352020-06-29 13:39:39 +0200323 } else if (!(*mod)->implemented) {
324 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, module \"%s%s%s\" not implemented.",
Michal Vasko69730152020-10-09 16:30:07 +0200325 mod_name, rev ? "@" : "", rev ? mod_rev : "");
Michal Vasko60ea6352020-06-29 13:39:39 +0200326 }
327 ret = LY_EINVAL;
328 goto cleanup;
329 }
330
331 }
332
Michal Vasko85d9edc2021-04-22 09:15:05 +0200333 if (*mod) {
334 /* fill cached hashes, if not already */
335 lyb_cache_module_hash(*mod);
336 }
Michal Vasko11f76c82021-04-15 14:36:14 +0200337
Michal Vasko60ea6352020-06-29 13:39:39 +0200338cleanup:
339 free(mod_name);
340 return ret;
341}
342
343/**
344 * @brief Parse YANG node metadata.
345 *
346 * @param[in] lybctx LYB context.
Michal Vasko60ea6352020-06-29 13:39:39 +0200347 * @param[out] meta Parsed metadata.
348 * @return LY_ERR value.
349 */
350static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200351lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, struct lyd_meta **meta)
Michal Vasko60ea6352020-06-29 13:39:39 +0200352{
353 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +0200354 ly_bool dynamic;
Michal Vasko60ea6352020-06-29 13:39:39 +0200355 uint8_t i, count = 0;
Michal Vasko1e5d5612020-07-03 13:29:26 +0200356 char *meta_name = NULL, *meta_value;
Michal Vasko60ea6352020-06-29 13:39:39 +0200357 const struct lys_module *mod;
358
359 /* read number of attributes stored */
Radek Krejci1798aae2020-07-14 13:26:06 +0200360 lyb_read(&count, 1, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200361
362 /* read attributes */
363 for (i = 0; i < count; ++i) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200364 ret = lyb_read_start_subtree(lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200365 LY_CHECK_GOTO(ret, cleanup);
366
367 /* find model */
Michal Vaskoe0665742021-02-11 11:08:44 +0100368 ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_opts, &mod);
Michal Vasko60ea6352020-06-29 13:39:39 +0200369 LY_CHECK_GOTO(ret, cleanup);
370
371 if (!mod) {
372 /* skip it */
373 do {
Radek Krejci1798aae2020-07-14 13:26:06 +0200374 lyb_read(NULL, LYB_LAST_SUBTREE(lybctx->lybctx).written, lybctx->lybctx);
375 } while (LYB_LAST_SUBTREE(lybctx->lybctx).written);
Michal Vasko60ea6352020-06-29 13:39:39 +0200376 goto stop_subtree;
377 }
378
379 /* meta name */
Radek Krejci1798aae2020-07-14 13:26:06 +0200380 ret = lyb_read_string(&meta_name, 1, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200381 LY_CHECK_GOTO(ret, cleanup);
382
383 /* meta value */
Radek Krejci1798aae2020-07-14 13:26:06 +0200384 ret = lyb_read_string(&meta_value, 0, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200385 LY_CHECK_GOTO(ret, cleanup);
386 dynamic = 1;
387
388 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200389 ret = lyd_parser_create_meta((struct lyd_ctx *)lybctx, NULL, meta, mod, meta_name, strlen(meta_name), meta_value,
Michal Vasko69730152020-10-09 16:30:07 +0200390 ly_strlen(meta_value), &dynamic, LY_PREF_JSON, NULL, LYD_HINT_DATA);
Michal Vasko60ea6352020-06-29 13:39:39 +0200391
392 /* free strings */
393 free(meta_name);
394 meta_name = NULL;
395 if (dynamic) {
396 free(meta_value);
397 dynamic = 0;
398 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200399
Radek Krejci1798aae2020-07-14 13:26:06 +0200400 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +0200401
402stop_subtree:
Radek Krejci1798aae2020-07-14 13:26:06 +0200403 ret = lyb_read_stop_subtree(lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200404 LY_CHECK_GOTO(ret, cleanup);
405 }
406
407cleanup:
408 free(meta_name);
Michal Vasko60ea6352020-06-29 13:39:39 +0200409 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200410 lyd_free_meta_siblings(*meta);
Michal Vasko60ea6352020-06-29 13:39:39 +0200411 *meta = NULL;
412 }
413 return ret;
414}
415
416/**
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100417 * @brief Parse format-specific prefix data.
Michal Vasko60ea6352020-06-29 13:39:39 +0200418 *
419 * @param[in] lybctx LYB context.
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100420 * @param[in] format Prefix data format.
421 * @param[out] prefix_data Parsed prefix data.
Michal Vasko60ea6352020-06-29 13:39:39 +0200422 * @return LY_ERR value.
423 */
424static LY_ERR
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100425lyb_parse_prefix_data(struct lylyb_ctx *lybctx, LY_PREFIX_FORMAT format, void **prefix_data)
Michal Vasko60ea6352020-06-29 13:39:39 +0200426{
427 LY_ERR ret = LY_SUCCESS;
428 uint8_t count, i;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100429 struct ly_set *set = NULL;
430 struct lyxml_ns *ns = NULL;
Michal Vasko60ea6352020-06-29 13:39:39 +0200431
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100432 switch (format) {
433 case LY_PREF_XML:
434 /* read count */
435 lyb_read(&count, 1, lybctx);
436 if (!count) {
437 return LY_SUCCESS;
438 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200439
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100440 /* read all NS elements */
441 LY_CHECK_GOTO(ret = ly_set_new(&set), cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +0200442
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100443 for (i = 0; i < count; ++i) {
444 ns = calloc(1, sizeof *ns);
Michal Vasko60ea6352020-06-29 13:39:39 +0200445
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100446 /* prefix */
447 LY_CHECK_GOTO(ret = lyb_read_string(&ns->prefix, 1, lybctx), cleanup);
448
449 /* namespace */
450 LY_CHECK_GOTO(ret = lyb_read_string(&ns->uri, 1, lybctx), cleanup);
451
452 LY_CHECK_GOTO(ret = ly_set_add(set, ns, 1, NULL), cleanup);
453 ns = NULL;
454 }
455
456 *prefix_data = set;
457 break;
458 case LY_PREF_JSON:
459 /* nothing stored */
460 break;
461 default:
462 LOGINT(lybctx->ctx);
463 ret = LY_EINT;
464 break;
Michal Vasko60ea6352020-06-29 13:39:39 +0200465 }
466
467cleanup:
468 if (ret) {
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100469 ly_free_prefix_data(format, set);
470 if (ns) {
471 free(ns->prefix);
472 free(ns->uri);
473 free(ns);
474 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200475 }
476 return ret;
477}
478
479/**
480 * @brief Parse opaque attributes.
481 *
482 * @param[in] lybctx LYB context.
483 * @param[out] attr Parsed attributes.
484 * @return LY_ERR value.
485 */
486static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200487lyb_parse_attributes(struct lylyb_ctx *lybctx, struct lyd_attr **attr)
Michal Vasko60ea6352020-06-29 13:39:39 +0200488{
489 LY_ERR ret = LY_SUCCESS;
490 uint8_t count, i;
Radek Krejci1798aae2020-07-14 13:26:06 +0200491 struct lyd_attr *attr2;
492 char *prefix = NULL, *module_name = NULL, *name = NULL, *value = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200493 ly_bool dynamic = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100494 LY_PREFIX_FORMAT format = 0;
495 void *val_prefix_data = NULL;
Michal Vasko60ea6352020-06-29 13:39:39 +0200496
497 /* read count */
498 lyb_read(&count, 1, lybctx);
499
500 /* read attributes */
501 for (i = 0; i < count; ++i) {
502 ret = lyb_read_start_subtree(lybctx);
503 LY_CHECK_GOTO(ret, cleanup);
504
Michal Vasko0fdcd242020-11-11 19:12:30 +0100505 /* prefix, may be empty */
Michal Vasko60ea6352020-06-29 13:39:39 +0200506 ret = lyb_read_string(&prefix, 1, lybctx);
507 LY_CHECK_GOTO(ret, cleanup);
508 if (!prefix[0]) {
509 free(prefix);
510 prefix = NULL;
511 }
512
513 /* namespace, may be empty */
Radek Krejci1798aae2020-07-14 13:26:06 +0200514 ret = lyb_read_string(&module_name, 1, lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200515 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200516 if (!module_name[0]) {
517 free(module_name);
518 module_name = NULL;
Michal Vasko60ea6352020-06-29 13:39:39 +0200519 }
520
521 /* name */
522 ret = lyb_read_string(&name, 1, lybctx);
523 LY_CHECK_GOTO(ret, cleanup);
524
Michal Vasko60ea6352020-06-29 13:39:39 +0200525 /* format */
526 lyb_read((uint8_t *)&format, 1, lybctx);
527
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100528 /* value prefixes */
529 ret = lyb_parse_prefix_data(lybctx, format, &val_prefix_data);
530 LY_CHECK_GOTO(ret, cleanup);
531
Michal Vasko60ea6352020-06-29 13:39:39 +0200532 /* value */
533 ret = lyb_read_string(&value, 0, lybctx);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100534 LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +0200535 dynamic = 1;
536
537 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100538 ret = lyd_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), prefix, ly_strlen(prefix), module_name,
539 ly_strlen(module_name), value, ly_strlen(value), &dynamic, format, val_prefix_data, 0);
Michal Vasko60ea6352020-06-29 13:39:39 +0200540 LY_CHECK_GOTO(ret, cleanup);
541
542 free(prefix);
543 prefix = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200544 free(module_name);
545 module_name = NULL;
Michal Vasko60ea6352020-06-29 13:39:39 +0200546 free(name);
547 name = NULL;
Michal Vasko60ea6352020-06-29 13:39:39 +0200548 assert(!dynamic);
549 value = NULL;
550
551 if (!*attr) {
552 *attr = attr2;
553 }
554
555 ret = lyb_read_stop_subtree(lybctx);
556 LY_CHECK_GOTO(ret, cleanup);
557 }
558
559cleanup:
560 free(prefix);
Radek Krejci1798aae2020-07-14 13:26:06 +0200561 free(module_name);
Michal Vasko60ea6352020-06-29 13:39:39 +0200562 free(name);
563 if (dynamic) {
564 free(value);
565 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200566 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200567 lyd_free_attr_siblings(lybctx->ctx, *attr);
Michal Vasko60ea6352020-06-29 13:39:39 +0200568 *attr = NULL;
569 }
570 return ret;
571}
572
573/**
574 * @brief Check whether a schema node matches a hash(es).
575 *
576 * @param[in] sibling Schema node to check.
577 * @param[in] hash Hash array to check.
578 * @param[in] hash_count Number of hashes in @p hash.
579 * @return non-zero if matches,
580 * @return 0 if not.
581 */
582static int
583lyb_is_schema_hash_match(struct lysc_node *sibling, LYB_HASH *hash, uint8_t hash_count)
584{
585 LYB_HASH sibling_hash;
586 uint8_t i;
587
588 /* compare all the hashes starting from collision ID 0 */
589 for (i = 0; i < hash_count; ++i) {
Michal Vasko11f76c82021-04-15 14:36:14 +0200590 sibling_hash = lyb_get_hash(sibling, i);
Michal Vasko60ea6352020-06-29 13:39:39 +0200591 if (sibling_hash != hash[i]) {
592 return 0;
593 }
594 }
595
596 return 1;
597}
598
599/**
Michal Vasko60ea6352020-06-29 13:39:39 +0200600 * @brief Parse schema node hash.
601 *
602 * @param[in] lybctx LYB context.
603 * @param[in] sparent Schema parent, must be set if @p mod is not.
604 * @param[in] mod Module of the top-level node, must be set if @p sparent is not.
605 * @param[out] snode Parsed found schema node, may be NULL if opaque.
606 * @return LY_ERR value.
607 */
608static LY_ERR
609lyb_parse_schema_hash(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, const struct lys_module *mod,
Radek Krejci0f969882020-08-21 16:56:47 +0200610 const struct lysc_node **snode)
Michal Vasko60ea6352020-06-29 13:39:39 +0200611{
612 LY_ERR ret;
613 uint8_t i, j;
614 const struct lysc_node *sibling;
615 LYB_HASH hash[LYB_HASH_BITS - 1];
Radek Krejci1deb5be2020-08-26 16:43:36 +0200616 uint32_t getnext_opts;
Michal Vasko60ea6352020-06-29 13:39:39 +0200617
618 *snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100619 getnext_opts = lybctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko60ea6352020-06-29 13:39:39 +0200620
621 /* read the first hash */
Radek Krejci1798aae2020-07-14 13:26:06 +0200622 lyb_read(&hash[0], sizeof *hash, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200623
624 if (!hash[0]) {
625 /* opaque node */
626 return LY_SUCCESS;
627 }
628
629 /* based on the first hash read all the other ones, if any */
630 for (i = 0; !(hash[0] & (LYB_HASH_COLLISION_ID >> i)); ++i) {
631 if (i > LYB_HASH_BITS) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200632 LOGINT_RET(lybctx->lybctx->ctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200633 }
634 }
635
636 /* move the first hash on its accurate position */
637 hash[i] = hash[0];
638
639 /* read the rest of hashes */
640 for (j = i; j; --j) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200641 lyb_read(&hash[j - 1], sizeof *hash, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200642
643 /* correct collision ID */
644 assert(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)));
645 /* preceded with zeros */
646 assert(!(hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))));
647 }
648
649 /* find our node with matching hashes */
650 sibling = NULL;
Radek Krejcif16e2542021-02-17 15:39:23 +0100651 while (1) {
652 if (!sparent && lybctx->ext) {
653 sibling = lys_getnext_ext(sibling, sparent, lybctx->ext, getnext_opts);
654 } else {
655 sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts);
656 }
657 if (!sibling) {
658 break;
659 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200660 /* skip schema nodes from models not present during printing */
Michal Vasko69730152020-10-09 16:30:07 +0200661 if (lyb_has_schema_model(sibling, lybctx->lybctx->models) &&
662 lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, i + 1)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200663 /* match found */
664 break;
665 }
666 }
667
Michal Vaskoe0665742021-02-11 11:08:44 +0100668 if (!sibling && (lybctx->parse_opts & LYD_PARSE_STRICT)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100669 if (lybctx->ext) {
670 LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a node from \"%s\" extension instance node.",
671 lybctx->ext->def->name);
672 } else if (mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100673 LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
Michal Vasko69730152020-10-09 16:30:07 +0200674 " from \"%s\".", mod->name);
Michal Vasko60ea6352020-06-29 13:39:39 +0200675 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100676 LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a child node"
Michal Vasko69730152020-10-09 16:30:07 +0200677 " of \"%s\".", sparent->name);
Michal Vasko60ea6352020-06-29 13:39:39 +0200678 }
679 return LY_EVALID;
Radek Krejci1798aae2020-07-14 13:26:06 +0200680 } else if (sibling && (ret = lyd_parser_check_schema((struct lyd_ctx *)lybctx, sibling))) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200681 return ret;
682 }
683
684 *snode = sibling;
685 return LY_SUCCESS;
686}
687
688/**
689 * @brief Read until the end of the current subtree.
690 *
691 * @param[in] lybctx LYB context.
692 */
693static void
Radek Krejci1798aae2020-07-14 13:26:06 +0200694lyb_skip_subtree(struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +0200695{
Michal Vasko60ea6352020-06-29 13:39:39 +0200696 do {
697 /* first skip any meta information inside */
Michal Vasko63f3d842020-07-08 10:10:14 +0200698 ly_in_skip(lybctx->in, LYB_LAST_SUBTREE(lybctx).inner_chunks * LYB_META_BYTES);
Michal Vasko60ea6352020-06-29 13:39:39 +0200699
700 /* then read data */
701 lyb_read(NULL, LYB_LAST_SUBTREE(lybctx).written, lybctx);
702 } while (LYB_LAST_SUBTREE(lybctx).written);
703}
704
705/**
706 * @brief Parse LYB subtree.
707 *
708 * @param[in] lybctx LYB context.
709 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
710 * @param[in,out] first First top-level sibling, must be set if @p parent is not.
711 * @return LY_ERR value.
712 */
713static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100714lyb_parse_subtree_r(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
Michal Vasko60ea6352020-06-29 13:39:39 +0200715{
716 LY_ERR ret = LY_SUCCESS;
717 struct lyd_node *node = NULL, *tree;
718 const struct lys_module *mod;
719 const struct lysc_node *snode = NULL;
720 struct lyd_meta *meta = NULL, *m;
Radek Krejci1798aae2020-07-14 13:26:06 +0200721 struct lyd_attr *attr = NULL, *a;
Michal Vasko60ea6352020-06-29 13:39:39 +0200722 LYD_ANYDATA_VALUETYPE value_type;
Radek Krejci1798aae2020-07-14 13:26:06 +0200723 char *value = NULL, *name = NULL, *prefix = NULL, *module_key = NULL;
Michal Vasko9afe3df2021-02-05 16:33:50 +0100724 const char *val_dict;
Radek Krejci857189e2020-09-01 13:26:36 +0200725 ly_bool dynamic = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100726 LY_PREFIX_FORMAT format = 0;
727 void *val_prefix_data = NULL;
Michal Vaskoc5e866a2020-11-04 17:09:26 +0100728 uint32_t prev_lo, flags;
Radek Krejci1798aae2020-07-14 13:26:06 +0200729 const struct ly_ctx *ctx = lybctx->lybctx->ctx;
Michal Vasko60ea6352020-06-29 13:39:39 +0200730
731 /* register a new subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200732 LY_CHECK_GOTO(ret = lyb_read_start_subtree(lybctx->lybctx), cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +0200733
734 if (!parent) {
735 /* top-level, read module name */
Michal Vaskoe0665742021-02-11 11:08:44 +0100736 ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_opts, &mod);
Michal Vasko60ea6352020-06-29 13:39:39 +0200737 LY_CHECK_GOTO(ret, cleanup);
738
739 /* read hash, find the schema node starting from mod */
740 ret = lyb_parse_schema_hash(lybctx, NULL, mod, &snode);
741 LY_CHECK_GOTO(ret, cleanup);
742 } else {
743 /* read hash, find the schema node starting from parent schema */
744 ret = lyb_parse_schema_hash(lybctx, parent->schema, NULL, &snode);
745 LY_CHECK_GOTO(ret, cleanup);
746 }
747
Michal Vaskoe0665742021-02-11 11:08:44 +0100748 if (!snode && !(lybctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200749 /* unknown data, skip them */
Radek Krejci1798aae2020-07-14 13:26:06 +0200750 lyb_skip_subtree(lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200751 goto stop_subtree;
Radek Krejci0f969882020-08-21 16:56:47 +0200752 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200753
754 /* create metadata/attributes */
755 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200756 ret = lyb_parse_metadata(lybctx, &meta);
Michal Vasko60ea6352020-06-29 13:39:39 +0200757 LY_CHECK_GOTO(ret, cleanup);
758 } else {
Radek Krejci1798aae2020-07-14 13:26:06 +0200759 ret = lyb_parse_attributes(lybctx->lybctx, &attr);
Michal Vasko60ea6352020-06-29 13:39:39 +0200760 LY_CHECK_GOTO(ret, cleanup);
761 }
762
Michal Vaskoc5e866a2020-11-04 17:09:26 +0100763 /* read flags */
764 lyb_read_number(&flags, sizeof flags, sizeof flags, lybctx->lybctx);
765
Michal Vasko60ea6352020-06-29 13:39:39 +0200766 if (!snode) {
767 /* parse prefix */
Radek Krejci1798aae2020-07-14 13:26:06 +0200768 ret = lyb_read_string(&prefix, 1, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200769 LY_CHECK_GOTO(ret, cleanup);
770
Radek Krejci1798aae2020-07-14 13:26:06 +0200771 /* parse module key */
772 ret = lyb_read_string(&module_key, 1, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200773 LY_CHECK_GOTO(ret, cleanup);
774
775 /* parse name */
Radek Krejci1798aae2020-07-14 13:26:06 +0200776 ret = lyb_read_string(&name, 1, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200777 LY_CHECK_GOTO(ret, cleanup);
778
Michal Vasko60ea6352020-06-29 13:39:39 +0200779 /* parse format */
Radek Krejci1798aae2020-07-14 13:26:06 +0200780 lyb_read((uint8_t *)&format, 1, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200781
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100782 /* parse value prefixes */
783 ret = lyb_parse_prefix_data(lybctx->lybctx, format, &val_prefix_data);
784 LY_CHECK_GOTO(ret, cleanup);
785
Michal Vasko60ea6352020-06-29 13:39:39 +0200786 /* parse value */
Radek Krejci1798aae2020-07-14 13:26:06 +0200787 ret = lyb_read_string(&value, 0, lybctx->lybctx);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100788 LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +0200789 dynamic = 1;
790
791 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100792 ret = lyd_create_opaq(ctx, name, strlen(name), prefix, ly_strlen(prefix), module_key, ly_strlen(module_key),
793 value, strlen(value), &dynamic, format, val_prefix_data, 0, &node);
Michal Vasko60ea6352020-06-29 13:39:39 +0200794 LY_CHECK_GOTO(ret, cleanup);
795
796 /* process children */
Radek Krejci1798aae2020-07-14 13:26:06 +0200797 while (LYB_LAST_SUBTREE(lybctx->lybctx).written) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100798 ret = lyb_parse_subtree_r(lybctx, node, NULL, NULL);
Michal Vasko60ea6352020-06-29 13:39:39 +0200799 LY_CHECK_GOTO(ret, cleanup);
800 }
801 } else if (snode->nodetype & LYD_NODE_TERM) {
802 /* parse value */
Radek Krejci1798aae2020-07-14 13:26:06 +0200803 ret = lyb_read_string(&value, 0, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200804 LY_CHECK_GOTO(ret, cleanup);
805 dynamic = 1;
806
807 /* create node */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200808 ret = lyd_parser_create_term((struct lyd_ctx *)lybctx, snode, value, ly_strlen(value), &dynamic, LY_PREF_JSON,
Michal Vasko69730152020-10-09 16:30:07 +0200809 NULL, LYD_HINT_DATA, &node);
Michal Vasko60ea6352020-06-29 13:39:39 +0200810 if (dynamic) {
811 free(value);
812 dynamic = 0;
813 }
814 value = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200815 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +0200816 } else if (snode->nodetype & LYD_NODE_INNER) {
817 /* create node */
818 ret = lyd_create_inner(snode, &node);
819 LY_CHECK_GOTO(ret, cleanup);
820
821 /* process children */
Radek Krejci1798aae2020-07-14 13:26:06 +0200822 while (LYB_LAST_SUBTREE(lybctx->lybctx).written) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100823 ret = lyb_parse_subtree_r(lybctx, node, NULL, NULL);
Michal Vasko60ea6352020-06-29 13:39:39 +0200824 LY_CHECK_GOTO(ret, cleanup);
825 }
826
Michal Vaskoe0665742021-02-11 11:08:44 +0100827 if (!(lybctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200828 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100829 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vasko60ea6352020-06-29 13:39:39 +0200830 LY_CHECK_GOTO(ret, cleanup);
831
832 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200833 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lybctx->node_when, &lybctx->node_exts,
Michal Vaskoc43c8ab2021-03-05 13:32:44 +0100834 &lybctx->node_types, (lybctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vasko60ea6352020-06-29 13:39:39 +0200835 LY_CHECK_GOTO(ret, cleanup);
836 }
837
Michal Vasko751cb4d2020-07-14 12:25:28 +0200838 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200839 /* rememeber the RPC/action/notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200840 lybctx->op_node = node;
Michal Vasko60ea6352020-06-29 13:39:39 +0200841 }
842 } else if (snode->nodetype & LYD_NODE_ANY) {
843 /* parse value type */
Radek Krejci1798aae2020-07-14 13:26:06 +0200844 lyb_read((uint8_t *)&value_type, sizeof value_type, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200845 if (value_type == LYD_ANYDATA_DATATREE) {
846 /* invalid situation */
Radek Krejci1798aae2020-07-14 13:26:06 +0200847 LOGINT(ctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200848 goto cleanup;
849 }
850
851 /* read anydata content */
Radek Krejci1798aae2020-07-14 13:26:06 +0200852 ret = lyb_read_string(&value, 0, lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200853 LY_CHECK_GOTO(ret, cleanup);
854 dynamic = 1;
855
856 if (value_type == LYD_ANYDATA_LYB) {
857 /* turn logging off */
858 prev_lo = ly_log_options(0);
859
860 /* try to parse LYB into a data tree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200861 if (lyd_parse_data_mem(ctx, value, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200862 /* successfully parsed */
863 free(value);
864 value = (char *)tree;
865 value_type = LYD_ANYDATA_DATATREE;
866 }
Radek Krejci7931b192020-06-25 17:05:03 +0200867
868 /* turn logging on again */
869 ly_log_options(prev_lo);
Michal Vasko60ea6352020-06-29 13:39:39 +0200870 }
871
Michal Vasko9afe3df2021-02-05 16:33:50 +0100872 /* create the node */
873 switch (value_type) {
874 case LYD_ANYDATA_LYB:
875 case LYD_ANYDATA_DATATREE:
876 /* use the value directly */
877 ret = lyd_create_any(snode, value, value_type, 1, &node);
878 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +0200879
Michal Vasko9afe3df2021-02-05 16:33:50 +0100880 dynamic = 0;
881 value = NULL;
882 break;
883 case LYD_ANYDATA_STRING:
884 case LYD_ANYDATA_XML:
885 case LYD_ANYDATA_JSON:
886 /* value is expected to be in the dictionary */
887 ret = lydict_insert_zc(ctx, value, &val_dict);
888 LY_CHECK_GOTO(ret, cleanup);
889 dynamic = 0;
890 value = NULL;
891
892 /* use the value in the dictionary */
893 ret = lyd_create_any(snode, val_dict, value_type, 1, &node);
894 if (ret) {
895 lydict_remove(ctx, val_dict);
896 goto cleanup;
897 }
898 break;
899 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200900 }
901 assert(node);
902
Michal Vaskoc5e866a2020-11-04 17:09:26 +0100903 /* set flags */
904 node->flags = flags;
Michal Vasko60ea6352020-06-29 13:39:39 +0200905
906 /* add metadata/attributes */
907 if (snode) {
908 LY_LIST_FOR(meta, m) {
909 m->parent = node;
910 }
911 node->meta = meta;
912 meta = NULL;
913 } else {
914 assert(!node->schema);
915 LY_LIST_FOR(attr, a) {
916 a->parent = (struct lyd_node_opaq *)node;
917 }
918 ((struct lyd_node_opaq *)node)->attr = attr;
919 attr = NULL;
920 }
921
Michal Vaskob104f112020-07-17 09:54:54 +0200922 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100923 lyd_insert_node(parent, first_p, node);
924 while (!parent && (*first_p)->prev->next) {
925 *first_p = (*first_p)->prev;
926 }
927
928 /* rememeber a successfully parsed node */
929 if (parsed) {
930 ly_set_add(parsed, node, 1, NULL);
Michal Vaskob104f112020-07-17 09:54:54 +0200931 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200932 node = NULL;
933
934stop_subtree:
935 /* end the subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200936 ret = lyb_read_stop_subtree(lybctx->lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +0200937 LY_CHECK_GOTO(ret, cleanup);
938
939cleanup:
940 free(prefix);
Radek Krejci1798aae2020-07-14 13:26:06 +0200941 free(module_key);
Michal Vasko60ea6352020-06-29 13:39:39 +0200942 free(name);
943 if (dynamic) {
944 free(value);
945 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200946
Michal Vasko3a41dff2020-07-15 14:30:28 +0200947 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200948 lyd_free_attr_siblings(ctx, attr);
Michal Vasko60ea6352020-06-29 13:39:39 +0200949 lyd_free_tree(node);
950 return ret;
951}
952
953/**
954 * @brief Parse used YANG data models.
955 *
956 * @param[in] lybctx LYB context.
957 * @return LY_ERR value.
958 */
959static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200960lyb_parse_data_models(struct lylyb_ctx *lybctx, uint32_t parse_options)
Michal Vasko60ea6352020-06-29 13:39:39 +0200961{
962 LY_ERR ret;
963 uint32_t count;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200964 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200965
966 /* read model count */
967 lyb_read_number(&count, sizeof count, 2, lybctx);
968
969 if (count) {
970 LY_ARRAY_CREATE_RET(lybctx->ctx, lybctx->models, count, LY_EMEM);
971
972 /* read modules */
973 for (u = 0; u < count; ++u) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200974 ret = lyb_parse_model(lybctx, parse_options, &lybctx->models[u]);
Michal Vasko60ea6352020-06-29 13:39:39 +0200975 LY_CHECK_RET(ret);
976 LY_ARRAY_INCREMENT(lybctx->models);
977 }
978 }
979
980 return LY_SUCCESS;
981}
982
983/**
984 * @brief Parse LYB magic number.
985 *
986 * @param[in] lybctx LYB context.
987 * @return LY_ERR value.
988 */
989static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200990lyb_parse_magic_number(struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +0200991{
992 char magic_byte = 0;
993
994 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
995 if (magic_byte != 'l') {
996 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid first magic number byte \"0x%02x\".", magic_byte);
997 return LY_EINVAL;
998 }
999
1000 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
1001 if (magic_byte != 'y') {
1002 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid second magic number byte \"0x%02x\".", magic_byte);
1003 return LY_EINVAL;
1004 }
1005
1006 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
1007 if (magic_byte != 'b') {
1008 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid third magic number byte \"0x%02x\".", magic_byte);
1009 return LY_EINVAL;
1010 }
1011
1012 return LY_SUCCESS;
1013}
1014
1015/**
1016 * @brief Parse LYB header.
1017 *
1018 * @param[in] lybctx LYB context.
1019 * @return LY_ERR value.
1020 */
1021static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +02001022lyb_parse_header(struct lylyb_ctx *lybctx)
Michal Vasko60ea6352020-06-29 13:39:39 +02001023{
1024 uint8_t byte = 0;
1025
1026 /* version, future flags */
1027 lyb_read((uint8_t *)&byte, sizeof byte, lybctx);
1028
1029 if ((byte & LYB_VERSION_MASK) != LYB_VERSION_NUM) {
1030 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid LYB format version \"0x%02x\", expected \"0x%02x\".",
Michal Vasko69730152020-10-09 16:30:07 +02001031 byte & LYB_VERSION_MASK, LYB_VERSION_NUM);
Michal Vasko60ea6352020-06-29 13:39:39 +02001032 return LY_EINVAL;
1033 }
1034
1035 return LY_SUCCESS;
1036}
1037
Michal Vaskoe0665742021-02-11 11:08:44 +01001038LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001039lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1040 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1041 struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko60ea6352020-06-29 13:39:39 +02001042{
Michal Vaskoe0665742021-02-11 11:08:44 +01001043 LY_ERR rc = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +02001044 struct lyd_lyb_ctx *lybctx;
Michal Vaskoe0665742021-02-11 11:08:44 +01001045 uint32_t int_opts;
Michal Vasko60ea6352020-06-29 13:39:39 +02001046
Michal Vaskoe0665742021-02-11 11:08:44 +01001047 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1048 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Radek Krejci7931b192020-06-25 17:05:03 +02001049
Radek Krejci1798aae2020-07-14 13:26:06 +02001050 lybctx = calloc(1, sizeof *lybctx);
1051 LY_CHECK_ERR_RET(!lybctx, LOGMEM(ctx), LY_EMEM);
1052 lybctx->lybctx = calloc(1, sizeof *lybctx->lybctx);
Michal Vaskoe0665742021-02-11 11:08:44 +01001053 LY_CHECK_ERR_GOTO(!lybctx->lybctx, LOGMEM(ctx); rc = LY_EMEM, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +02001054
Radek Krejci1798aae2020-07-14 13:26:06 +02001055 lybctx->lybctx->in = in;
1056 lybctx->lybctx->ctx = ctx;
Michal Vaskoe0665742021-02-11 11:08:44 +01001057 lybctx->parse_opts = parse_opts;
1058 lybctx->val_opts = val_opts;
Radek Krejci1798aae2020-07-14 13:26:06 +02001059 lybctx->free = lyd_lyb_ctx_free;
Michal Vasko60ea6352020-06-29 13:39:39 +02001060
Michal Vaskoe0665742021-02-11 11:08:44 +01001061 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001062 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001063 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1064 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001065 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001066 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1067 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001068 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001069 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1070 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001071 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001072 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1073 break;
1074 default:
1075 LOGINT(ctx);
1076 rc = LY_EINT;
1077 goto cleanup;
1078 }
1079 lybctx->int_opts = int_opts;
Radek Krejcif16e2542021-02-17 15:39:23 +01001080 lybctx->ext = ext;
Michal Vaskoe0665742021-02-11 11:08:44 +01001081
1082 /* find the operation node if it exists already */
1083 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lybctx->op_node), cleanup);
1084
Michal Vasko60ea6352020-06-29 13:39:39 +02001085 /* read magic number */
Michal Vaskoe0665742021-02-11 11:08:44 +01001086 rc = lyb_parse_magic_number(lybctx->lybctx);
1087 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +02001088
1089 /* read header */
Michal Vaskoe0665742021-02-11 11:08:44 +01001090 rc = lyb_parse_header(lybctx->lybctx);
1091 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +02001092
1093 /* read used models */
Michal Vaskoe0665742021-02-11 11:08:44 +01001094 rc = lyb_parse_data_models(lybctx->lybctx, lybctx->parse_opts);
1095 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +02001096
1097 /* read subtree(s) */
Radek Krejci1798aae2020-07-14 13:26:06 +02001098 while (lybctx->lybctx->in->current[0]) {
Michal Vaskoe0665742021-02-11 11:08:44 +01001099 rc = lyb_parse_subtree_r(lybctx, parent, first_p, parsed);
1100 LY_CHECK_GOTO(rc, cleanup);
1101
1102 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1103 break;
1104 }
1105 }
1106
1107 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && lybctx->lybctx->in->current[0]) {
1108 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1109 rc = LY_EVALID;
1110 goto cleanup;
1111 }
1112 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lybctx->op_node) {
1113 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1114 rc = LY_EVALID;
1115 goto cleanup;
Michal Vasko60ea6352020-06-29 13:39:39 +02001116 }
1117
1118 /* read the last zero, parsing finished */
Radek Krejci1798aae2020-07-14 13:26:06 +02001119 ly_in_skip(lybctx->lybctx->in, 1);
Michal Vasko60ea6352020-06-29 13:39:39 +02001120
Michal Vasko60ea6352020-06-29 13:39:39 +02001121cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001122 /* there should be no unres stored if validation should be skipped */
1123 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lybctx->node_types.count && !lybctx->meta_types.count &&
1124 !lybctx->node_when.count));
1125
1126 if (rc) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001127 lyd_lyb_ctx_free((struct lyd_ctx *)lybctx);
Radek Krejci1798aae2020-07-14 13:26:06 +02001128 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +01001129 *lydctx_p = (struct lyd_ctx *)lybctx;
Michal Vasko60ea6352020-06-29 13:39:39 +02001130 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001131 return rc;
Michal Vasko60ea6352020-06-29 13:39:39 +02001132}
1133
1134API int
1135lyd_lyb_data_length(const char *data)
1136{
1137 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +02001138 struct lylyb_ctx *lybctx;
Michal Vasko60ea6352020-06-29 13:39:39 +02001139 int count, i;
1140 size_t len;
1141 uint8_t buf[LYB_SIZE_MAX];
1142
1143 if (!data) {
1144 return -1;
1145 }
1146
Radek Krejci1798aae2020-07-14 13:26:06 +02001147 lybctx = calloc(1, sizeof *lybctx);
1148 LY_CHECK_ERR_RET(!lybctx, LOGMEM(NULL), LY_EMEM);
1149 ret = ly_in_new_memory(data, &lybctx->in);
Michal Vasko63f3d842020-07-08 10:10:14 +02001150 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +02001151
1152 /* read magic number */
Radek Krejci1798aae2020-07-14 13:26:06 +02001153 ret = lyb_parse_magic_number(lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001154 LY_CHECK_GOTO(ret, cleanup);
1155
1156 /* read header */
Radek Krejci1798aae2020-07-14 13:26:06 +02001157 ret = lyb_parse_header(lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001158 LY_CHECK_GOTO(ret, cleanup);
1159
1160 /* read model count */
Radek Krejci1798aae2020-07-14 13:26:06 +02001161 lyb_read_number(&count, sizeof count, 2, lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001162
1163 /* read all models */
1164 for (i = 0; i < count; ++i) {
1165 /* module name length */
1166 len = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +02001167 lyb_read_number(&len, sizeof len, 2, lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001168
1169 /* model name */
Radek Krejci1798aae2020-07-14 13:26:06 +02001170 lyb_read(buf, len, lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001171
1172 /* revision */
Radek Krejci1798aae2020-07-14 13:26:06 +02001173 lyb_read(buf, 2, lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001174 }
1175
Radek Krejci1798aae2020-07-14 13:26:06 +02001176 while (lybctx->in->current[0]) {
Michal Vasko60ea6352020-06-29 13:39:39 +02001177 /* register a new subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +02001178 ret = lyb_read_start_subtree(lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001179 LY_CHECK_GOTO(ret, cleanup);
1180
1181 /* skip it */
Radek Krejci1798aae2020-07-14 13:26:06 +02001182 lyb_skip_subtree(lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001183
1184 /* subtree finished */
Radek Krejci1798aae2020-07-14 13:26:06 +02001185 ret = lyb_read_stop_subtree(lybctx);
Michal Vasko60ea6352020-06-29 13:39:39 +02001186 LY_CHECK_GOTO(ret, cleanup);
1187 }
1188
1189 /* read the last zero, parsing finished */
Radek Krejci1798aae2020-07-14 13:26:06 +02001190 ly_in_skip(lybctx->in, 1);
Michal Vasko60ea6352020-06-29 13:39:39 +02001191
1192cleanup:
Radek Krejci1798aae2020-07-14 13:26:06 +02001193 count = lybctx->in->current - lybctx->in->start;
Michal Vasko63f3d842020-07-08 10:10:14 +02001194
Radek Krejci1798aae2020-07-14 13:26:06 +02001195 ly_in_free(lybctx->in, 0);
1196 lylyb_ctx_free(lybctx);
1197
Michal Vasko63f3d842020-07-08 10:10:14 +02001198 return ret ? -1 : count;
Michal Vasko60ea6352020-06-29 13:39:39 +02001199}