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