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