blob: b2aca777e569a80188af5bc020f246cb69428646 [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{
46 int parsed = 0;
47 LY_ARRAY_SIZE_TYPE u;
48 struct lyd_lyb_subtree *empty;
49 size_t to_read;
50 uint8_t meta_buf[LYB_META_BYTES];
51
52 assert(lybctx);
53
54 while (1) {
55 /* check for fully-read (empty) data chunks */
56 to_read = count;
57 empty = NULL;
58 LY_ARRAY_FOR(lybctx->subtrees, u) {
59 /* we want the innermost chunks resolved first, so replace previous empty chunks,
60 * also ignore chunks that are completely finished, there is nothing for us to do */
61 if ((lybctx->subtrees[u].written <= to_read) && lybctx->subtrees[u].position) {
62 /* empty chunk, do not read more */
63 to_read = lybctx->subtrees[u].written;
64 empty = &lybctx->subtrees[u];
65 }
66 }
67
68 if (!empty && !count) {
69 break;
70 }
71
72 /* we are actually reading some data, not just finishing another chunk */
73 if (to_read) {
74 if (buf) {
75 memcpy(buf, lybctx->data + parsed, to_read);
76 }
77
78 LY_ARRAY_FOR(lybctx->subtrees, u) {
79 /* decrease all written counters */
80 lybctx->subtrees[u].written -= to_read;
81 assert(lybctx->subtrees[u].written <= LYB_SIZE_MAX);
82 }
83 /* decrease count/buf */
84 count -= to_read;
85 if (buf) {
86 buf += to_read;
87 }
88
89 parsed += to_read;
90 }
91
92 if (empty) {
93 /* read the next chunk meta information */
94 memcpy(meta_buf, lybctx->data + parsed, LYB_META_BYTES);
95 empty->written = meta_buf[0];
96 empty->inner_chunks = meta_buf[1];
97
98 /* remember whether there is a following chunk or not */
99 empty->position = (empty->written == LYB_SIZE_MAX ? 1 : 0);
100
101 parsed += LYB_META_BYTES;
102 }
103 }
104
105 lybctx->byte_count += parsed;
106 lybctx->data += parsed;
107}
108
109/**
110 * @brief Read a number.
111 *
112 * @param[in] num Destination buffer.
113 * @param[in] num_size Size of @p num.
114 * @param[in] bytes Number of bytes to read.
115 * @param[in] lybctx LYB context.
116 */
117static void
118lyb_read_number(void *num, size_t num_size, size_t bytes, struct lyd_lyb_ctx *lybctx)
119{
120 uint64_t buf = 0;
121
122 lyb_read((uint8_t *)&buf, bytes, lybctx);
123
124 /* correct byte order */
125 buf = le64toh(buf);
126
127 switch (num_size) {
128 case 1:
129 *((uint8_t *)num) = buf;
130 break;
131 case 2:
132 *((uint16_t *)num) = buf;
133 break;
134 case 4:
135 *((uint32_t *)num) = buf;
136 break;
137 case 8:
138 *((uint64_t *)num) = buf;
139 break;
140 default:
141 LOGINT(lybctx->ctx);
142 }
143}
144
145/**
146 * @brief Read a string.
147 *
148 * @param[in] str Destination buffer, is allocated.
149 * @param[in] with_length Whether the string is preceded with its length or it ends at the end of this subtree.
150 * @param[in] lybctx LYB context.
151 * @return LY_ERR value.
152 */
153static LY_ERR
154lyb_read_string(char **str, int with_length, struct lyd_lyb_ctx *lybctx)
155{
156 int next_chunk = 0;
157 size_t len = 0, cur_len;
158
159 *str = NULL;
160
161 if (with_length) {
162 lyb_read_number(&len, sizeof len, 2, lybctx);
163 } else {
164 /* read until the end of this subtree */
165 len = LYB_LAST_SUBTREE(lybctx).written;
166 if (LYB_LAST_SUBTREE(lybctx).position) {
167 next_chunk = 1;
168 }
169 }
170
171 *str = malloc((len + 1) * sizeof **str);
172 LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
173
174 lyb_read((uint8_t *)*str, len, lybctx);
175
176 while (next_chunk) {
177 cur_len = LYB_LAST_SUBTREE(lybctx).written;
178 if (LYB_LAST_SUBTREE(lybctx).position) {
179 next_chunk = 1;
180 } else {
181 next_chunk = 0;
182 }
183
184 *str = ly_realloc(*str, (len + cur_len + 1) * sizeof **str);
185 LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
186
187 lyb_read(((uint8_t *)*str) + len, cur_len, lybctx);
188
189 len += cur_len;
190 }
191
192 ((char *)*str)[len] = '\0';
193 return LY_SUCCESS;
194}
195
196/**
197 * @brief Stop the current subtree - change LYB context state.
198 *
199 * @param[in] lybctx LYB context.
200 * @return LY_ERR value.
201 */
202static LY_ERR
203lyb_read_stop_subtree(struct lyd_lyb_ctx *lybctx)
204{
205 if (LYB_LAST_SUBTREE(lybctx).written) {
206 LOGINT_RET(lybctx->ctx);
207 }
208
209 LY_ARRAY_DECREMENT(lybctx->subtrees);
210 return LY_SUCCESS;
211}
212
213/**
214 * @brief Start a new subtree - change LYB context state but also read the expected metadata.
215 *
216 * @param[in] lybctx LYB context.
217 * @return LY_ERR value.
218 */
219static LY_ERR
220lyb_read_start_subtree(struct lyd_lyb_ctx *lybctx)
221{
222 uint8_t meta_buf[LYB_META_BYTES];
223 LY_ARRAY_SIZE_TYPE u;
224
225 if (!lybctx->subtrees) {
Radek Krejcif6d14cb2020-07-02 16:11:45 +0200226 assert(lybctx->subtree_size == 0);
Michal Vasko60ea6352020-06-29 13:39:39 +0200227 u = 0;
228 } else {
229 u = LY_ARRAY_SIZE(lybctx->subtrees);
230 }
231 if (u == lybctx->subtree_size) {
232 LY_ARRAY_CREATE_RET(lybctx->ctx, lybctx->subtrees, u + LYB_SUBTREE_STEP, LY_EMEM);
233 lybctx->subtree_size = u + LYB_SUBTREE_STEP;
234 }
235
236 memcpy(meta_buf, lybctx->data, LYB_META_BYTES);
237
238 LY_ARRAY_INCREMENT(lybctx->subtrees);
239 LYB_LAST_SUBTREE(lybctx).written = meta_buf[0];
240 LYB_LAST_SUBTREE(lybctx).inner_chunks = meta_buf[LYB_SIZE_BYTES];
241 LYB_LAST_SUBTREE(lybctx).position = (LYB_LAST_SUBTREE(lybctx).written == LYB_SIZE_MAX ? 1 : 0);
242
243 lybctx->byte_count += LYB_META_BYTES;
244 lybctx->data += LYB_META_BYTES;
245 return LY_SUCCESS;
246}
247
248/**
249 * @brief Parse YANG model info.
250 *
251 * @param[in] lybctx LYB context.
252 * @param[out] mod Parsed module.
253 * @return LY_ERR value.
254 */
255static LY_ERR
256lyb_parse_model(struct lyd_lyb_ctx *lybctx, const struct lys_module **mod)
257{
258 LY_ERR ret = LY_SUCCESS;
259 char *mod_name = NULL, mod_rev[11];
260 uint16_t rev;
261
262 /* model name */
263 ret = lyb_read_string(&mod_name, 1, lybctx);
264 LY_CHECK_GOTO(ret, cleanup);
265
266 /* revision */
267 lyb_read_number(&rev, sizeof rev, 2, lybctx);
268
269 if (!mod_name[0]) {
270 /* opaq node, no module */
271 *mod = NULL;
272 goto cleanup;
273 }
274
275 if (rev) {
276 sprintf(mod_rev, "%04u-%02u-%02u", ((rev & 0xFE00) >> 9) + 2000, (rev & 0x01E0) >> 5, rev & 0x001Fu);
277 *mod = ly_ctx_get_module(lybctx->ctx, mod_name, mod_rev);
Radek Krejci7931b192020-06-25 17:05:03 +0200278 if ((lybctx->parse_options & LYD_PARSE_LYB_MOD_UPDATE) && !(*mod)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200279 /* try to use an updated module */
280 *mod = ly_ctx_get_module_implemented(lybctx->ctx, mod_name);
281 if (*mod && (!(*mod)->revision || (strcmp((*mod)->revision, mod_rev) < 0))) {
282 /* not an implemented module in a newer revision */
283 *mod = NULL;
284 }
285 }
286 } else {
287 *mod = ly_ctx_get_module_latest(lybctx->ctx, mod_name);
288 }
289 /* TODO data_clb supported?
290 if (lybctx->ctx->data_clb) {
291 if (!*mod) {
292 *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, NULL, 0, lybctx->ctx->data_clb_data);
293 } else if (!(*mod)->implemented) {
294 *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, (*mod)->ns, LY_MODCLB_NOT_IMPLEMENTED, lybctx->ctx->data_clb_data);
295 }
296 }*/
297
298 if (!*mod || !(*mod)->implemented) {
Radek Krejci7931b192020-06-25 17:05:03 +0200299 if (lybctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200300 if (!*mod) {
301 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, missing module \"%s%s%s\".",
302 mod_name, rev ? "@" : "", rev ? mod_rev : "");
303 } else if (!(*mod)->implemented) {
304 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, module \"%s%s%s\" not implemented.",
305 mod_name, rev ? "@" : "", rev ? mod_rev : "");
306 }
307 ret = LY_EINVAL;
308 goto cleanup;
309 }
310
311 }
312
313cleanup:
314 free(mod_name);
315 return ret;
316}
317
318/**
319 * @brief Parse YANG node metadata.
320 *
321 * @param[in] lybctx LYB context.
322 * @param[in] sparent Schema parent node.
323 * @param[out] meta Parsed metadata.
324 * @return LY_ERR value.
325 */
326static LY_ERR
327lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, struct lyd_meta **meta)
328{
329 LY_ERR ret = LY_SUCCESS;
330 int dynamic = 0;
331 uint8_t i, count = 0;
332 char *meta_name = NULL, *meta_value = NULL;
333 const struct lys_module *mod;
334
335 /* read number of attributes stored */
336 lyb_read(&count, 1, lybctx);
337
338 /* read attributes */
339 for (i = 0; i < count; ++i) {
340 ret = lyb_read_start_subtree(lybctx);
341 LY_CHECK_GOTO(ret, cleanup);
342
343 /* find model */
344 ret = lyb_parse_model(lybctx, &mod);
345 LY_CHECK_GOTO(ret, cleanup);
346
347 if (!mod) {
348 /* skip it */
349 do {
350 lyb_read(NULL, LYB_LAST_SUBTREE(lybctx).written, lybctx);
351 } while (LYB_LAST_SUBTREE(lybctx).written);
352 goto stop_subtree;
353 }
354
355 /* meta name */
356 ret = lyb_read_string(&meta_name, 1, lybctx);
357 LY_CHECK_GOTO(ret, cleanup);
358
359 /* meta value */
360 ret = lyb_read_string(&meta_value, 0, lybctx);
361 LY_CHECK_GOTO(ret, cleanup);
362 dynamic = 1;
363
364 /* create metadata */
365 ret = lyd_create_meta(NULL, meta, mod, meta_name, strlen(meta_name), meta_value, strlen(meta_value), &dynamic,
366 lydjson_resolve_prefix, NULL, LYD_JSON, sparent);
367
368 /* free strings */
369 free(meta_name);
370 meta_name = NULL;
371 if (dynamic) {
372 free(meta_value);
373 dynamic = 0;
374 }
375 meta_value = NULL;
376
377 if (ret == LY_EINCOMPLETE) {
378 ly_set_add(&lybctx->unres_meta_type, *meta, LY_SET_OPT_USEASLIST);
379 } else if (ret) {
380 goto cleanup;
381 }
382
383stop_subtree:
384 ret = lyb_read_stop_subtree(lybctx);
385 LY_CHECK_GOTO(ret, cleanup);
386 }
387
388cleanup:
389 free(meta_name);
390 if (dynamic) {
391 free(meta_value);
392 }
393 if (ret) {
394 lyd_free_meta(lybctx->ctx, *meta, 1);
395 *meta = NULL;
396 }
397 return ret;
398}
399
400/**
401 * @brief Parse opaque prefixes structure.
402 *
403 * @param[in] lybctx LYB context.
404 * @param[out] prefs Parsed prefixes.
405 * @return LY_ERR value.
406 */
407static LY_ERR
408lyb_parse_opaq_prefixes(struct lyd_lyb_ctx *lybctx, struct ly_prefix **prefs)
409{
410 LY_ERR ret = LY_SUCCESS;
411 uint8_t count, i;
412 char *str;
413
414 /* read count */
415 lyb_read(&count, 1, lybctx);
416 if (!count) {
417 return LY_SUCCESS;
418 }
419
420 LY_ARRAY_CREATE_RET(lybctx->ctx, *prefs, count, LY_EMEM);
421 for (i = 0; i < count; ++i) {
422 LY_ARRAY_INCREMENT(*prefs);
423
424 /* prefix */
425 ret = lyb_read_string(&str, 1, lybctx);
426 LY_CHECK_GOTO(ret, cleanup);
427 (*prefs)[i].pref = lydict_insert_zc(lybctx->ctx, str);
428
429 /* namespace */
430 ret = lyb_read_string(&str, 1, lybctx);
431 LY_CHECK_GOTO(ret, cleanup);
432 (*prefs)[i].ns = lydict_insert_zc(lybctx->ctx, str);
433 }
434
435cleanup:
436 if (ret) {
437 ly_free_val_prefs(lybctx->ctx, *prefs);
438 *prefs = NULL;
439 }
440 return ret;
441}
442
443/**
444 * @brief Parse opaque attributes.
445 *
446 * @param[in] lybctx LYB context.
447 * @param[out] attr Parsed attributes.
448 * @return LY_ERR value.
449 */
450static LY_ERR
451lyb_parse_attributes(struct lyd_lyb_ctx *lybctx, struct ly_attr **attr)
452{
453 LY_ERR ret = LY_SUCCESS;
454 uint8_t count, i;
455 struct ly_attr *attr2;
456 char *prefix = NULL, *ns = NULL, *name = NULL, *value = NULL;
457 int dynamic = 0;
458 LYD_FORMAT format = 0;
459 struct ly_prefix *val_prefs = NULL;
460
461 /* read count */
462 lyb_read(&count, 1, lybctx);
463
464 /* read attributes */
465 for (i = 0; i < count; ++i) {
466 ret = lyb_read_start_subtree(lybctx);
467 LY_CHECK_GOTO(ret, cleanup);
468
469 /* prefix, may be emtpy */
470 ret = lyb_read_string(&prefix, 1, lybctx);
471 LY_CHECK_GOTO(ret, cleanup);
472 if (!prefix[0]) {
473 free(prefix);
474 prefix = NULL;
475 }
476
477 /* namespace, may be empty */
478 ret = lyb_read_string(&ns, 1, lybctx);
479 LY_CHECK_GOTO(ret, cleanup);
480 if (!ns[0]) {
481 free(ns);
482 ns = NULL;
483 }
484
485 /* name */
486 ret = lyb_read_string(&name, 1, lybctx);
487 LY_CHECK_GOTO(ret, cleanup);
488
489 /* value prefixes */
490 ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
491 LY_CHECK_GOTO(ret, cleanup);
492
493 /* format */
494 lyb_read((uint8_t *)&format, 1, lybctx);
495
496 /* value */
497 ret = lyb_read_string(&value, 0, lybctx);
498 LY_CHECK_GOTO(ret, cleanup);
499 dynamic = 1;
500
501 /* attr2 is always changed to the created attribute */
502 ret = ly_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format,
503 val_prefs, prefix, prefix ? strlen(prefix) : 0, ns);
504 LY_CHECK_GOTO(ret, cleanup);
505
506 free(prefix);
507 prefix = NULL;
508 free(ns);
509 ns = NULL;
510 free(name);
511 name = NULL;
512 val_prefs = NULL;
513 assert(!dynamic);
514 value = NULL;
515
516 if (!*attr) {
517 *attr = attr2;
518 }
519
520 ret = lyb_read_stop_subtree(lybctx);
521 LY_CHECK_GOTO(ret, cleanup);
522 }
523
524cleanup:
525 free(prefix);
526 free(ns);
527 free(name);
528 if (dynamic) {
529 free(value);
530 }
531 ly_free_val_prefs(lybctx->ctx, val_prefs);
532 if (ret) {
533 ly_free_attr(lybctx->ctx, *attr, 1);
534 *attr = NULL;
535 }
536 return ret;
537}
538
539/**
540 * @brief Check whether a schema node matches a hash(es).
541 *
542 * @param[in] sibling Schema node to check.
543 * @param[in] hash Hash array to check.
544 * @param[in] hash_count Number of hashes in @p hash.
545 * @return non-zero if matches,
546 * @return 0 if not.
547 */
548static int
549lyb_is_schema_hash_match(struct lysc_node *sibling, LYB_HASH *hash, uint8_t hash_count)
550{
551 LYB_HASH sibling_hash;
552 uint8_t i;
553
554 /* compare all the hashes starting from collision ID 0 */
555 for (i = 0; i < hash_count; ++i) {
556 sibling_hash = lyb_hash(sibling, i);
557 if (sibling_hash != hash[i]) {
558 return 0;
559 }
560 }
561
562 return 1;
563}
564
565/**
566 * @brief Check that a schema node is suitable based on options.
567 *
568 * @param[in] lybctx LYB context.
569 * @param[in] snode Schema node to check.
570 * @return LY_ERR value.
571 */
572static LY_ERR
573lyb_parse_check_schema(struct lyd_lyb_ctx *lybctx, const struct lysc_node *snode)
574{
575 LY_ERR ret = LY_SUCCESS;
576
Radek Krejci7931b192020-06-25 17:05:03 +0200577 if ((lybctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200578 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LY_VCODE_INNODE, "state", snode->name);
579 return LY_EVALID;
580 }
581
582 if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
583 if (lybctx->int_opts & LYD_INTOPT_RPC) {
584 if (lybctx->op_ntf) {
585 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
586 lys_nodetype2str(snode->nodetype), snode->name,
587 lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
588 return LY_EVALID;
589 }
590 } else {
591 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
592 lys_nodetype2str(snode->nodetype), snode->name);
593 return LY_EVALID;
594 }
595 } else if (snode->nodetype == LYS_NOTIF) {
596 if (lybctx->int_opts & LYD_INTOPT_NOTIF) {
597 if (lybctx->op_ntf) {
598 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
599 lys_nodetype2str(snode->nodetype), snode->name,
600 lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
601 return LY_EVALID;
602 }
603 } else {
604 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
605 lys_nodetype2str(snode->nodetype), snode->name);
606 return LY_EVALID;
607 }
608 }
609
610 return ret;
611}
612
613/**
614 * @brief Parse schema node hash.
615 *
616 * @param[in] lybctx LYB context.
617 * @param[in] sparent Schema parent, must be set if @p mod is not.
618 * @param[in] mod Module of the top-level node, must be set if @p sparent is not.
619 * @param[out] snode Parsed found schema node, may be NULL if opaque.
620 * @return LY_ERR value.
621 */
622static LY_ERR
623lyb_parse_schema_hash(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, const struct lys_module *mod,
624 const struct lysc_node **snode)
625{
626 LY_ERR ret;
627 uint8_t i, j;
628 const struct lysc_node *sibling;
629 LYB_HASH hash[LYB_HASH_BITS - 1];
630 int getnext_opts;
631
632 *snode = NULL;
633 /* leave if-feature check for validation */
634 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lybctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
635
636 /* read the first hash */
637 lyb_read(&hash[0], sizeof *hash, lybctx);
638
639 if (!hash[0]) {
640 /* opaque node */
641 return LY_SUCCESS;
642 }
643
644 /* based on the first hash read all the other ones, if any */
645 for (i = 0; !(hash[0] & (LYB_HASH_COLLISION_ID >> i)); ++i) {
646 if (i > LYB_HASH_BITS) {
647 LOGINT_RET(lybctx->ctx);
648 }
649 }
650
651 /* move the first hash on its accurate position */
652 hash[i] = hash[0];
653
654 /* read the rest of hashes */
655 for (j = i; j; --j) {
656 lyb_read(&hash[j - 1], sizeof *hash, lybctx);
657
658 /* correct collision ID */
659 assert(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)));
660 /* preceded with zeros */
661 assert(!(hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))));
662 }
663
664 /* find our node with matching hashes */
665 sibling = NULL;
666 while ((sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts))) {
667 /* skip schema nodes from models not present during printing */
668 if (lyb_has_schema_model(sibling, lybctx->models)
669 && lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, i + 1)) {
670 /* match found */
671 break;
672 }
673 }
674
Radek Krejci7931b192020-06-25 17:05:03 +0200675 if (!sibling && (lybctx->parse_options & LYD_PARSE_STRICT)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200676 if (mod) {
677 LOGVAL(lybctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
678 " from \"%s\".", mod->name);
679 } else {
680 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, sparent, LYVE_REFERENCE, "Failed to find matching hash for a child node"
681 " of \"%s\".", sparent->name);
682 }
683 return LY_EVALID;
684 } else if (sibling && (ret = lyb_parse_check_schema(lybctx, sibling))) {
685 return ret;
686 }
687
688 *snode = sibling;
689 return LY_SUCCESS;
690}
691
692/**
693 * @brief Read until the end of the current subtree.
694 *
695 * @param[in] lybctx LYB context.
696 */
697static void
698lyb_skip_subtree(struct lyd_lyb_ctx *lybctx)
699{
700 int parsed;
701
702 do {
703 /* first skip any meta information inside */
704 parsed = LYB_LAST_SUBTREE(lybctx).inner_chunks * LYB_META_BYTES;
705 lybctx->data += parsed;
706 lybctx->byte_count += parsed;
707
708 /* then read data */
709 lyb_read(NULL, LYB_LAST_SUBTREE(lybctx).written, lybctx);
710 } while (LYB_LAST_SUBTREE(lybctx).written);
711}
712
713/**
714 * @brief Parse LYB subtree.
715 *
716 * @param[in] lybctx LYB context.
717 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
718 * @param[in,out] first First top-level sibling, must be set if @p parent is not.
719 * @return LY_ERR value.
720 */
721static LY_ERR
722lyb_parse_subtree_r(struct lyd_lyb_ctx *lybctx, struct lyd_node_inner *parent, struct lyd_node **first)
723{
724 LY_ERR ret = LY_SUCCESS;
725 struct lyd_node *node = NULL, *tree;
726 const struct lys_module *mod;
727 const struct lysc_node *snode = NULL;
728 struct lyd_meta *meta = NULL, *m;
729 struct ly_attr *attr = NULL, *a;
730 struct ly_prefix *val_prefs = NULL;
731 LYD_ANYDATA_VALUETYPE value_type;
732 char *value = NULL, *name = NULL, *prefix = NULL, *ns = NULL;
733 int dynamic = 0;
734 LYD_FORMAT format = 0;
735 int prev_lo;
736
737 /* register a new subtree */
738 LY_CHECK_GOTO(ret = lyb_read_start_subtree(lybctx), cleanup);
739
740 if (!parent) {
741 /* top-level, read module name */
742 ret = lyb_parse_model(lybctx, &mod);
743 LY_CHECK_GOTO(ret, cleanup);
744
745 /* read hash, find the schema node starting from mod */
746 ret = lyb_parse_schema_hash(lybctx, NULL, mod, &snode);
747 LY_CHECK_GOTO(ret, cleanup);
748 } else {
749 /* read hash, find the schema node starting from parent schema */
750 ret = lyb_parse_schema_hash(lybctx, parent->schema, NULL, &snode);
751 LY_CHECK_GOTO(ret, cleanup);
752 }
753
Radek Krejci7931b192020-06-25 17:05:03 +0200754 if (!snode && !(lybctx->parse_options & LYD_PARSE_OPAQ)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200755 /* unknown data, skip them */
756 lyb_skip_subtree(lybctx);
757 goto stop_subtree;
758 }
759
760 /* create metadata/attributes */
761 if (snode) {
762 ret = lyb_parse_metadata(lybctx, snode, &meta);
763 LY_CHECK_GOTO(ret, cleanup);
764 } else {
765 ret = lyb_parse_attributes(lybctx, &attr);
766 LY_CHECK_GOTO(ret, cleanup);
767 }
768
769 if (!snode) {
770 /* parse prefix */
771 ret = lyb_read_string(&prefix, 1, lybctx);
772 LY_CHECK_GOTO(ret, cleanup);
773
774 /* parse namespace */
775 ret = lyb_read_string(&ns, 1, lybctx);
776 LY_CHECK_GOTO(ret, cleanup);
777
778 /* parse name */
779 ret = lyb_read_string(&name, 1, lybctx);
780 LY_CHECK_GOTO(ret, cleanup);
781
782 /* parse value prefixes */
783 ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
784 LY_CHECK_GOTO(ret, cleanup);
785
786 /* parse format */
787 lyb_read((uint8_t *)&format, 1, lybctx);
788
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_opaq(lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format, val_prefs, prefix,
796 strlen(prefix), ns, &node);
797 LY_CHECK_GOTO(ret, cleanup);
798
799 /* process children */
800 while (LYB_LAST_SUBTREE(lybctx).written) {
801 ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
802 LY_CHECK_GOTO(ret, cleanup);
803 }
804 } else if (snode->nodetype & LYD_NODE_TERM) {
805 /* parse value */
806 ret = lyb_read_string(&value, 0, lybctx);
807 LY_CHECK_GOTO(ret, cleanup);
808 dynamic = 1;
809
810 /* create node */
811 ret = lyd_create_term(snode, value, strlen(value), &dynamic, lydjson_resolve_prefix, NULL, LYD_JSON, &node);
812 if (dynamic) {
813 free(value);
814 dynamic = 0;
815 }
816 value = NULL;
817 if (ret == LY_EINCOMPLETE) {
Radek Krejci7931b192020-06-25 17:05:03 +0200818 if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200819 ly_set_add(&lybctx->unres_node_type, node, LY_SET_OPT_USEASLIST);
820 }
821 ret = LY_SUCCESS;
822 } else if (ret) {
823 goto cleanup;
824 }
825 } else if (snode->nodetype & LYD_NODE_INNER) {
826 /* create node */
827 ret = lyd_create_inner(snode, &node);
828 LY_CHECK_GOTO(ret, cleanup);
829
830 /* process children */
831 while (LYB_LAST_SUBTREE(lybctx).written) {
832 ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
833 LY_CHECK_GOTO(ret, cleanup);
834 }
835
Radek Krejci7931b192020-06-25 17:05:03 +0200836 if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200837 /* new node validation, autodelete CANNOT occur, all nodes are new */
838 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL);
839 LY_CHECK_GOTO(ret, cleanup);
840
841 /* add any missing default children */
842 ret = lyd_validate_defaults_r((struct lyd_node_inner *)node, lyd_node_children_p(node), NULL, NULL,
Radek Krejci7931b192020-06-25 17:05:03 +0200843 &lybctx->unres_node_type, &lybctx->when_check, lybctx->validate_options);
Michal Vasko60ea6352020-06-29 13:39:39 +0200844 LY_CHECK_GOTO(ret, cleanup);
845 }
846
847 if (snode->nodetype == LYS_LIST) {
848 /* hash now that all keys should be parsed, rehash for key-less list */
849 lyd_hash(node);
850 } else if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
851 /* rememeber the RPC/action/notification */
852 lybctx->op_ntf = node;
853 }
854 } else if (snode->nodetype & LYD_NODE_ANY) {
855 /* parse value type */
856 lyb_read((uint8_t *)&value_type, sizeof value_type, lybctx);
857 if (value_type == LYD_ANYDATA_DATATREE) {
858 /* invalid situation */
859 LOGINT(lybctx->ctx);
860 goto cleanup;
861 }
862
863 /* read anydata content */
864 ret = lyb_read_string(&value, 0, lybctx);
865 LY_CHECK_GOTO(ret, cleanup);
866 dynamic = 1;
867
868 if (value_type == LYD_ANYDATA_LYB) {
869 /* turn logging off */
870 prev_lo = ly_log_options(0);
871
872 /* try to parse LYB into a data tree */
Radek Krejci7931b192020-06-25 17:05:03 +0200873 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 +0200874 /* successfully parsed */
875 free(value);
876 value = (char *)tree;
877 value_type = LYD_ANYDATA_DATATREE;
878 }
Radek Krejci7931b192020-06-25 17:05:03 +0200879
880 /* turn logging on again */
881 ly_log_options(prev_lo);
Michal Vasko60ea6352020-06-29 13:39:39 +0200882 }
883
884 /* create node */
885 ret = lyd_create_any(snode, value, value_type, &node);
886 LY_CHECK_GOTO(ret, cleanup);
887
888 dynamic = 0;
889 value = NULL;
890 }
891 assert(node);
892
893 /* add/correct flags */
894 if (snode) {
Radek Krejci7931b192020-06-25 17:05:03 +0200895 lyd_parse_set_data_flags(node, &lybctx->when_check, &meta, lybctx->parse_options);
Michal Vasko60ea6352020-06-29 13:39:39 +0200896 }
897
898 /* add metadata/attributes */
899 if (snode) {
900 LY_LIST_FOR(meta, m) {
901 m->parent = node;
902 }
903 node->meta = meta;
904 meta = NULL;
905 } else {
906 assert(!node->schema);
907 LY_LIST_FOR(attr, a) {
908 a->parent = (struct lyd_node_opaq *)node;
909 }
910 ((struct lyd_node_opaq *)node)->attr = attr;
911 attr = NULL;
912 }
913
914 /* insert */
915 lyd_insert_node((struct lyd_node *)parent, first, node);
916 node = NULL;
917
918stop_subtree:
919 /* end the subtree */
920 ret = lyb_read_stop_subtree(lybctx);
921 LY_CHECK_GOTO(ret, cleanup);
922
923cleanup:
924 free(prefix);
925 free(ns);
926 free(name);
927 if (dynamic) {
928 free(value);
929 }
930 ly_free_val_prefs(lybctx->ctx, val_prefs);
931
932 lyd_free_meta(lybctx->ctx, meta, 1);
933 ly_free_attr(lybctx->ctx, attr, 1);
934 lyd_free_tree(node);
935 return ret;
936}
937
938/**
939 * @brief Parse used YANG data models.
940 *
941 * @param[in] lybctx LYB context.
942 * @return LY_ERR value.
943 */
944static LY_ERR
945lyb_parse_data_models(struct lyd_lyb_ctx *lybctx)
946{
947 LY_ERR ret;
948 uint32_t count;
949 LY_ARRAY_SIZE_TYPE u;
950
951 /* read model count */
952 lyb_read_number(&count, sizeof count, 2, lybctx);
953
954 if (count) {
955 LY_ARRAY_CREATE_RET(lybctx->ctx, lybctx->models, count, LY_EMEM);
956
957 /* read modules */
958 for (u = 0; u < count; ++u) {
959 ret = lyb_parse_model(lybctx, &lybctx->models[u]);
960 LY_CHECK_RET(ret);
961 LY_ARRAY_INCREMENT(lybctx->models);
962 }
963 }
964
965 return LY_SUCCESS;
966}
967
968/**
969 * @brief Parse LYB magic number.
970 *
971 * @param[in] lybctx LYB context.
972 * @return LY_ERR value.
973 */
974static LY_ERR
975lyb_parse_magic_number(struct lyd_lyb_ctx *lybctx)
976{
977 char magic_byte = 0;
978
979 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
980 if (magic_byte != 'l') {
981 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid first magic number byte \"0x%02x\".", magic_byte);
982 return LY_EINVAL;
983 }
984
985 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
986 if (magic_byte != 'y') {
987 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid second magic number byte \"0x%02x\".", magic_byte);
988 return LY_EINVAL;
989 }
990
991 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
992 if (magic_byte != 'b') {
993 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid third magic number byte \"0x%02x\".", magic_byte);
994 return LY_EINVAL;
995 }
996
997 return LY_SUCCESS;
998}
999
1000/**
1001 * @brief Parse LYB header.
1002 *
1003 * @param[in] lybctx LYB context.
1004 * @return LY_ERR value.
1005 */
1006static LY_ERR
1007lyb_parse_header(struct lyd_lyb_ctx *lybctx)
1008{
1009 uint8_t byte = 0;
1010
1011 /* version, future flags */
1012 lyb_read((uint8_t *)&byte, sizeof byte, lybctx);
1013
1014 if ((byte & LYB_VERSION_MASK) != LYB_VERSION_NUM) {
1015 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid LYB format version \"0x%02x\", expected \"0x%02x\".",
1016 byte & LYB_VERSION_MASK, LYB_VERSION_NUM);
1017 return LY_EINVAL;
1018 }
1019
1020 return LY_SUCCESS;
1021}
1022
1023LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001024lyd_parse_lyb_data(const struct ly_ctx *ctx, const char *data, int parse_options, int validate_options, struct lyd_node **tree, int *parsed_bytes)
Michal Vasko60ea6352020-06-29 13:39:39 +02001025{
1026 LY_ERR ret = LY_SUCCESS;
1027 struct lyd_lyb_ctx lybctx = {0};
1028
Radek Krejci7931b192020-06-25 17:05:03 +02001029 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
1030 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
1031
Michal Vasko60ea6352020-06-29 13:39:39 +02001032 *tree = NULL;
1033
1034 lybctx.data = data;
1035 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001036 lybctx.parse_options = parse_options;
1037 lybctx.validate_options = validate_options;
Michal Vasko60ea6352020-06-29 13:39:39 +02001038
1039 /* read magic number */
1040 ret = lyb_parse_magic_number(&lybctx);
1041 LY_CHECK_GOTO(ret, cleanup);
1042
1043 /* read header */
1044 ret = lyb_parse_header(&lybctx);
1045 LY_CHECK_GOTO(ret, cleanup);
1046
1047 /* read used models */
1048 ret = lyb_parse_data_models(&lybctx);
1049 LY_CHECK_GOTO(ret, cleanup);
1050
1051 /* read subtree(s) */
1052 while (lybctx.data[0]) {
1053 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1054 LY_CHECK_GOTO(ret, cleanup);
1055 }
1056
1057 /* read the last zero, parsing finished */
1058 ++lybctx.byte_count;
1059 ++lybctx.data;
1060
1061 /* TODO validation */
1062
1063cleanup:
1064 LY_ARRAY_FREE(lybctx.subtrees);
1065 LY_ARRAY_FREE(lybctx.models);
1066 ly_set_erase(&lybctx.unres_node_type, NULL);
1067 ly_set_erase(&lybctx.unres_meta_type, NULL);
1068 ly_set_erase(&lybctx.when_check, NULL);
1069
1070 if (parsed_bytes) {
1071 *parsed_bytes = lybctx.byte_count;
1072 }
1073 if (ret) {
1074 lyd_free_all(*tree);
1075 *tree = NULL;
1076 }
1077 return ret;
1078}
1079
1080LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001081lyd_parse_lyb_rpc(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op, int *parsed_bytes)
Michal Vasko60ea6352020-06-29 13:39:39 +02001082{
1083 LY_ERR ret = LY_SUCCESS;
1084 struct lyd_lyb_ctx lybctx = {0};
1085
1086 lybctx.data = data;
1087 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001088 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001089 lybctx.int_opts = LYD_INTOPT_RPC;
1090
1091 *tree = NULL;
1092 if (op) {
1093 *op = NULL;
1094 }
1095
1096 /* read magic number */
1097 ret = lyb_parse_magic_number(&lybctx);
1098 LY_CHECK_GOTO(ret, cleanup);
1099
1100 /* read header */
1101 ret = lyb_parse_header(&lybctx);
1102 LY_CHECK_GOTO(ret, cleanup);
1103
1104 /* read used models */
1105 ret = lyb_parse_data_models(&lybctx);
1106 LY_CHECK_GOTO(ret, cleanup);
1107
1108 /* read subtree(s) */
1109 while (lybctx.data[0]) {
1110 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1111 LY_CHECK_GOTO(ret, cleanup);
1112 }
1113
1114 /* read the last zero, parsing finished */
1115 ++lybctx.byte_count;
1116 ++lybctx.data;
1117
1118 /* make sure we have parsed some operation */
1119 if (!lybctx.op_ntf) {
1120 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
1121 ret = LY_EVALID;
1122 goto cleanup;
1123 }
1124
1125 if (op) {
1126 *op = lybctx.op_ntf;
1127 }
1128 assert(*tree);
1129
1130cleanup:
1131 LY_ARRAY_FREE(lybctx.subtrees);
1132 LY_ARRAY_FREE(lybctx.models);
1133 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1134
1135 if (parsed_bytes) {
1136 *parsed_bytes = lybctx.byte_count;
1137 }
1138 if (ret) {
1139 lyd_free_all(*tree);
1140 *tree = NULL;
1141 }
1142 return ret;
1143}
1144
1145LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001146lyd_parse_lyb_notif(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf, int *parsed_bytes)
Michal Vasko60ea6352020-06-29 13:39:39 +02001147{
1148 LY_ERR ret = LY_SUCCESS;
1149 struct lyd_lyb_ctx lybctx = {0};
1150
1151 lybctx.data = data;
1152 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001153 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001154 lybctx.int_opts = LYD_INTOPT_NOTIF;
1155
1156 *tree = NULL;
1157 if (ntf) {
1158 *ntf = NULL;
1159 }
1160
1161 /* read magic number */
1162 ret = lyb_parse_magic_number(&lybctx);
1163 LY_CHECK_GOTO(ret, cleanup);
1164
1165 /* read header */
1166 ret = lyb_parse_header(&lybctx);
1167 LY_CHECK_GOTO(ret, cleanup);
1168
1169 /* read used models */
1170 ret = lyb_parse_data_models(&lybctx);
1171 LY_CHECK_GOTO(ret, cleanup);
1172
1173 /* read subtree(s) */
1174 while (lybctx.data[0]) {
1175 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1176 LY_CHECK_GOTO(ret, cleanup);
1177 }
1178
1179 /* read the last zero, parsing finished */
1180 ++lybctx.byte_count;
1181 ++lybctx.data;
1182
1183 /* make sure we have parsed some notification */
1184 if (!lybctx.op_ntf) {
1185 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1186 ret = LY_EVALID;
1187 goto cleanup;
1188 }
1189
1190 if (ntf) {
1191 *ntf = lybctx.op_ntf;
1192 }
1193 assert(*tree);
1194
1195cleanup:
1196 LY_ARRAY_FREE(lybctx.subtrees);
1197 LY_ARRAY_FREE(lybctx.models);
1198 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1199
1200 if (parsed_bytes) {
1201 *parsed_bytes = lybctx.byte_count;
1202 }
1203 if (ret) {
1204 lyd_free_all(*tree);
1205 *tree = NULL;
1206 }
1207 return ret;
1208}
1209
1210LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001211lyd_parse_lyb_reply(const struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op,
Michal Vasko60ea6352020-06-29 13:39:39 +02001212 int *parsed_bytes)
1213{
1214 LY_ERR ret = LY_SUCCESS;
1215 struct lyd_lyb_ctx lybctx = {0};
1216 struct lyd_node *iter, *req_op, *rep_op = NULL;
1217
1218 lybctx.data = data;
1219 lybctx.ctx = LYD_NODE_CTX(request);
Radek Krejci7931b192020-06-25 17:05:03 +02001220 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001221 lybctx.int_opts = LYD_INTOPT_REPLY;
1222
1223 *tree = NULL;
1224 if (op) {
1225 *op = NULL;
1226 }
1227
1228 /* find request OP */
1229 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, iter, req_op) {
1230 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1231 break;
1232 }
1233 LYD_TREE_DFS_END(request, iter, req_op);
1234 }
1235 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1236 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1237 ret = LY_EINVAL;
1238 goto cleanup;
1239 }
1240
1241 /* duplicate request OP with parents */
1242 rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
1243 LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
1244
1245 /* read magic number */
1246 ret = lyb_parse_magic_number(&lybctx);
1247 LY_CHECK_GOTO(ret, cleanup);
1248
1249 /* read header */
1250 ret = lyb_parse_header(&lybctx);
1251 LY_CHECK_GOTO(ret, cleanup);
1252
1253 /* read used models */
1254 ret = lyb_parse_data_models(&lybctx);
1255 LY_CHECK_GOTO(ret, cleanup);
1256
1257 /* read subtree(s) */
1258 while (lybctx.data[0]) {
1259 ret = lyb_parse_subtree_r(&lybctx, (struct lyd_node_inner *)rep_op, NULL);
1260 LY_CHECK_GOTO(ret, cleanup);
1261 }
1262
1263 /* read the last zero, parsing finished */
1264 ++lybctx.byte_count;
1265 ++lybctx.data;
1266
1267 if (op) {
1268 *op = rep_op;
1269 }
1270 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
1271 *tree = iter;
1272 rep_op = NULL;
1273
1274cleanup:
1275 lyd_free_all(rep_op);
1276 LY_ARRAY_FREE(lybctx.subtrees);
1277 LY_ARRAY_FREE(lybctx.models);
1278 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1279
1280 if (parsed_bytes) {
1281 *parsed_bytes = lybctx.byte_count;
1282 }
1283 if (ret) {
1284 lyd_free_all(*tree);
1285 *tree = NULL;
1286 }
1287 return ret;
1288}
1289
1290API int
1291lyd_lyb_data_length(const char *data)
1292{
1293 LY_ERR ret = LY_SUCCESS;
1294 struct lyd_lyb_ctx lybctx = {0};
1295 int count, i;
1296 size_t len;
1297 uint8_t buf[LYB_SIZE_MAX];
1298
1299 if (!data) {
1300 return -1;
1301 }
1302
1303 lybctx.data = data;
1304
1305 /* read magic number */
1306 ret = lyb_parse_magic_number(&lybctx);
1307 LY_CHECK_GOTO(ret, cleanup);
1308
1309 /* read header */
1310 ret = lyb_parse_header(&lybctx);
1311 LY_CHECK_GOTO(ret, cleanup);
1312
1313 /* read model count */
1314 lyb_read_number(&count, sizeof count, 2, &lybctx);
1315
1316 /* read all models */
1317 for (i = 0; i < count; ++i) {
1318 /* module name length */
1319 len = 0;
1320 lyb_read_number(&len, sizeof len, 2, &lybctx);
1321
1322 /* model name */
1323 lyb_read(buf, len, &lybctx);
1324
1325 /* revision */
1326 lyb_read(buf, 2, &lybctx);
1327 }
1328
1329 while (lybctx.data[0]) {
1330 /* register a new subtree */
1331 ret = lyb_read_start_subtree(&lybctx);
1332 LY_CHECK_GOTO(ret, cleanup);
1333
1334 /* skip it */
1335 lyb_skip_subtree(&lybctx);
1336
1337 /* subtree finished */
1338 ret = lyb_read_stop_subtree(&lybctx);
1339 LY_CHECK_GOTO(ret, cleanup);
1340 }
1341
1342 /* read the last zero, parsing finished */
1343 ++lybctx.byte_count;
1344 ++lybctx.data;
1345
1346cleanup:
1347 LY_ARRAY_FREE(lybctx.subtrees);
1348 return ret ? -1 : (signed)lybctx.byte_count;
1349}