blob: 499cf28d3dab9277498fa77247af0b1e15a7f6eb [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;
Michal Vaskofd69e1d2020-07-03 11:57:17 +020047 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +020048 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];
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200223 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200224
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 {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200229 u = LY_ARRAY_COUNT(lybctx->subtrees);
Michal Vasko60ea6352020-06-29 13:39:39 +0200230 }
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;
Michal Vasko1e5d5612020-07-03 13:29:26 +0200330 int dynamic;
Michal Vasko60ea6352020-06-29 13:39:39 +0200331 uint8_t i, count = 0;
Michal Vasko1e5d5612020-07-03 13:29:26 +0200332 char *meta_name = NULL, *meta_value;
Michal Vasko60ea6352020-06-29 13:39:39 +0200333 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 }
Michal Vasko60ea6352020-06-29 13:39:39 +0200375
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);
Michal Vasko60ea6352020-06-29 13:39:39 +0200389 if (ret) {
390 lyd_free_meta(lybctx->ctx, *meta, 1);
391 *meta = NULL;
392 }
393 return ret;
394}
395
396/**
397 * @brief Parse opaque prefixes structure.
398 *
399 * @param[in] lybctx LYB context.
400 * @param[out] prefs Parsed prefixes.
401 * @return LY_ERR value.
402 */
403static LY_ERR
404lyb_parse_opaq_prefixes(struct lyd_lyb_ctx *lybctx, struct ly_prefix **prefs)
405{
406 LY_ERR ret = LY_SUCCESS;
407 uint8_t count, i;
408 char *str;
409
410 /* read count */
411 lyb_read(&count, 1, lybctx);
412 if (!count) {
413 return LY_SUCCESS;
414 }
415
416 LY_ARRAY_CREATE_RET(lybctx->ctx, *prefs, count, LY_EMEM);
417 for (i = 0; i < count; ++i) {
418 LY_ARRAY_INCREMENT(*prefs);
419
420 /* prefix */
421 ret = lyb_read_string(&str, 1, lybctx);
422 LY_CHECK_GOTO(ret, cleanup);
423 (*prefs)[i].pref = lydict_insert_zc(lybctx->ctx, str);
424
425 /* namespace */
426 ret = lyb_read_string(&str, 1, lybctx);
427 LY_CHECK_GOTO(ret, cleanup);
428 (*prefs)[i].ns = lydict_insert_zc(lybctx->ctx, str);
429 }
430
431cleanup:
432 if (ret) {
433 ly_free_val_prefs(lybctx->ctx, *prefs);
434 *prefs = NULL;
435 }
436 return ret;
437}
438
439/**
440 * @brief Parse opaque attributes.
441 *
442 * @param[in] lybctx LYB context.
443 * @param[out] attr Parsed attributes.
444 * @return LY_ERR value.
445 */
446static LY_ERR
447lyb_parse_attributes(struct lyd_lyb_ctx *lybctx, struct ly_attr **attr)
448{
449 LY_ERR ret = LY_SUCCESS;
450 uint8_t count, i;
451 struct ly_attr *attr2;
452 char *prefix = NULL, *ns = NULL, *name = NULL, *value = NULL;
453 int dynamic = 0;
454 LYD_FORMAT format = 0;
455 struct ly_prefix *val_prefs = NULL;
456
457 /* read count */
458 lyb_read(&count, 1, lybctx);
459
460 /* read attributes */
461 for (i = 0; i < count; ++i) {
462 ret = lyb_read_start_subtree(lybctx);
463 LY_CHECK_GOTO(ret, cleanup);
464
465 /* prefix, may be emtpy */
466 ret = lyb_read_string(&prefix, 1, lybctx);
467 LY_CHECK_GOTO(ret, cleanup);
468 if (!prefix[0]) {
469 free(prefix);
470 prefix = NULL;
471 }
472
473 /* namespace, may be empty */
474 ret = lyb_read_string(&ns, 1, lybctx);
475 LY_CHECK_GOTO(ret, cleanup);
476 if (!ns[0]) {
477 free(ns);
478 ns = NULL;
479 }
480
481 /* name */
482 ret = lyb_read_string(&name, 1, lybctx);
483 LY_CHECK_GOTO(ret, cleanup);
484
485 /* value prefixes */
486 ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
487 LY_CHECK_GOTO(ret, cleanup);
488
489 /* format */
490 lyb_read((uint8_t *)&format, 1, lybctx);
491
492 /* value */
493 ret = lyb_read_string(&value, 0, lybctx);
494 LY_CHECK_GOTO(ret, cleanup);
495 dynamic = 1;
496
497 /* attr2 is always changed to the created attribute */
498 ret = ly_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format,
499 val_prefs, prefix, prefix ? strlen(prefix) : 0, ns);
500 LY_CHECK_GOTO(ret, cleanup);
501
502 free(prefix);
503 prefix = NULL;
504 free(ns);
505 ns = NULL;
506 free(name);
507 name = NULL;
508 val_prefs = NULL;
509 assert(!dynamic);
510 value = NULL;
511
512 if (!*attr) {
513 *attr = attr2;
514 }
515
516 ret = lyb_read_stop_subtree(lybctx);
517 LY_CHECK_GOTO(ret, cleanup);
518 }
519
520cleanup:
521 free(prefix);
522 free(ns);
523 free(name);
524 if (dynamic) {
525 free(value);
526 }
527 ly_free_val_prefs(lybctx->ctx, val_prefs);
528 if (ret) {
529 ly_free_attr(lybctx->ctx, *attr, 1);
530 *attr = NULL;
531 }
532 return ret;
533}
534
535/**
536 * @brief Check whether a schema node matches a hash(es).
537 *
538 * @param[in] sibling Schema node to check.
539 * @param[in] hash Hash array to check.
540 * @param[in] hash_count Number of hashes in @p hash.
541 * @return non-zero if matches,
542 * @return 0 if not.
543 */
544static int
545lyb_is_schema_hash_match(struct lysc_node *sibling, LYB_HASH *hash, uint8_t hash_count)
546{
547 LYB_HASH sibling_hash;
548 uint8_t i;
549
550 /* compare all the hashes starting from collision ID 0 */
551 for (i = 0; i < hash_count; ++i) {
552 sibling_hash = lyb_hash(sibling, i);
553 if (sibling_hash != hash[i]) {
554 return 0;
555 }
556 }
557
558 return 1;
559}
560
561/**
562 * @brief Check that a schema node is suitable based on options.
563 *
564 * @param[in] lybctx LYB context.
565 * @param[in] snode Schema node to check.
566 * @return LY_ERR value.
567 */
568static LY_ERR
569lyb_parse_check_schema(struct lyd_lyb_ctx *lybctx, const struct lysc_node *snode)
570{
571 LY_ERR ret = LY_SUCCESS;
572
Radek Krejci7931b192020-06-25 17:05:03 +0200573 if ((lybctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200574 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LY_VCODE_INNODE, "state", snode->name);
575 return LY_EVALID;
576 }
577
578 if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
579 if (lybctx->int_opts & LYD_INTOPT_RPC) {
580 if (lybctx->op_ntf) {
581 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
582 lys_nodetype2str(snode->nodetype), snode->name,
583 lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
584 return LY_EVALID;
585 }
586 } else {
587 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
588 lys_nodetype2str(snode->nodetype), snode->name);
589 return LY_EVALID;
590 }
591 } else if (snode->nodetype == LYS_NOTIF) {
592 if (lybctx->int_opts & LYD_INTOPT_NOTIF) {
593 if (lybctx->op_ntf) {
594 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
595 lys_nodetype2str(snode->nodetype), snode->name,
596 lys_nodetype2str(lybctx->op_ntf->schema->nodetype), lybctx->op_ntf->schema->name);
597 return LY_EVALID;
598 }
599 } else {
600 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
601 lys_nodetype2str(snode->nodetype), snode->name);
602 return LY_EVALID;
603 }
604 }
605
606 return ret;
607}
608
609/**
610 * @brief Parse schema node hash.
611 *
612 * @param[in] lybctx LYB context.
613 * @param[in] sparent Schema parent, must be set if @p mod is not.
614 * @param[in] mod Module of the top-level node, must be set if @p sparent is not.
615 * @param[out] snode Parsed found schema node, may be NULL if opaque.
616 * @return LY_ERR value.
617 */
618static LY_ERR
619lyb_parse_schema_hash(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, const struct lys_module *mod,
620 const struct lysc_node **snode)
621{
622 LY_ERR ret;
623 uint8_t i, j;
624 const struct lysc_node *sibling;
625 LYB_HASH hash[LYB_HASH_BITS - 1];
626 int getnext_opts;
627
628 *snode = NULL;
629 /* leave if-feature check for validation */
630 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lybctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
631
632 /* read the first hash */
633 lyb_read(&hash[0], sizeof *hash, lybctx);
634
635 if (!hash[0]) {
636 /* opaque node */
637 return LY_SUCCESS;
638 }
639
640 /* based on the first hash read all the other ones, if any */
641 for (i = 0; !(hash[0] & (LYB_HASH_COLLISION_ID >> i)); ++i) {
642 if (i > LYB_HASH_BITS) {
643 LOGINT_RET(lybctx->ctx);
644 }
645 }
646
647 /* move the first hash on its accurate position */
648 hash[i] = hash[0];
649
650 /* read the rest of hashes */
651 for (j = i; j; --j) {
652 lyb_read(&hash[j - 1], sizeof *hash, lybctx);
653
654 /* correct collision ID */
655 assert(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)));
656 /* preceded with zeros */
657 assert(!(hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))));
658 }
659
660 /* find our node with matching hashes */
661 sibling = NULL;
662 while ((sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts))) {
663 /* skip schema nodes from models not present during printing */
664 if (lyb_has_schema_model(sibling, lybctx->models)
665 && lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, i + 1)) {
666 /* match found */
667 break;
668 }
669 }
670
Radek Krejci7931b192020-06-25 17:05:03 +0200671 if (!sibling && (lybctx->parse_options & LYD_PARSE_STRICT)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200672 if (mod) {
673 LOGVAL(lybctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
674 " from \"%s\".", mod->name);
675 } else {
676 LOGVAL(lybctx->ctx, LY_VLOG_LYSC, sparent, LYVE_REFERENCE, "Failed to find matching hash for a child node"
677 " of \"%s\".", sparent->name);
678 }
679 return LY_EVALID;
680 } else if (sibling && (ret = lyb_parse_check_schema(lybctx, sibling))) {
681 return ret;
682 }
683
684 *snode = sibling;
685 return LY_SUCCESS;
686}
687
688/**
689 * @brief Read until the end of the current subtree.
690 *
691 * @param[in] lybctx LYB context.
692 */
693static void
694lyb_skip_subtree(struct lyd_lyb_ctx *lybctx)
695{
696 int parsed;
697
698 do {
699 /* first skip any meta information inside */
700 parsed = LYB_LAST_SUBTREE(lybctx).inner_chunks * LYB_META_BYTES;
701 lybctx->data += parsed;
702 lybctx->byte_count += parsed;
703
704 /* then read data */
705 lyb_read(NULL, LYB_LAST_SUBTREE(lybctx).written, lybctx);
706 } while (LYB_LAST_SUBTREE(lybctx).written);
707}
708
709/**
710 * @brief Parse LYB subtree.
711 *
712 * @param[in] lybctx LYB context.
713 * @param[in] parent Data parent of the subtree, must be set if @p first is not.
714 * @param[in,out] first First top-level sibling, must be set if @p parent is not.
715 * @return LY_ERR value.
716 */
717static LY_ERR
718lyb_parse_subtree_r(struct lyd_lyb_ctx *lybctx, struct lyd_node_inner *parent, struct lyd_node **first)
719{
720 LY_ERR ret = LY_SUCCESS;
721 struct lyd_node *node = NULL, *tree;
722 const struct lys_module *mod;
723 const struct lysc_node *snode = NULL;
724 struct lyd_meta *meta = NULL, *m;
725 struct ly_attr *attr = NULL, *a;
726 struct ly_prefix *val_prefs = NULL;
727 LYD_ANYDATA_VALUETYPE value_type;
728 char *value = NULL, *name = NULL, *prefix = NULL, *ns = NULL;
729 int dynamic = 0;
730 LYD_FORMAT format = 0;
731 int prev_lo;
732
733 /* register a new subtree */
734 LY_CHECK_GOTO(ret = lyb_read_start_subtree(lybctx), cleanup);
735
736 if (!parent) {
737 /* top-level, read module name */
738 ret = lyb_parse_model(lybctx, &mod);
739 LY_CHECK_GOTO(ret, cleanup);
740
741 /* read hash, find the schema node starting from mod */
742 ret = lyb_parse_schema_hash(lybctx, NULL, mod, &snode);
743 LY_CHECK_GOTO(ret, cleanup);
744 } else {
745 /* read hash, find the schema node starting from parent schema */
746 ret = lyb_parse_schema_hash(lybctx, parent->schema, NULL, &snode);
747 LY_CHECK_GOTO(ret, cleanup);
748 }
749
Radek Krejci7931b192020-06-25 17:05:03 +0200750 if (!snode && !(lybctx->parse_options & LYD_PARSE_OPAQ)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200751 /* unknown data, skip them */
752 lyb_skip_subtree(lybctx);
753 goto stop_subtree;
754 }
755
756 /* create metadata/attributes */
757 if (snode) {
758 ret = lyb_parse_metadata(lybctx, snode, &meta);
759 LY_CHECK_GOTO(ret, cleanup);
760 } else {
761 ret = lyb_parse_attributes(lybctx, &attr);
762 LY_CHECK_GOTO(ret, cleanup);
763 }
764
765 if (!snode) {
766 /* parse prefix */
767 ret = lyb_read_string(&prefix, 1, lybctx);
768 LY_CHECK_GOTO(ret, cleanup);
769
770 /* parse namespace */
771 ret = lyb_read_string(&ns, 1, lybctx);
772 LY_CHECK_GOTO(ret, cleanup);
773
774 /* parse name */
775 ret = lyb_read_string(&name, 1, lybctx);
776 LY_CHECK_GOTO(ret, cleanup);
777
778 /* parse value prefixes */
779 ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
780 LY_CHECK_GOTO(ret, cleanup);
781
782 /* parse format */
783 lyb_read((uint8_t *)&format, 1, lybctx);
784
785 /* parse value */
786 ret = lyb_read_string(&value, 0, lybctx);
787 LY_CHECK_GOTO(ret, cleanup);
788 dynamic = 1;
789
790 /* create node */
791 ret = lyd_create_opaq(lybctx->ctx, name, strlen(name), value, strlen(value), &dynamic, format, val_prefs, prefix,
792 strlen(prefix), ns, &node);
793 LY_CHECK_GOTO(ret, cleanup);
794
795 /* process children */
796 while (LYB_LAST_SUBTREE(lybctx).written) {
797 ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
798 LY_CHECK_GOTO(ret, cleanup);
799 }
800 } else if (snode->nodetype & LYD_NODE_TERM) {
801 /* parse value */
802 ret = lyb_read_string(&value, 0, lybctx);
803 LY_CHECK_GOTO(ret, cleanup);
804 dynamic = 1;
805
806 /* create node */
807 ret = lyd_create_term(snode, value, strlen(value), &dynamic, lydjson_resolve_prefix, NULL, LYD_JSON, &node);
808 if (dynamic) {
809 free(value);
810 dynamic = 0;
811 }
812 value = NULL;
813 if (ret == LY_EINCOMPLETE) {
Radek Krejci7931b192020-06-25 17:05:03 +0200814 if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200815 ly_set_add(&lybctx->unres_node_type, node, LY_SET_OPT_USEASLIST);
816 }
817 ret = LY_SUCCESS;
818 } else if (ret) {
819 goto cleanup;
820 }
821 } else if (snode->nodetype & LYD_NODE_INNER) {
822 /* create node */
823 ret = lyd_create_inner(snode, &node);
824 LY_CHECK_GOTO(ret, cleanup);
825
826 /* process children */
827 while (LYB_LAST_SUBTREE(lybctx).written) {
828 ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
829 LY_CHECK_GOTO(ret, cleanup);
830 }
831
Radek Krejci7931b192020-06-25 17:05:03 +0200832 if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200833 /* new node validation, autodelete CANNOT occur, all nodes are new */
834 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL);
835 LY_CHECK_GOTO(ret, cleanup);
836
837 /* add any missing default children */
838 ret = lyd_validate_defaults_r((struct lyd_node_inner *)node, lyd_node_children_p(node), NULL, NULL,
Radek Krejci7931b192020-06-25 17:05:03 +0200839 &lybctx->unres_node_type, &lybctx->when_check, lybctx->validate_options);
Michal Vasko60ea6352020-06-29 13:39:39 +0200840 LY_CHECK_GOTO(ret, cleanup);
841 }
842
843 if (snode->nodetype == LYS_LIST) {
844 /* hash now that all keys should be parsed, rehash for key-less list */
845 lyd_hash(node);
846 } else if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
847 /* rememeber the RPC/action/notification */
848 lybctx->op_ntf = node;
849 }
850 } else if (snode->nodetype & LYD_NODE_ANY) {
851 /* parse value type */
852 lyb_read((uint8_t *)&value_type, sizeof value_type, lybctx);
853 if (value_type == LYD_ANYDATA_DATATREE) {
854 /* invalid situation */
855 LOGINT(lybctx->ctx);
856 goto cleanup;
857 }
858
859 /* read anydata content */
860 ret = lyb_read_string(&value, 0, lybctx);
861 LY_CHECK_GOTO(ret, cleanup);
862 dynamic = 1;
863
864 if (value_type == LYD_ANYDATA_LYB) {
865 /* turn logging off */
866 prev_lo = ly_log_options(0);
867
868 /* try to parse LYB into a data tree */
Radek Krejci7931b192020-06-25 17:05:03 +0200869 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 +0200870 /* successfully parsed */
871 free(value);
872 value = (char *)tree;
873 value_type = LYD_ANYDATA_DATATREE;
874 }
Radek Krejci7931b192020-06-25 17:05:03 +0200875
876 /* turn logging on again */
877 ly_log_options(prev_lo);
Michal Vasko60ea6352020-06-29 13:39:39 +0200878 }
879
880 /* create node */
881 ret = lyd_create_any(snode, value, value_type, &node);
882 LY_CHECK_GOTO(ret, cleanup);
883
884 dynamic = 0;
885 value = NULL;
886 }
887 assert(node);
888
889 /* add/correct flags */
890 if (snode) {
Radek Krejci7931b192020-06-25 17:05:03 +0200891 lyd_parse_set_data_flags(node, &lybctx->when_check, &meta, lybctx->parse_options);
Michal Vasko60ea6352020-06-29 13:39:39 +0200892 }
893
894 /* add metadata/attributes */
895 if (snode) {
896 LY_LIST_FOR(meta, m) {
897 m->parent = node;
898 }
899 node->meta = meta;
900 meta = NULL;
901 } else {
902 assert(!node->schema);
903 LY_LIST_FOR(attr, a) {
904 a->parent = (struct lyd_node_opaq *)node;
905 }
906 ((struct lyd_node_opaq *)node)->attr = attr;
907 attr = NULL;
908 }
909
910 /* insert */
911 lyd_insert_node((struct lyd_node *)parent, first, node);
912 node = NULL;
913
914stop_subtree:
915 /* end the subtree */
916 ret = lyb_read_stop_subtree(lybctx);
917 LY_CHECK_GOTO(ret, cleanup);
918
919cleanup:
920 free(prefix);
921 free(ns);
922 free(name);
923 if (dynamic) {
924 free(value);
925 }
926 ly_free_val_prefs(lybctx->ctx, val_prefs);
927
928 lyd_free_meta(lybctx->ctx, meta, 1);
929 ly_free_attr(lybctx->ctx, attr, 1);
930 lyd_free_tree(node);
931 return ret;
932}
933
934/**
935 * @brief Parse used YANG data models.
936 *
937 * @param[in] lybctx LYB context.
938 * @return LY_ERR value.
939 */
940static LY_ERR
941lyb_parse_data_models(struct lyd_lyb_ctx *lybctx)
942{
943 LY_ERR ret;
944 uint32_t count;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200945 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200946
947 /* read model count */
948 lyb_read_number(&count, sizeof count, 2, lybctx);
949
950 if (count) {
951 LY_ARRAY_CREATE_RET(lybctx->ctx, lybctx->models, count, LY_EMEM);
952
953 /* read modules */
954 for (u = 0; u < count; ++u) {
955 ret = lyb_parse_model(lybctx, &lybctx->models[u]);
956 LY_CHECK_RET(ret);
957 LY_ARRAY_INCREMENT(lybctx->models);
958 }
959 }
960
961 return LY_SUCCESS;
962}
963
964/**
965 * @brief Parse LYB magic number.
966 *
967 * @param[in] lybctx LYB context.
968 * @return LY_ERR value.
969 */
970static LY_ERR
971lyb_parse_magic_number(struct lyd_lyb_ctx *lybctx)
972{
973 char magic_byte = 0;
974
975 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
976 if (magic_byte != 'l') {
977 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid first magic number byte \"0x%02x\".", magic_byte);
978 return LY_EINVAL;
979 }
980
981 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
982 if (magic_byte != 'y') {
983 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid second magic number byte \"0x%02x\".", magic_byte);
984 return LY_EINVAL;
985 }
986
987 lyb_read((uint8_t *)&magic_byte, 1, lybctx);
988 if (magic_byte != 'b') {
989 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid third magic number byte \"0x%02x\".", magic_byte);
990 return LY_EINVAL;
991 }
992
993 return LY_SUCCESS;
994}
995
996/**
997 * @brief Parse LYB header.
998 *
999 * @param[in] lybctx LYB context.
1000 * @return LY_ERR value.
1001 */
1002static LY_ERR
1003lyb_parse_header(struct lyd_lyb_ctx *lybctx)
1004{
1005 uint8_t byte = 0;
1006
1007 /* version, future flags */
1008 lyb_read((uint8_t *)&byte, sizeof byte, lybctx);
1009
1010 if ((byte & LYB_VERSION_MASK) != LYB_VERSION_NUM) {
1011 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid LYB format version \"0x%02x\", expected \"0x%02x\".",
1012 byte & LYB_VERSION_MASK, LYB_VERSION_NUM);
1013 return LY_EINVAL;
1014 }
1015
1016 return LY_SUCCESS;
1017}
1018
1019LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001020lyd_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 +02001021{
1022 LY_ERR ret = LY_SUCCESS;
1023 struct lyd_lyb_ctx lybctx = {0};
1024
Radek Krejci7931b192020-06-25 17:05:03 +02001025 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
1026 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
1027
Michal Vasko60ea6352020-06-29 13:39:39 +02001028 *tree = NULL;
1029
1030 lybctx.data = data;
1031 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001032 lybctx.parse_options = parse_options;
1033 lybctx.validate_options = validate_options;
Michal Vasko60ea6352020-06-29 13:39:39 +02001034
1035 /* read magic number */
1036 ret = lyb_parse_magic_number(&lybctx);
1037 LY_CHECK_GOTO(ret, cleanup);
1038
1039 /* read header */
1040 ret = lyb_parse_header(&lybctx);
1041 LY_CHECK_GOTO(ret, cleanup);
1042
1043 /* read used models */
1044 ret = lyb_parse_data_models(&lybctx);
1045 LY_CHECK_GOTO(ret, cleanup);
1046
1047 /* read subtree(s) */
1048 while (lybctx.data[0]) {
1049 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1050 LY_CHECK_GOTO(ret, cleanup);
1051 }
1052
1053 /* read the last zero, parsing finished */
1054 ++lybctx.byte_count;
1055 ++lybctx.data;
1056
1057 /* TODO validation */
1058
1059cleanup:
1060 LY_ARRAY_FREE(lybctx.subtrees);
1061 LY_ARRAY_FREE(lybctx.models);
1062 ly_set_erase(&lybctx.unres_node_type, NULL);
1063 ly_set_erase(&lybctx.unres_meta_type, NULL);
1064 ly_set_erase(&lybctx.when_check, NULL);
1065
1066 if (parsed_bytes) {
1067 *parsed_bytes = lybctx.byte_count;
1068 }
1069 if (ret) {
1070 lyd_free_all(*tree);
1071 *tree = NULL;
1072 }
1073 return ret;
1074}
1075
1076LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001077lyd_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 +02001078{
1079 LY_ERR ret = LY_SUCCESS;
1080 struct lyd_lyb_ctx lybctx = {0};
1081
1082 lybctx.data = data;
1083 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001084 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001085 lybctx.int_opts = LYD_INTOPT_RPC;
1086
1087 *tree = NULL;
1088 if (op) {
1089 *op = NULL;
1090 }
1091
1092 /* read magic number */
1093 ret = lyb_parse_magic_number(&lybctx);
1094 LY_CHECK_GOTO(ret, cleanup);
1095
1096 /* read header */
1097 ret = lyb_parse_header(&lybctx);
1098 LY_CHECK_GOTO(ret, cleanup);
1099
1100 /* read used models */
1101 ret = lyb_parse_data_models(&lybctx);
1102 LY_CHECK_GOTO(ret, cleanup);
1103
1104 /* read subtree(s) */
1105 while (lybctx.data[0]) {
1106 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1107 LY_CHECK_GOTO(ret, cleanup);
1108 }
1109
1110 /* read the last zero, parsing finished */
1111 ++lybctx.byte_count;
1112 ++lybctx.data;
1113
1114 /* make sure we have parsed some operation */
1115 if (!lybctx.op_ntf) {
1116 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
1117 ret = LY_EVALID;
1118 goto cleanup;
1119 }
1120
1121 if (op) {
1122 *op = lybctx.op_ntf;
1123 }
1124 assert(*tree);
1125
1126cleanup:
1127 LY_ARRAY_FREE(lybctx.subtrees);
1128 LY_ARRAY_FREE(lybctx.models);
1129 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1130
1131 if (parsed_bytes) {
1132 *parsed_bytes = lybctx.byte_count;
1133 }
1134 if (ret) {
1135 lyd_free_all(*tree);
1136 *tree = NULL;
1137 }
1138 return ret;
1139}
1140
1141LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001142lyd_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 +02001143{
1144 LY_ERR ret = LY_SUCCESS;
1145 struct lyd_lyb_ctx lybctx = {0};
1146
1147 lybctx.data = data;
1148 lybctx.ctx = ctx;
Radek Krejci7931b192020-06-25 17:05:03 +02001149 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001150 lybctx.int_opts = LYD_INTOPT_NOTIF;
1151
1152 *tree = NULL;
1153 if (ntf) {
1154 *ntf = NULL;
1155 }
1156
1157 /* read magic number */
1158 ret = lyb_parse_magic_number(&lybctx);
1159 LY_CHECK_GOTO(ret, cleanup);
1160
1161 /* read header */
1162 ret = lyb_parse_header(&lybctx);
1163 LY_CHECK_GOTO(ret, cleanup);
1164
1165 /* read used models */
1166 ret = lyb_parse_data_models(&lybctx);
1167 LY_CHECK_GOTO(ret, cleanup);
1168
1169 /* read subtree(s) */
1170 while (lybctx.data[0]) {
1171 ret = lyb_parse_subtree_r(&lybctx, NULL, tree);
1172 LY_CHECK_GOTO(ret, cleanup);
1173 }
1174
1175 /* read the last zero, parsing finished */
1176 ++lybctx.byte_count;
1177 ++lybctx.data;
1178
1179 /* make sure we have parsed some notification */
1180 if (!lybctx.op_ntf) {
1181 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1182 ret = LY_EVALID;
1183 goto cleanup;
1184 }
1185
1186 if (ntf) {
1187 *ntf = lybctx.op_ntf;
1188 }
1189 assert(*tree);
1190
1191cleanup:
1192 LY_ARRAY_FREE(lybctx.subtrees);
1193 LY_ARRAY_FREE(lybctx.models);
1194 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1195
1196 if (parsed_bytes) {
1197 *parsed_bytes = lybctx.byte_count;
1198 }
1199 if (ret) {
1200 lyd_free_all(*tree);
1201 *tree = NULL;
1202 }
1203 return ret;
1204}
1205
1206LY_ERR
Radek Krejci7931b192020-06-25 17:05:03 +02001207lyd_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 +02001208 int *parsed_bytes)
1209{
1210 LY_ERR ret = LY_SUCCESS;
1211 struct lyd_lyb_ctx lybctx = {0};
1212 struct lyd_node *iter, *req_op, *rep_op = NULL;
1213
1214 lybctx.data = data;
1215 lybctx.ctx = LYD_NODE_CTX(request);
Radek Krejci7931b192020-06-25 17:05:03 +02001216 lybctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko60ea6352020-06-29 13:39:39 +02001217 lybctx.int_opts = LYD_INTOPT_REPLY;
1218
1219 *tree = NULL;
1220 if (op) {
1221 *op = NULL;
1222 }
1223
1224 /* find request OP */
1225 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, iter, req_op) {
1226 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1227 break;
1228 }
1229 LYD_TREE_DFS_END(request, iter, req_op);
1230 }
1231 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1232 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1233 ret = LY_EINVAL;
1234 goto cleanup;
1235 }
1236
1237 /* duplicate request OP with parents */
1238 rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
1239 LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
1240
1241 /* read magic number */
1242 ret = lyb_parse_magic_number(&lybctx);
1243 LY_CHECK_GOTO(ret, cleanup);
1244
1245 /* read header */
1246 ret = lyb_parse_header(&lybctx);
1247 LY_CHECK_GOTO(ret, cleanup);
1248
1249 /* read used models */
1250 ret = lyb_parse_data_models(&lybctx);
1251 LY_CHECK_GOTO(ret, cleanup);
1252
1253 /* read subtree(s) */
1254 while (lybctx.data[0]) {
1255 ret = lyb_parse_subtree_r(&lybctx, (struct lyd_node_inner *)rep_op, NULL);
1256 LY_CHECK_GOTO(ret, cleanup);
1257 }
1258
1259 /* read the last zero, parsing finished */
1260 ++lybctx.byte_count;
1261 ++lybctx.data;
1262
1263 if (op) {
1264 *op = rep_op;
1265 }
1266 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
1267 *tree = iter;
1268 rep_op = NULL;
1269
1270cleanup:
1271 lyd_free_all(rep_op);
1272 LY_ARRAY_FREE(lybctx.subtrees);
1273 LY_ARRAY_FREE(lybctx.models);
1274 assert(!lybctx.unres_node_type.count && !lybctx.unres_meta_type.count && !lybctx.when_check.count);
1275
1276 if (parsed_bytes) {
1277 *parsed_bytes = lybctx.byte_count;
1278 }
1279 if (ret) {
1280 lyd_free_all(*tree);
1281 *tree = NULL;
1282 }
1283 return ret;
1284}
1285
1286API int
1287lyd_lyb_data_length(const char *data)
1288{
1289 LY_ERR ret = LY_SUCCESS;
1290 struct lyd_lyb_ctx lybctx = {0};
1291 int count, i;
1292 size_t len;
1293 uint8_t buf[LYB_SIZE_MAX];
1294
1295 if (!data) {
1296 return -1;
1297 }
1298
1299 lybctx.data = data;
1300
1301 /* read magic number */
1302 ret = lyb_parse_magic_number(&lybctx);
1303 LY_CHECK_GOTO(ret, cleanup);
1304
1305 /* read header */
1306 ret = lyb_parse_header(&lybctx);
1307 LY_CHECK_GOTO(ret, cleanup);
1308
1309 /* read model count */
1310 lyb_read_number(&count, sizeof count, 2, &lybctx);
1311
1312 /* read all models */
1313 for (i = 0; i < count; ++i) {
1314 /* module name length */
1315 len = 0;
1316 lyb_read_number(&len, sizeof len, 2, &lybctx);
1317
1318 /* model name */
1319 lyb_read(buf, len, &lybctx);
1320
1321 /* revision */
1322 lyb_read(buf, 2, &lybctx);
1323 }
1324
1325 while (lybctx.data[0]) {
1326 /* register a new subtree */
1327 ret = lyb_read_start_subtree(&lybctx);
1328 LY_CHECK_GOTO(ret, cleanup);
1329
1330 /* skip it */
1331 lyb_skip_subtree(&lybctx);
1332
1333 /* subtree finished */
1334 ret = lyb_read_stop_subtree(&lybctx);
1335 LY_CHECK_GOTO(ret, cleanup);
1336 }
1337
1338 /* read the last zero, parsing finished */
1339 ++lybctx.byte_count;
1340 ++lybctx.data;
1341
1342cleanup:
1343 LY_ARRAY_FREE(lybctx.subtrees);
1344 return ret ? -1 : (signed)lybctx.byte_count;
1345}