blob: 1965afb995246f71dc7e869b00b1e394ef0993a3 [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"
27#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020028#include "parser_data.h"
29#include "parser_internal.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020030#include "set.h"
31#include "tree.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020032#include "tree_data_internal.h"
33#include "tree_schema.h"
34#include "validation.h"
35
36/**
37 * @brief Read YANG data from LYB input. Metadata are handled transparently and not returned.
38 *
39 * @param[in] buf Destination buffer.
40 * @param[in] count Number of bytes to read.
41 * @param[in] lybctx LYB context.
42 */
43static void
44lyb_read(uint8_t *buf, size_t count, struct lyd_lyb_ctx *lybctx)
45{
Michal Vaskofd69e1d2020-07-03 11:57:17 +020046 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +020047 struct lyd_lyb_subtree *empty;
48 size_t to_read;
49 uint8_t meta_buf[LYB_META_BYTES];
50
51 assert(lybctx);
52
53 while (1) {
54 /* check for fully-read (empty) data chunks */
55 to_read = count;
56 empty = NULL;
57 LY_ARRAY_FOR(lybctx->subtrees, u) {
58 /* we want the innermost chunks resolved first, so replace previous empty chunks,
59 * also ignore chunks that are completely finished, there is nothing for us to do */
60 if ((lybctx->subtrees[u].written <= to_read) && lybctx->subtrees[u].position) {
61 /* empty chunk, do not read more */
62 to_read = lybctx->subtrees[u].written;
63 empty = &lybctx->subtrees[u];
64 }
65 }
66
67 if (!empty && !count) {
68 break;
69 }
70
71 /* we are actually reading some data, not just finishing another chunk */
72 if (to_read) {
73 if (buf) {
Michal Vasko63f3d842020-07-08 10:10:14 +020074 ly_in_read(lybctx->in, buf, to_read);
75 } else {
76 ly_in_skip(lybctx->in, to_read);
Michal Vasko60ea6352020-06-29 13:39:39 +020077 }
78
79 LY_ARRAY_FOR(lybctx->subtrees, u) {
80 /* decrease all written counters */
81 lybctx->subtrees[u].written -= to_read;
82 assert(lybctx->subtrees[u].written <= LYB_SIZE_MAX);
83 }
84 /* decrease count/buf */
85 count -= to_read;
86 if (buf) {
87 buf += to_read;
88 }
Michal Vasko60ea6352020-06-29 13:39:39 +020089 }
90
91 if (empty) {
92 /* read the next chunk meta information */
Michal Vasko63f3d842020-07-08 10:10:14 +020093 ly_in_read(lybctx->in, meta_buf, LYB_META_BYTES);
Michal Vasko60ea6352020-06-29 13:39:39 +020094 empty->written = meta_buf[0];
95 empty->inner_chunks = meta_buf[1];
96
97 /* remember whether there is a following chunk or not */
98 empty->position = (empty->written == LYB_SIZE_MAX ? 1 : 0);
Michal Vasko60ea6352020-06-29 13:39:39 +020099 }
100 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200101}
102
103/**
104 * @brief Read a number.
105 *
106 * @param[in] num Destination buffer.
107 * @param[in] num_size Size of @p num.
108 * @param[in] bytes Number of bytes to read.
109 * @param[in] lybctx LYB context.
110 */
111static void
112lyb_read_number(void *num, size_t num_size, size_t bytes, struct lyd_lyb_ctx *lybctx)
113{
114 uint64_t buf = 0;
115
116 lyb_read((uint8_t *)&buf, bytes, lybctx);
117
118 /* correct byte order */
119 buf = le64toh(buf);
120
121 switch (num_size) {
122 case 1:
123 *((uint8_t *)num) = buf;
124 break;
125 case 2:
126 *((uint16_t *)num) = buf;
127 break;
128 case 4:
129 *((uint32_t *)num) = buf;
130 break;
131 case 8:
132 *((uint64_t *)num) = buf;
133 break;
134 default:
135 LOGINT(lybctx->ctx);
136 }
137}
138
139/**
140 * @brief Read a string.
141 *
142 * @param[in] str Destination buffer, is allocated.
143 * @param[in] with_length Whether the string is preceded with its length or it ends at the end of this subtree.
144 * @param[in] lybctx LYB context.
145 * @return LY_ERR value.
146 */
147static LY_ERR
148lyb_read_string(char **str, int with_length, struct lyd_lyb_ctx *lybctx)
149{
150 int next_chunk = 0;
151 size_t len = 0, cur_len;
152
153 *str = NULL;
154
155 if (with_length) {
156 lyb_read_number(&len, sizeof len, 2, lybctx);
157 } else {
158 /* read until the end of this subtree */
159 len = LYB_LAST_SUBTREE(lybctx).written;
160 if (LYB_LAST_SUBTREE(lybctx).position) {
161 next_chunk = 1;
162 }
163 }
164
165 *str = malloc((len + 1) * sizeof **str);
166 LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
167
168 lyb_read((uint8_t *)*str, len, lybctx);
169
170 while (next_chunk) {
171 cur_len = LYB_LAST_SUBTREE(lybctx).written;
172 if (LYB_LAST_SUBTREE(lybctx).position) {
173 next_chunk = 1;
174 } else {
175 next_chunk = 0;
176 }
177
178 *str = ly_realloc(*str, (len + cur_len + 1) * sizeof **str);
179 LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
180
181 lyb_read(((uint8_t *)*str) + len, cur_len, lybctx);
182
183 len += cur_len;
184 }
185
186 ((char *)*str)[len] = '\0';
187 return LY_SUCCESS;
188}
189
190/**
191 * @brief Stop the current subtree - change LYB context state.
192 *
193 * @param[in] lybctx LYB context.
194 * @return LY_ERR value.
195 */
196static LY_ERR
197lyb_read_stop_subtree(struct lyd_lyb_ctx *lybctx)
198{
199 if (LYB_LAST_SUBTREE(lybctx).written) {
200 LOGINT_RET(lybctx->ctx);
201 }
202
203 LY_ARRAY_DECREMENT(lybctx->subtrees);
204 return LY_SUCCESS;
205}
206
207/**
208 * @brief Start a new subtree - change LYB context state but also read the expected metadata.
209 *
210 * @param[in] lybctx LYB context.
211 * @return LY_ERR value.
212 */
213static LY_ERR
214lyb_read_start_subtree(struct lyd_lyb_ctx *lybctx)
215{
216 uint8_t meta_buf[LYB_META_BYTES];
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200217 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200218
219 if (!lybctx->subtrees) {
Radek Krejcif6d14cb2020-07-02 16:11:45 +0200220 assert(lybctx->subtree_size == 0);
Michal Vasko60ea6352020-06-29 13:39:39 +0200221 u = 0;
222 } else {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200223 u = LY_ARRAY_COUNT(lybctx->subtrees);
Michal Vasko60ea6352020-06-29 13:39:39 +0200224 }
225 if (u == lybctx->subtree_size) {
226 LY_ARRAY_CREATE_RET(lybctx->ctx, lybctx->subtrees, u + LYB_SUBTREE_STEP, LY_EMEM);
227 lybctx->subtree_size = u + LYB_SUBTREE_STEP;
228 }
229
Michal Vasko63f3d842020-07-08 10:10:14 +0200230 LY_CHECK_RET(ly_in_read(lybctx->in, meta_buf, LYB_META_BYTES));
Michal Vasko60ea6352020-06-29 13:39:39 +0200231
232 LY_ARRAY_INCREMENT(lybctx->subtrees);
233 LYB_LAST_SUBTREE(lybctx).written = meta_buf[0];
234 LYB_LAST_SUBTREE(lybctx).inner_chunks = meta_buf[LYB_SIZE_BYTES];
235 LYB_LAST_SUBTREE(lybctx).position = (LYB_LAST_SUBTREE(lybctx).written == LYB_SIZE_MAX ? 1 : 0);
236
Michal Vasko60ea6352020-06-29 13:39:39 +0200237 return LY_SUCCESS;
238}
239
240/**
241 * @brief Parse YANG model info.
242 *
243 * @param[in] lybctx LYB context.
244 * @param[out] mod Parsed module.
245 * @return LY_ERR value.
246 */
247static LY_ERR
248lyb_parse_model(struct lyd_lyb_ctx *lybctx, const struct lys_module **mod)
249{
250 LY_ERR ret = LY_SUCCESS;
251 char *mod_name = NULL, mod_rev[11];
252 uint16_t rev;
253
254 /* model name */
255 ret = lyb_read_string(&mod_name, 1, lybctx);
256 LY_CHECK_GOTO(ret, cleanup);
257
258 /* revision */
259 lyb_read_number(&rev, sizeof rev, 2, lybctx);
260
261 if (!mod_name[0]) {
262 /* opaq node, no module */
263 *mod = NULL;
264 goto cleanup;
265 }
266
267 if (rev) {
268 sprintf(mod_rev, "%04u-%02u-%02u", ((rev & 0xFE00) >> 9) + 2000, (rev & 0x01E0) >> 5, rev & 0x001Fu);
269 *mod = ly_ctx_get_module(lybctx->ctx, mod_name, mod_rev);
Radek Krejci7931b192020-06-25 17:05:03 +0200270 if ((lybctx->parse_options & LYD_PARSE_LYB_MOD_UPDATE) && !(*mod)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200271 /* try to use an updated module */
272 *mod = ly_ctx_get_module_implemented(lybctx->ctx, mod_name);
273 if (*mod && (!(*mod)->revision || (strcmp((*mod)->revision, mod_rev) < 0))) {
274 /* not an implemented module in a newer revision */
275 *mod = NULL;
276 }
277 }
278 } else {
279 *mod = ly_ctx_get_module_latest(lybctx->ctx, mod_name);
280 }
281 /* TODO data_clb supported?
282 if (lybctx->ctx->data_clb) {
283 if (!*mod) {
284 *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, NULL, 0, lybctx->ctx->data_clb_data);
285 } else if (!(*mod)->implemented) {
286 *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, (*mod)->ns, LY_MODCLB_NOT_IMPLEMENTED, lybctx->ctx->data_clb_data);
287 }
288 }*/
289
290 if (!*mod || !(*mod)->implemented) {
Radek Krejci7931b192020-06-25 17:05:03 +0200291 if (lybctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200292 if (!*mod) {
293 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, missing module \"%s%s%s\".",
294 mod_name, rev ? "@" : "", rev ? mod_rev : "");
295 } else if (!(*mod)->implemented) {
296 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, module \"%s%s%s\" not implemented.",
297 mod_name, rev ? "@" : "", rev ? mod_rev : "");
298 }
299 ret = LY_EINVAL;
300 goto cleanup;
301 }
302
303 }
304
305cleanup:
306 free(mod_name);
307 return ret;
308}
309
310/**
311 * @brief Parse YANG node metadata.
312 *
313 * @param[in] lybctx LYB context.
314 * @param[in] sparent Schema parent node.
315 * @param[out] meta Parsed metadata.
316 * @return LY_ERR value.
317 */
318static LY_ERR
319lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, struct lyd_meta **meta)
320{
321 LY_ERR ret = LY_SUCCESS;
Michal Vasko1e5d5612020-07-03 13:29:26 +0200322 int dynamic;
Michal Vasko60ea6352020-06-29 13:39:39 +0200323 uint8_t i, count = 0;
Michal Vasko1e5d5612020-07-03 13:29:26 +0200324 char *meta_name = NULL, *meta_value;
Michal Vasko60ea6352020-06-29 13:39:39 +0200325 const struct lys_module *mod;
326
327 /* read number of attributes stored */
328 lyb_read(&count, 1, lybctx);
329
330 /* read attributes */
331 for (i = 0; i < count; ++i) {
332 ret = lyb_read_start_subtree(lybctx);
333 LY_CHECK_GOTO(ret, cleanup);
334
335 /* find model */
336 ret = lyb_parse_model(lybctx, &mod);
337 LY_CHECK_GOTO(ret, cleanup);
338
339 if (!mod) {
340 /* skip it */
341 do {
342 lyb_read(NULL, LYB_LAST_SUBTREE(lybctx).written, lybctx);
343 } while (LYB_LAST_SUBTREE(lybctx).written);
344 goto stop_subtree;
345 }
346
347 /* meta name */
348 ret = lyb_read_string(&meta_name, 1, lybctx);
349 LY_CHECK_GOTO(ret, cleanup);
350
351 /* meta value */
352 ret = lyb_read_string(&meta_value, 0, lybctx);
353 LY_CHECK_GOTO(ret, cleanup);
354 dynamic = 1;
355
356 /* create metadata */
357 ret = lyd_create_meta(NULL, meta, mod, meta_name, strlen(meta_name), meta_value, strlen(meta_value), &dynamic,
358 lydjson_resolve_prefix, NULL, LYD_JSON, sparent);
359
360 /* free strings */
361 free(meta_name);
362 meta_name = NULL;
363 if (dynamic) {
364 free(meta_value);
365 dynamic = 0;
366 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200367
368 if (ret == LY_EINCOMPLETE) {
369 ly_set_add(&lybctx->unres_meta_type, *meta, LY_SET_OPT_USEASLIST);
370 } else if (ret) {
371 goto cleanup;
372 }
373
374stop_subtree:
375 ret = lyb_read_stop_subtree(lybctx);
376 LY_CHECK_GOTO(ret, cleanup);
377 }
378
379cleanup:
380 free(meta_name);
Michal Vasko60ea6352020-06-29 13:39:39 +0200381 if (ret) {
382 lyd_free_meta(lybctx->ctx, *meta, 1);
383 *meta = NULL;
384 }
385 return ret;
386}
387
388/**
389 * @brief Parse opaque prefixes structure.
390 *
391 * @param[in] lybctx LYB context.
392 * @param[out] prefs Parsed prefixes.
393 * @return LY_ERR value.
394 */
395static LY_ERR
396lyb_parse_opaq_prefixes(struct lyd_lyb_ctx *lybctx, struct ly_prefix **prefs)
397{
398 LY_ERR ret = LY_SUCCESS;
399 uint8_t count, i;
400 char *str;
401
402 /* read count */
403 lyb_read(&count, 1, lybctx);
404 if (!count) {
405 return LY_SUCCESS;
406 }
407
408 LY_ARRAY_CREATE_RET(lybctx->ctx, *prefs, count, LY_EMEM);
409 for (i = 0; i < count; ++i) {
410 LY_ARRAY_INCREMENT(*prefs);
411
412 /* prefix */
413 ret = lyb_read_string(&str, 1, lybctx);
414 LY_CHECK_GOTO(ret, cleanup);
415 (*prefs)[i].pref = lydict_insert_zc(lybctx->ctx, str);
416
417 /* namespace */
418 ret = lyb_read_string(&str, 1, lybctx);
419 LY_CHECK_GOTO(ret, cleanup);
420 (*prefs)[i].ns = lydict_insert_zc(lybctx->ctx, str);
421 }
422
423cleanup:
424 if (ret) {
425 ly_free_val_prefs(lybctx->ctx, *prefs);
426 *prefs = NULL;
427 }
428 return ret;
429}
430
431/**
432 * @brief Parse opaque attributes.
433 *
434 * @param[in] lybctx LYB context.
435 * @param[out] attr Parsed attributes.
436 * @return LY_ERR value.
437 */
438static LY_ERR
439lyb_parse_attributes(struct lyd_lyb_ctx *lybctx, struct ly_attr **attr)
440{
441 LY_ERR ret = LY_SUCCESS;
442 uint8_t count, i;
443 struct ly_attr *attr2;
444 char *prefix = NULL, *ns = NULL, *name = NULL, *value = NULL;
445 int dynamic = 0;
446 LYD_FORMAT format = 0;
447 struct ly_prefix *val_prefs = NULL;
448
449 /* read count */
450 lyb_read(&count, 1, lybctx);
451
452 /* read attributes */
453 for (i = 0; i < count; ++i) {
454 ret = lyb_read_start_subtree(lybctx);
455 LY_CHECK_GOTO(ret, cleanup);
456
457 /* prefix, may be emtpy */
458 ret = lyb_read_string(&prefix, 1, lybctx);
459 LY_CHECK_GOTO(ret, cleanup);
460 if (!prefix[0]) {
461 free(prefix);
462 prefix = NULL;
463 }
464
465 /* namespace, may be empty */
466 ret = lyb_read_string(&ns, 1, lybctx);
467 LY_CHECK_GOTO(ret, cleanup);
468 if (!ns[0]) {
469 free(ns);
470 ns = NULL;
471 }
472
473 /* name */
474 ret = lyb_read_string(&name, 1, lybctx);
475 LY_CHECK_GOTO(ret, cleanup);
476
477 /* value prefixes */
478 ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
479 LY_CHECK_GOTO(ret, cleanup);
480
481 /* format */
482 lyb_read((uint8_t *)&format, 1, lybctx);
483
484 /* value */
485 ret = lyb_read_string(&value, 0, lybctx);
486 LY_CHECK_GOTO(ret, cleanup);
487 dynamic = 1;
488
489 /* attr2 is always changed to the created attribute */
490 ret = ly_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format,
491 val_prefs, prefix, prefix ? strlen(prefix) : 0, ns);
492 LY_CHECK_GOTO(ret, cleanup);
493
494 free(prefix);
495 prefix = NULL;
496 free(ns);
497 ns = NULL;
498 free(name);
499 name = NULL;
500 val_prefs = NULL;
501 assert(!dynamic);
502 value = NULL;
503
504 if (!*attr) {
505 *attr = attr2;
506 }
507
508 ret = lyb_read_stop_subtree(lybctx);
509 LY_CHECK_GOTO(ret, cleanup);
510 }
511
512cleanup:
513 free(prefix);
514 free(ns);
515 free(name);
516 if (dynamic) {
517 free(value);
518 }
519 ly_free_val_prefs(lybctx->ctx, val_prefs);
520 if (ret) {
521 ly_free_attr(lybctx->ctx, *attr, 1);
522 *attr = NULL;
523 }
524 return ret;
525}
526
527/**
528 * @brief Check whether a schema node matches a hash(es).
529 *
530 * @param[in] sibling Schema node to check.
531 * @param[in] hash Hash array to check.
532 * @param[in] hash_count Number of hashes in @p hash.
533 * @return non-zero if matches,
534 * @return 0 if not.
535 */
536static int
537lyb_is_schema_hash_match(struct lysc_node *sibling, LYB_HASH *hash, uint8_t hash_count)
538{
539 LYB_HASH sibling_hash;
540 uint8_t i;
541
542 /* compare all the hashes starting from collision ID 0 */
543 for (i = 0; i < hash_count; ++i) {
544 sibling_hash = lyb_hash(sibling, i);
545 if (sibling_hash != hash[i]) {
546 return 0;
547 }
548 }
549
550 return 1;
551}
552
553/**
554 * @brief Check that a schema node is suitable based on options.
555 *
556 * @param[in] lybctx LYB context.
557 * @param[in] snode Schema node to check.
558 * @return LY_ERR value.
559 */
560static LY_ERR
561lyb_parse_check_schema(struct lyd_lyb_ctx *lybctx, const struct lysc_node *snode)
562{
563 LY_ERR ret = LY_SUCCESS;
564
Radek Krejci7931b192020-06-25 17:05:03 +0200565 if ((lybctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200566 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LY_VCODE_INNODE, "state", snode->name);
567 return LY_EVALID;
568 }
569
570 if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
571 if (lybctx->int_opts & LYD_INTOPT_RPC) {
572 if (lybctx->op_ntf) {
573 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
574 lys_nodetype2str(snode->nodetype), snode->name,
575 lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
576 return LY_EVALID;
577 }
578 } else {
579 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
580 lys_nodetype2str(snode->nodetype), snode->name);
581 return LY_EVALID;
582 }
583 } else if (snode->nodetype == LYS_NOTIF) {
584 if (lybctx->int_opts & LYD_INTOPT_NOTIF) {
585 if (lybctx->op_ntf) {
586 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
587 lys_nodetype2str(snode->nodetype), snode->name,
588 lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
589 return LY_EVALID;
590 }
591 } else {
592 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
593 lys_nodetype2str(snode->nodetype), snode->name);
594 return LY_EVALID;
595 }
596 }
597
598 return ret;
599}
600
601/**
602 * @brief Parse schema node hash.
603 *
604 * @param[in] lybctx LYB context.
605 * @param[in] sparent Schema parent, must be set if @p mod is not.
606 * @param[in] mod Module of the top-level node, must be set if @p sparent is not.
607 * @param[out] snode Parsed found schema node, may be NULL if opaque.
608 * @return LY_ERR value.
609 */
610static LY_ERR
611lyb_parse_schema_hash(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, const struct lys_module *mod,
612 const struct lysc_node **snode)
613{
614 LY_ERR ret;
615 uint8_t i, j;
616 const struct lysc_node *sibling;
617 LYB_HASH hash[LYB_HASH_BITS - 1];
618 int getnext_opts;
619
620 *snode = NULL;
621 /* leave if-feature check for validation */
622 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lybctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
623
624 /* read the first hash */
625 lyb_read(&hash[0], sizeof *hash, lybctx);
626
627 if (!hash[0]) {
628 /* opaque node */
629 return LY_SUCCESS;
630 }
631
632 /* based on the first hash read all the other ones, if any */
633 for (i = 0; !(hash[0] & (LYB_HASH_COLLISION_ID >> i)); ++i) {
634 if (i > LYB_HASH_BITS) {
635 LOGINT_RET(lybctx->ctx);
636 }
637 }
638
639 /* move the first hash on its accurate position */
640 hash[i] = hash[0];
641
642 /* read the rest of hashes */
643 for (j = i; j; --j) {
644 lyb_read(&hash[j - 1], sizeof *hash, lybctx);
645
646 /* correct collision ID */
647 assert(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)));
648 /* preceded with zeros */
649 assert(!(hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))));
650 }
651
652 /* find our node with matching hashes */
653 sibling = NULL;
654 while ((sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts))) {
655 /* skip schema nodes from models not present during printing */
656 if (lyb_has_schema_model(sibling, lybctx->models)
657 && lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, i + 1)) {
658 /* match found */
659 break;
660 }
661 }
662
Radek Krejci7931b192020-06-25 17:05:03 +0200663 if (!sibling && (lybctx->parse_options & LYD_PARSE_STRICT)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200664 if (mod) {
665 LOGVAL(lybctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
666 " from \"%s\".", mod->name);
667 } else {
668 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, sparent, LYVE_REFERENCE, "Failed to find matching hash for a child node"
669 " of \"%s\".", sparent->name);
670 }
671 return LY_EVALID;
672 } else if (sibling && (ret = lyb_parse_check_schema(lybctx, sibling))) {
673 return ret;
674 }
675
676 *snode = sibling;
677 return LY_SUCCESS;
678}
679
680/**
681 * @brief Read until the end of the current subtree.
682 *
683 * @param[in] lybctx LYB context.
684 */
685static void
686lyb_skip_subtree(struct lyd_lyb_ctx *lybctx)
687{
Michal Vasko60ea6352020-06-29 13:39:39 +0200688 do {
689 /* first skip any meta information inside */
Michal Vasko63f3d842020-07-08 10:10:14 +0200690 ly_in_skip(lybctx->in, LYB_LAST_SUBTREE(lybctx).inner_chunks * LYB_META_BYTES);
Michal Vasko60ea6352020-06-29 13:39:39 +0200691
692 /* then read data */
693 lyb_read(NULL, LYB_LAST_SUBTREE(lybctx).written, lybctx);
694 } while (LYB_LAST_SUBTREE(lybctx).written);
695}
696
697/**
698 * @brief Parse LYB subtree.
699 *
700 * @param[in] lybctx LYB context.
701 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
702 * @param[in,out] first First top-level sibling, must be set if @p parent is not.
703 * @return LY_ERR value.
704 */
705static LY_ERR
706lyb_parse_subtree_r(struct lyd_lyb_ctx *lybctx, struct lyd_node_inner *parent, struct lyd_node **first)
707{
708 LY_ERR ret = LY_SUCCESS;
709 struct lyd_node *node = NULL, *tree;
710 const struct lys_module *mod;
711 const struct lysc_node *snode = NULL;
712 struct lyd_meta *meta = NULL, *m;
713 struct ly_attr *attr = NULL, *a;
714 struct ly_prefix *val_prefs = NULL;
715 LYD_ANYDATA_VALUETYPE value_type;
716 char *value = NULL, *name = NULL, *prefix = NULL, *ns = NULL;
717 int dynamic = 0;
718 LYD_FORMAT format = 0;
719 int prev_lo;
720
721 /* register a new subtree */
722 LY_CHECK_GOTO(ret = lyb_read_start_subtree(lybctx), cleanup);
723
724 if (!parent) {
725 /* top-level, read module name */
726 ret = lyb_parse_model(lybctx, &mod);
727 LY_CHECK_GOTO(ret, cleanup);
728
729 /* read hash, find the schema node starting from mod */
730 ret = lyb_parse_schema_hash(lybctx, NULL, mod, &snode);
731 LY_CHECK_GOTO(ret, cleanup);
732 } else {
733 /* read hash, find the schema node starting from parent schema */
734 ret = lyb_parse_schema_hash(lybctx, parent->schema, NULL, &snode);
735 LY_CHECK_GOTO(ret, cleanup);
736 }
737
Radek Krejci7931b192020-06-25 17:05:03 +0200738 if (!snode && !(lybctx->parse_options & LYD_PARSE_OPAQ)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200739 /* unknown data, skip them */
740 lyb_skip_subtree(lybctx);
741 goto stop_subtree;
742 }
743
744 /* create metadata/attributes */
745 if (snode) {
746 ret = lyb_parse_metadata(lybctx, snode, &meta);
747 LY_CHECK_GOTO(ret, cleanup);
748 } else {
749 ret = lyb_parse_attributes(lybctx, &attr);
750 LY_CHECK_GOTO(ret, cleanup);
751 }
752
753 if (!snode) {
754 /* parse prefix */
755 ret = lyb_read_string(&prefix, 1, lybctx);
756 LY_CHECK_GOTO(ret, cleanup);
757
758 /* parse namespace */
759 ret = lyb_read_string(&ns, 1, lybctx);
760 LY_CHECK_GOTO(ret, cleanup);
761
762 /* parse name */
763 ret = lyb_read_string(&name, 1, lybctx);
764 LY_CHECK_GOTO(ret, cleanup);
765
766 /* parse value prefixes */
767 ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
768 LY_CHECK_GOTO(ret, cleanup);
769
770 /* parse format */
771 lyb_read((uint8_t *)&format, 1, lybctx);
772
773 /* parse value */
774 ret = lyb_read_string(&value, 0, lybctx);
775 LY_CHECK_GOTO(ret, cleanup);
776 dynamic = 1;
777
778 /* create node */
779 ret = lyd_create_opaq(lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format, val_prefs, prefix,
780 strlen(prefix), ns, &node);
781 LY_CHECK_GOTO(ret, cleanup);
782
783 /* process children */
784 while (LYB_LAST_SUBTREE(lybctx).written) {
785 ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
786 LY_CHECK_GOTO(ret, cleanup);
787 }
788 } else if (snode->nodetype & LYD_NODE_TERM) {
789 /* parse value */
790 ret = lyb_read_string(&value, 0, lybctx);
791 LY_CHECK_GOTO(ret, cleanup);
792 dynamic = 1;
793
794 /* create node */
795 ret = lyd_create_term(snode, value, strlen(value), &dynamic, lydjson_resolve_prefix, NULL, LYD_JSON, &node);
796 if (dynamic) {
797 free(value);
798 dynamic = 0;
799 }
800 value = NULL;
801 if (ret == LY_EINCOMPLETE) {
Radek Krejci7931b192020-06-25 17:05:03 +0200802 if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200803 ly_set_add(&lybctx->unres_node_type, node, LY_SET_OPT_USEASLIST);
804 }
805 ret = LY_SUCCESS;
806 } else if (ret) {
807 goto cleanup;
808 }
809 } else if (snode->nodetype & LYD_NODE_INNER) {
810 /* create node */
811 ret = lyd_create_inner(snode, &node);
812 LY_CHECK_GOTO(ret, cleanup);
813
814 /* process children */
815 while (LYB_LAST_SUBTREE(lybctx).written) {
816 ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
817 LY_CHECK_GOTO(ret, cleanup);
818 }
819
Radek Krejci7931b192020-06-25 17:05:03 +0200820 if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200821 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vasko8104fd42020-07-13 11:09:51 +0200822 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
Michal Vasko60ea6352020-06-29 13:39:39 +0200823 LY_CHECK_GOTO(ret, cleanup);
824
825 /* add any missing default children */
Michal Vaskofbed4ea2020-07-08 10:43:30 +0200826 ret = lyd_validate_defaults_r(node, lyd_node_children_p(node), NULL, NULL, &lybctx->unres_node_type,
Michal Vasko8104fd42020-07-13 11:09:51 +0200827 &lybctx->when_check, lybctx->validate_options, NULL);
Michal Vasko60ea6352020-06-29 13:39:39 +0200828 LY_CHECK_GOTO(ret, cleanup);
829 }
830
Michal Vasko751cb4d2020-07-14 12:25:28 +0200831 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200832 /* rememeber the RPC/action/notification */
833 lybctx->op_ntf = node;
834 }
835 } else if (snode->nodetype & LYD_NODE_ANY) {
836 /* parse value type */
837 lyb_read((uint8_t *)&value_type, sizeof value_type, lybctx);
838 if (value_type == LYD_ANYDATA_DATATREE) {
839 /* invalid situation */
840 LOGINT(lybctx->ctx);
841 goto cleanup;
842 }
843
844 /* read anydata content */
845 ret = lyb_read_string(&value, 0, lybctx);
846 LY_CHECK_GOTO(ret, cleanup);
847 dynamic = 1;
848
849 if (value_type == LYD_ANYDATA_LYB) {
850 /* turn logging off */
851 prev_lo = ly_log_options(0);
852
853 /* try to parse LYB into a data tree */
Radek Krejci7931b192020-06-25 17:05:03 +0200854 if (lyd_parse_data_mem((struct ly_ctx *)lybctx->ctx, value, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200855 /* successfully parsed */
856 free(value);
857 value = (char *)tree;
858 value_type = LYD_ANYDATA_DATATREE;
859 }
Radek Krejci7931b192020-06-25 17:05:03 +0200860
861 /* turn logging on again */
862 ly_log_options(prev_lo);
Michal Vasko60ea6352020-06-29 13:39:39 +0200863 }
864
865 /* create node */
866 ret = lyd_create_any(snode, value, value_type, &node);
867 LY_CHECK_GOTO(ret, cleanup);
868
869 dynamic = 0;
870 value = NULL;
871 }
872 assert(node);
873
874 /* add/correct flags */
875 if (snode) {
Radek Krejci7931b192020-06-25 17:05:03 +0200876 lyd_parse_set_data_flags(node, &lybctx->when_check, &meta, lybctx->parse_options);
Michal Vasko60ea6352020-06-29 13:39:39 +0200877 }
878
879 /* add metadata/attributes */
880 if (snode) {
881 LY_LIST_FOR(meta, m) {
882 m->parent = node;
883 }
884 node->meta = meta;
885 meta = NULL;
886 } else {
887 assert(!node->schema);
888 LY_LIST_FOR(attr, a) {
889 a->parent = (struct lyd_node_opaq *)node;
890 }
891 ((struct lyd_node_opaq *)node)->attr = attr;
892 attr = NULL;
893 }
894
895 /* insert */
896 lyd_insert_node((struct lyd_node *)parent, first, node);
897 node = NULL;
898
899stop_subtree:
900 /* end the subtree */
901 ret = lyb_read_stop_subtree(lybctx);
902 LY_CHECK_GOTO(ret, cleanup);
903
904cleanup:
905 free(prefix);
906 free(ns);
907 free(name);
908 if (dynamic) {
909 free(value);
910 }
911 ly_free_val_prefs(lybctx->ctx, val_prefs);
912
913 lyd_free_meta(lybctx->ctx, meta, 1);
914 ly_free_attr(lybctx->ctx, attr, 1);
915 lyd_free_tree(node);
916 return ret;
917}
918
919/**
920 * @brief Parse used YANG data models.
921 *
922 * @param[in] lybctx LYB context.
923 * @return LY_ERR value.
924 */
925static LY_ERR
926lyb_parse_data_models(struct lyd_lyb_ctx *lybctx)
927{
928 LY_ERR ret;
929 uint32_t count;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200930 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200931
932 /* read model count */
933 lyb_read_number(&count, sizeof count, 2, lybctx);
934
935 if (count) {
936 LY_ARRAY_CREATE_RET(lybctx->ctx, lybctx->models, count, LY_EMEM);
937
938 /* read modules */
939 for (u = 0; u < count; ++u) {
940 ret = lyb_parse_model(lybctx, &lybctx->models[u]);
941 LY_CHECK_RET(ret);
942 LY_ARRAY_INCREMENT(lybctx->models);
943 }
944 }
945
946 return LY_SUCCESS;
947}
948
949/**
950 * @brief Parse LYB magic number.
951 *
952 * @param[in] lybctx LYB context.
953 * @return LY_ERR value.
954 */
955static LY_ERR
956lyb_parse_magic_number(struct lyd_lyb_ctx *lybctx)
957{
958 char magic_byte = 0;
959
960 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
961 if (magic_byte != 'l') {
962 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid first magic number byte \"0x%02x\".", magic_byte);
963 return LY_EINVAL;
964 }
965
966 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
967 if (magic_byte != 'y') {
968 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid second magic number byte \"0x%02x\".", magic_byte);
969 return LY_EINVAL;
970 }
971
972 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
973 if (magic_byte != 'b') {
974 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid third magic number byte \"0x%02x\".", magic_byte);
975 return LY_EINVAL;
976 }
977
978 return LY_SUCCESS;
979}
980
981/**
982 * @brief Parse LYB header.
983 *
984 * @param[in] lybctx LYB context.
985 * @return LY_ERR value.
986 */
987static LY_ERR
988lyb_parse_header(struct lyd_lyb_ctx *lybctx)
989{
990 uint8_t byte = 0;
991
992 /* version, future flags */
993 lyb_read((uint8_t *)&byte, sizeof byte, lybctx);
994
995 if ((byte & LYB_VERSION_MASK) != LYB_VERSION_NUM) {
996 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid LYB format version \"0x%02x\", expected \"0x%02x\".",
997 byte & LYB_VERSION_MASK, LYB_VERSION_NUM);
998 return LY_EINVAL;
999 }
1000
1001 return LY_SUCCESS;
1002}
1003
1004LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +02001005lyd_parse_lyb_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
1006 struct lyd_node **tree)
Michal Vasko60ea6352020-06-29 13:39:39 +02001007{
1008 LY_ERR ret = LY_SUCCESS;
1009 struct lyd_lyb_ctx lybctx = {0};
1010
Radek Krejci7931b192020-06-25 17:05:03 +02001011 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
1012 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
1013
Michal Vasko60ea6352020-06-29 13:39:39 +02001014 *tree = NULL;
1015
Michal Vasko63f3d842020-07-08 10:10:14 +02001016 lybctx.in = in;
Michal Vasko60ea6352020-06-29 13:39:39 +02001017 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001018 lybctx.parse_options = parse_options;
1019 lybctx.validate_options = validate_options;
Michal Vasko60ea6352020-06-29 13:39:39 +02001020
1021 /* read magic number */
1022 ret = lyb_parse_magic_number(&lybctx);
1023 LY_CHECK_GOTO(ret, cleanup);
1024
1025 /* read header */
1026 ret = lyb_parse_header(&lybctx);
1027 LY_CHECK_GOTO(ret, cleanup);
1028
1029 /* read used models */
1030 ret = lyb_parse_data_models(&lybctx);
1031 LY_CHECK_GOTO(ret, cleanup);
1032
1033 /* read subtree(s) */
Michal Vasko63f3d842020-07-08 10:10:14 +02001034 while (lybctx.in->current[0]) {
Michal Vasko60ea6352020-06-29 13:39:39 +02001035 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1036 LY_CHECK_GOTO(ret, cleanup);
1037 }
1038
1039 /* read the last zero, parsing finished */
Michal Vasko63f3d842020-07-08 10:10:14 +02001040 ly_in_skip(lybctx.in, 1);
Michal Vasko60ea6352020-06-29 13:39:39 +02001041
1042 /* TODO validation */
1043
1044cleanup:
1045 LY_ARRAY_FREE(lybctx.subtrees);
1046 LY_ARRAY_FREE(lybctx.models);
1047 ly_set_erase(&lybctx.unres_node_type, NULL);
1048 ly_set_erase(&lybctx.unres_meta_type, NULL);
1049 ly_set_erase(&lybctx.when_check, NULL);
1050
Michal Vasko60ea6352020-06-29 13:39:39 +02001051 if (ret) {
1052 lyd_free_all(*tree);
1053 *tree = NULL;
1054 }
1055 return ret;
1056}
1057
1058LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +02001059lyd_parse_lyb_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
Michal Vasko60ea6352020-06-29 13:39:39 +02001060{
1061 LY_ERR ret = LY_SUCCESS;
1062 struct lyd_lyb_ctx lybctx = {0};
1063
Michal Vasko63f3d842020-07-08 10:10:14 +02001064 lybctx.in = in;
Michal Vasko60ea6352020-06-29 13:39:39 +02001065 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001066 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001067 lybctx.int_opts = LYD_INTOPT_RPC;
1068
1069 *tree = NULL;
1070 if (op) {
1071 *op = NULL;
1072 }
1073
1074 /* read magic number */
1075 ret = lyb_parse_magic_number(&lybctx);
1076 LY_CHECK_GOTO(ret, cleanup);
1077
1078 /* read header */
1079 ret = lyb_parse_header(&lybctx);
1080 LY_CHECK_GOTO(ret, cleanup);
1081
1082 /* read used models */
1083 ret = lyb_parse_data_models(&lybctx);
1084 LY_CHECK_GOTO(ret, cleanup);
1085
1086 /* read subtree(s) */
Michal Vasko63f3d842020-07-08 10:10:14 +02001087 while (lybctx.in->current[0]) {
Michal Vasko60ea6352020-06-29 13:39:39 +02001088 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1089 LY_CHECK_GOTO(ret, cleanup);
1090 }
1091
1092 /* read the last zero, parsing finished */
Michal Vasko63f3d842020-07-08 10:10:14 +02001093 ly_in_skip(lybctx.in, 1);
Michal Vasko60ea6352020-06-29 13:39:39 +02001094
1095 /* make sure we have parsed some operation */
1096 if (!lybctx.op_ntf) {
1097 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
1098 ret = LY_EVALID;
1099 goto cleanup;
1100 }
1101
1102 if (op) {
1103 *op = lybctx.op_ntf;
1104 }
1105 assert(*tree);
1106
1107cleanup:
1108 LY_ARRAY_FREE(lybctx.subtrees);
1109 LY_ARRAY_FREE(lybctx.models);
1110 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1111
Michal Vasko60ea6352020-06-29 13:39:39 +02001112 if (ret) {
1113 lyd_free_all(*tree);
1114 *tree = NULL;
1115 }
1116 return ret;
1117}
1118
1119LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +02001120lyd_parse_lyb_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **ntf)
Michal Vasko60ea6352020-06-29 13:39:39 +02001121{
1122 LY_ERR ret = LY_SUCCESS;
1123 struct lyd_lyb_ctx lybctx = {0};
1124
Michal Vasko63f3d842020-07-08 10:10:14 +02001125 lybctx.in = in;
Michal Vasko60ea6352020-06-29 13:39:39 +02001126 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001127 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001128 lybctx.int_opts = LYD_INTOPT_NOTIF;
1129
1130 *tree = NULL;
1131 if (ntf) {
1132 *ntf = NULL;
1133 }
1134
1135 /* read magic number */
1136 ret = lyb_parse_magic_number(&lybctx);
1137 LY_CHECK_GOTO(ret, cleanup);
1138
1139 /* read header */
1140 ret = lyb_parse_header(&lybctx);
1141 LY_CHECK_GOTO(ret, cleanup);
1142
1143 /* read used models */
1144 ret = lyb_parse_data_models(&lybctx);
1145 LY_CHECK_GOTO(ret, cleanup);
1146
1147 /* read subtree(s) */
Michal Vasko63f3d842020-07-08 10:10:14 +02001148 while (lybctx.in->current[0]) {
Michal Vasko60ea6352020-06-29 13:39:39 +02001149 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1150 LY_CHECK_GOTO(ret, cleanup);
1151 }
1152
1153 /* read the last zero, parsing finished */
Michal Vasko63f3d842020-07-08 10:10:14 +02001154 ly_in_skip(lybctx.in, 1);
Michal Vasko60ea6352020-06-29 13:39:39 +02001155
1156 /* make sure we have parsed some notification */
1157 if (!lybctx.op_ntf) {
1158 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1159 ret = LY_EVALID;
1160 goto cleanup;
1161 }
1162
1163 if (ntf) {
1164 *ntf = lybctx.op_ntf;
1165 }
1166 assert(*tree);
1167
1168cleanup:
1169 LY_ARRAY_FREE(lybctx.subtrees);
1170 LY_ARRAY_FREE(lybctx.models);
1171 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1172
Michal Vasko60ea6352020-06-29 13:39:39 +02001173 if (ret) {
1174 lyd_free_all(*tree);
1175 *tree = NULL;
1176 }
1177 return ret;
1178}
1179
1180LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +02001181lyd_parse_lyb_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
Michal Vasko60ea6352020-06-29 13:39:39 +02001182{
1183 LY_ERR ret = LY_SUCCESS;
1184 struct lyd_lyb_ctx lybctx = {0};
1185 struct lyd_node *iter, *req_op, *rep_op = NULL;
1186
Michal Vasko63f3d842020-07-08 10:10:14 +02001187 lybctx.in = in;
Michal Vasko60ea6352020-06-29 13:39:39 +02001188 lybctx.ctx = LYD_NODE_CTX(request);
Radek Krejci7931b192020-06-25 17:05:03 +02001189 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001190 lybctx.int_opts = LYD_INTOPT_REPLY;
1191
1192 *tree = NULL;
1193 if (op) {
1194 *op = NULL;
1195 }
1196
1197 /* find request OP */
1198 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, iter, req_op) {
1199 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1200 break;
1201 }
1202 LYD_TREE_DFS_END(request, iter, req_op);
1203 }
1204 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1205 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1206 ret = LY_EINVAL;
1207 goto cleanup;
1208 }
1209
1210 /* duplicate request OP with parents */
1211 rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
1212 LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
1213
1214 /* read magic number */
1215 ret = lyb_parse_magic_number(&lybctx);
1216 LY_CHECK_GOTO(ret, cleanup);
1217
1218 /* read header */
1219 ret = lyb_parse_header(&lybctx);
1220 LY_CHECK_GOTO(ret, cleanup);
1221
1222 /* read used models */
1223 ret = lyb_parse_data_models(&lybctx);
1224 LY_CHECK_GOTO(ret, cleanup);
1225
1226 /* read subtree(s) */
Michal Vasko63f3d842020-07-08 10:10:14 +02001227 while (lybctx.in->current[0]) {
Michal Vasko60ea6352020-06-29 13:39:39 +02001228 ret = lyb_parse_subtree_r(&lybctx, (struct lyd_node_inner *)rep_op, NULL);
1229 LY_CHECK_GOTO(ret, cleanup);
1230 }
1231
1232 /* read the last zero, parsing finished */
Michal Vasko63f3d842020-07-08 10:10:14 +02001233 ly_in_skip(lybctx.in, 1);
Michal Vasko60ea6352020-06-29 13:39:39 +02001234
1235 if (op) {
1236 *op = rep_op;
1237 }
1238 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
1239 *tree = iter;
1240 rep_op = NULL;
1241
1242cleanup:
1243 lyd_free_all(rep_op);
1244 LY_ARRAY_FREE(lybctx.subtrees);
1245 LY_ARRAY_FREE(lybctx.models);
1246 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1247
Michal Vasko60ea6352020-06-29 13:39:39 +02001248 if (ret) {
1249 lyd_free_all(*tree);
1250 *tree = NULL;
1251 }
1252 return ret;
1253}
1254
1255API int
1256lyd_lyb_data_length(const char *data)
1257{
1258 LY_ERR ret = LY_SUCCESS;
1259 struct lyd_lyb_ctx lybctx = {0};
1260 int count, i;
1261 size_t len;
1262 uint8_t buf[LYB_SIZE_MAX];
1263
1264 if (!data) {
1265 return -1;
1266 }
1267
Michal Vasko63f3d842020-07-08 10:10:14 +02001268 ret = ly_in_new_memory(data, &lybctx.in);
1269 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko60ea6352020-06-29 13:39:39 +02001270
1271 /* read magic number */
1272 ret = lyb_parse_magic_number(&lybctx);
1273 LY_CHECK_GOTO(ret, cleanup);
1274
1275 /* read header */
1276 ret = lyb_parse_header(&lybctx);
1277 LY_CHECK_GOTO(ret, cleanup);
1278
1279 /* read model count */
1280 lyb_read_number(&count, sizeof count, 2, &lybctx);
1281
1282 /* read all models */
1283 for (i = 0; i < count; ++i) {
1284 /* module name length */
1285 len = 0;
1286 lyb_read_number(&len, sizeof len, 2, &lybctx);
1287
1288 /* model name */
1289 lyb_read(buf, len, &lybctx);
1290
1291 /* revision */
1292 lyb_read(buf, 2, &lybctx);
1293 }
1294
Michal Vasko63f3d842020-07-08 10:10:14 +02001295 while (lybctx.in->current[0]) {
Michal Vasko60ea6352020-06-29 13:39:39 +02001296 /* register a new subtree */
1297 ret = lyb_read_start_subtree(&lybctx);
1298 LY_CHECK_GOTO(ret, cleanup);
1299
1300 /* skip it */
1301 lyb_skip_subtree(&lybctx);
1302
1303 /* subtree finished */
1304 ret = lyb_read_stop_subtree(&lybctx);
1305 LY_CHECK_GOTO(ret, cleanup);
1306 }
1307
1308 /* read the last zero, parsing finished */
Michal Vasko63f3d842020-07-08 10:10:14 +02001309 ly_in_skip(lybctx.in, 1);
Michal Vasko60ea6352020-06-29 13:39:39 +02001310
1311cleanup:
Michal Vasko63f3d842020-07-08 10:10:14 +02001312 count = lybctx.in->current - lybctx.in->start;
1313
1314 ly_in_free(lybctx.in, 0);
Michal Vasko60ea6352020-06-29 13:39:39 +02001315 LY_ARRAY_FREE(lybctx.subtrees);
Michal Vasko63f3d842020-07-08 10:10:14 +02001316 return ret ? -1 : count;
Michal Vasko60ea6352020-06-29 13:39:39 +02001317}