libyang 6.4.13
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
Loading...
Searching...
No Matches
union.c
Go to the documentation of this file.
1
15
16#define _GNU_SOURCE /* strdup */
17
18#include "plugins_types.h"
19
20#include <assert.h>
21#include <inttypes.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "compat.h"
26#include "dict.h"
27#include "ly_array.h"
28#include "ly_common.h"
29#include "lyb.h"
30#include "plugins_internal.h"
31
43
44static void lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value);
45
49#define LYPLG_UNION_TYPE_IDX_SIZE 1
50
60static LY_ERR
61union_validate_value_lyb(const void *lyb_data, uint64_t lyb_data_size_bits, const struct lysc_type_union *type_u,
62 struct ly_err_item **err)
63{
64 uint32_t type_idx = 0;
65
66 /* basic validation */
67 if (lyb_data_size_bits < LYPLG_UNION_TYPE_IDX_SIZE * 8) {
68 return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB union value size %" PRIu64
69 " b (expected at least %" PRIu8 " b).", lyb_data_size_bits, LYPLG_UNION_TYPE_IDX_SIZE * 8);
70 }
71
72 /* get index in correct byte order */
73 memcpy(&type_idx, lyb_data, LYPLG_UNION_TYPE_IDX_SIZE);
74 type_idx = le32toh(type_idx);
75 if (type_idx >= LYA_COUNT(type_u->types)) {
76 return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
77 "Invalid LYB union type index %" PRIu32 " (type count %" LYA_PRI_COUNT_T ").",
78 type_idx, LYA_COUNT(type_u->types));
79 }
80
81 return LY_SUCCESS;
82}
83
94static void
95union_parse_value_lyb(const void *lyb_data, uint64_t lyb_data_size_bits, uint32_t *type_idx, const void **lyb_value,
96 uint64_t *lyb_value_size_bits)
97{
98 uint32_t num = 0;
99
100 assert(lyb_data);
101
102 if (type_idx) {
103 memcpy(&num, lyb_data, LYPLG_UNION_TYPE_IDX_SIZE);
104 num = le32toh(num);
105
106 *type_idx = num;
107 }
108
109 if (lyb_value && lyb_value_size_bits && lyb_data_size_bits) {
110 /* get lyb_value and its size */
111 if (lyb_data_size_bits == LYPLG_UNION_TYPE_IDX_SIZE * 8) {
112 *lyb_value_size_bits = 0;
113 *lyb_value = "";
114 } else {
115 *lyb_value_size_bits = lyb_data_size_bits - LYPLG_UNION_TYPE_IDX_SIZE * 8;
116 *lyb_value = (char *)lyb_data + LYPLG_UNION_TYPE_IDX_SIZE;
117 }
118 }
119}
120
133static LY_ERR
134union_create_value_lyb(const struct ly_ctx *ctx, uint32_t type_idx, const struct lyd_value *value, void **lyb_value,
135 uint64_t *lyb_size_bits, struct ly_err_item **err)
136{
137 LY_ERR rc = LY_SUCCESS;
138 void *lyb = NULL;
139 const void *pval = NULL;
140 uint64_t pval_size_bits, lyb_bits = 0;
141 uint32_t num;
142 ly_bool dynamic = 0;
143
144 *err = NULL;
145
146 /* print the value in LYB format */
147 pval = LYSC_GET_TYPE_PLG(value->realtype->plugin_ref)->print(ctx, value, LY_VALUE_LYB, NULL, &dynamic, &pval_size_bits);
148 if (!pval) {
149 rc = ly_err_new_no_mem(err);
150 goto cleanup;
151 }
152
153 /* create the binary data of the pinned member type index followed by its binary value
154 * (the size may not be an exact number of bytes, e.g. for integers) */
155 lyb_bits = LYPLG_UNION_TYPE_IDX_SIZE * 8 + pval_size_bits;
156 lyb = malloc(LYPLG_BITS2BYTES(lyb_bits));
157 if (!lyb) {
158 lyb_bits = 0;
159 rc = ly_err_new_no_mem(err);
160 goto cleanup;
161 }
162
163 num = htole32(type_idx);
164 memcpy(lyb, &num, LYPLG_UNION_TYPE_IDX_SIZE);
165 memcpy((char *)lyb + LYPLG_UNION_TYPE_IDX_SIZE, pval, LYPLG_BITS2BYTES(pval_size_bits));
166
167cleanup:
168 if (dynamic) {
169 free((void *)pval);
170 }
171 *lyb_value = lyb;
172 if (lyb_size_bits) {
173 *lyb_size_bits = lyb_bits;
174 }
175 return rc;
176}
177
189static LY_ERR
190union_update_lref_err(struct ly_err_item *err, const struct lysc_type *type, const void *value, uint64_t value_size_bits)
191{
192 const struct lysc_type_leafref *lref;
193 char *valstr = NULL;
194 int r;
195
196 if (!err || (type->basetype != LY_TYPE_LEAFREF)) {
197 /* nothing to do */
198 return LY_SUCCESS;
199 }
200
201 lref = (const struct lysc_type_leafref *)type;
202
203 /* update error-app-tag */
204 free(err->apptag);
205 err->apptag = strdup("instance-required");
206 LY_CHECK_ERR_RET(!err->apptag, LOGMEM(NULL), LY_EMEM);
207
208 valstr = strndup((const char *)value, value_size_bits / 8);
209 LY_CHECK_ERR_RET(!valstr, LOGMEM(NULL), LY_EMEM);
210
211 /* update error-message */
212 free(err->msg);
213 r = asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path));
214 free(valstr);
215 LY_CHECK_ERR_RET(r == -1, LOGMEM(NULL), LY_EMEM);
216
217 return LY_SUCCESS;
218}
219
237static LY_ERR
238union_subvalue_get_input_value(const struct ly_ctx *ctx, const struct lysc_type_union *type_u, uint32_t type_idx,
239 const struct lyd_value_union *subvalue, const void **value, uint64_t *value_size_bits, ly_bool *dynamic,
240 LY_VALUE_FORMAT *format, void **prefix_data, struct ly_err_item **err)
241{
242 LY_ERR rc = LY_SUCCESS;
243 struct lyd_value storage = {0};
244 uint32_t ti;
245 struct lyplg_type *type_plg;
246
247 *value = NULL;
248 *value_size_bits = 0;
249 *dynamic = 0;
250 *format = 0;
251 *prefix_data = NULL;
252 *err = NULL;
253
254 if (subvalue->format == LY_VALUE_LYB) {
255 union_parse_value_lyb(subvalue->original, subvalue->orig_size_bits, &ti, value, value_size_bits);
256 if (ti != type_idx) {
257 /* value of another type, store the value */
258 type_plg = LYSC_GET_TYPE_PLG(type_u->types[ti]->plugin_ref);
259 rc = type_plg->store(ctx, type_u->types[ti], *value, *value_size_bits, LYPLG_TYPE_STORE_ONLY,
260 subvalue->format, subvalue->prefix_data, subvalue->hints, subvalue->ctx_node, &storage, NULL, err);
261 if (rc && (rc != LY_EINCOMPLETE)) {
262 /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
263 union_update_lref_err(*err, type_u->types[ti], *value, *value_size_bits);
264 goto cleanup;
265 }
266
267 /* print the value in canonical format */
268 assert(storage.realtype);
269 *value = LYSC_GET_TYPE_PLG(storage.realtype->plugin_ref)->print(ctx, &storage, LY_VALUE_CANON, NULL, dynamic,
270 value_size_bits);
271 assert(!(*value_size_bits % 8));
272
273 /* free storage, but we need the value, which may be stored there */
274 if (!*dynamic) {
275 *value = strndup(*value, *value_size_bits / 8);
276 *dynamic = 1;
277 }
278 type_plg->free(ctx, &storage);
279
280 *format = LY_VALUE_CANON;
281 *prefix_data = NULL;
282 } else {
283 *format = subvalue->format;
284 *prefix_data = subvalue->prefix_data;
285 }
286 } else {
287 *value = subvalue->original;
288 *value_size_bits = subvalue->orig_size_bits;
289 *format = subvalue->format;
290 *prefix_data = subvalue->prefix_data;
291 }
292
293cleanup:
294 return rc;
295}
296
318static LY_ERR
319union_store_type(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
320 uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_snode,
321 const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage,
322 struct lys_glob_unres *unres, struct ly_err_item **err)
323{
324 LY_ERR rc = LY_SUCCESS;
325 struct lyplg_type *type_plg;
326 ly_bool dynamic = 0;
327
328 *err = NULL;
329
330 type_plg = LYSC_GET_TYPE_PLG(type->plugin_ref);
331
332 /* do not free the value (yet) */
333 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
334 options &= ~LYPLG_TYPE_STORE_DYNAMIC;
335 dynamic = 1;
336 }
337
338 rc = type_plg->store(ctx, type, value, value_size_bits, options, format, prefix_data, hints, ctx_snode, storage,
339 unres, err);
340 if (rc && (rc != LY_EINCOMPLETE)) {
341 /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
342 union_update_lref_err(*err, type, value, value_size_bits);
343 goto cleanup;
344 }
345
346 if (tree && type_plg->validate_tree) {
347 /* we need the value validated in the data tree */
348 rc = type_plg->validate_tree(ctx, type, ctx_node, tree, storage, err);
349 if (rc) {
350 /* validate failed, we need to free the stored value */
351 type_plg->free(ctx, storage);
352 goto cleanup;
353 }
354 }
355
356cleanup:
357 if (dynamic) {
358 free((void *)value);
359 }
360 if (rc && (rc != LY_EINCOMPLETE)) {
361 /* clear any leftover/freed garbage */
362 memset(storage, 0, sizeof *storage);
363 }
364 return rc;
365}
366
383static LY_ERR
384union_read_store_type(const struct ly_ctx *ctx, const struct lysc_type_union *type_u, uint32_t type_idx,
385 struct lyd_value_union *subvalue, uint32_t options, const struct lyd_node *ctx_node,
386 const struct lyd_node *tree, struct lys_glob_unres *unres, struct ly_err_item **err)
387{
388 LY_ERR rc = LY_SUCCESS, r;
389 const void *value;
390 uint64_t value_size_bits;
391 ly_bool dynamic;
392 LY_VALUE_FORMAT format;
393 void *prefix_data;
394
395 /* get the input value in a suitable format from the original value */
396 r = union_subvalue_get_input_value(ctx, type_u, type_idx, subvalue, &value, &value_size_bits, &dynamic, &format,
397 &prefix_data, err);
398 if (r && (r != LY_EINCOMPLETE)) {
399 rc = r;
400 goto cleanup;
401 }
402
403 if (dynamic) {
404 options |= LYPLG_TYPE_STORE_DYNAMIC;
405 } else {
406 options &= ~LYPLG_TYPE_STORE_DYNAMIC;
407 }
408
409 /* store the value as the specific type */
410 rc = union_store_type(ctx, type_u->types[type_idx], value, value_size_bits, options, format, prefix_data,
411 subvalue->hints, subvalue->ctx_node, ctx_node, tree, &subvalue->value, unres, err);
412
413cleanup:
414 return rc;
415}
416
431static LY_ERR
432union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
433 uint32_t options, const struct lyd_node *ctx_node, const struct lyd_node *tree, uint32_t *type_idx,
434 struct lys_glob_unres *unres, struct ly_err_item **err)
435{
436 LY_ERR rc = LY_SUCCESS;
437 LYA_COUNT_T u;
438 struct ly_err_item **errs = NULL, *e;
439 uint32_t *prev_lo, temp_lo = 0;
440 char *msg = NULL, *err_app_tag = NULL;
441 int msg_len = 0;
442 ly_bool use_err_app_tag = 0;
443 struct lyplg_type *type_plg;
444
445 *err = NULL;
446
447 /* alloc errors */
448 errs = calloc(LYA_COUNT(type_u->types), sizeof *errs);
449 LY_CHECK_RET(!errs, LY_EMEM);
450
451 /* turn logging temporarily off */
452 prev_lo = ly_temp_log_options(&temp_lo);
453
454 /* use the first usable subtype to store the value */
455 LYA_FOR(type_u->types, u) {
456 rc = union_read_store_type(ctx, type_u, u, subvalue, options, ctx_node, tree, unres, &e);
457 if (!rc || (rc == LY_EINCOMPLETE)) {
458 /* success */
459 break;
460 }
461
462 errs[u] = e;
463 }
464
465 if (u == LYA_COUNT(type_u->types)) {
466 /* create the full error */
467 if (subvalue->format == LY_VALUE_LYB) {
468 msg_len = asprintf(&msg, "Invalid LYB union value - no matching subtype found:\n");
469 } else {
470 msg_len = asprintf(&msg, "Invalid union value \"%.*s\" - no matching subtype found:\n",
471 (int)subvalue->orig_size_bits / 8, (char *)subvalue->original);
472 }
473 if (msg_len == -1) {
474 LY_CHECK_ERR_GOTO(!errs, rc = LY_EMEM, cleanup);
475 /* for further actions in function msg_len is just 0 */
476 msg_len = 0;
477 }
478 LYA_FOR(type_u->types, u) {
479 if (!errs[u]) {
480 /* no error for some reason */
481 continue;
482 }
483
484 /* use an app-tag if all the types set it or set none */
485 if (errs[u]->apptag) {
486 if (!err_app_tag) {
487 err_app_tag = strdup(errs[u]->apptag);
488 LY_CHECK_ERR_GOTO(!err_app_tag, rc = LY_EMEM, cleanup);
489 use_err_app_tag = 1;
490 } else if (strcmp(errs[u]->apptag, err_app_tag)) {
491 use_err_app_tag = 0;
492 }
493 }
494
495 type_plg = LYSC_GET_TYPE_PLG(type_u->types[u]->plugin_ref);
496
497 msg = ly_realloc(msg, msg_len + 4 + strlen(type_plg->id) + 2 + strlen(errs[u]->msg) + 2);
498 LY_CHECK_ERR_GOTO(!msg, rc = LY_EMEM, cleanup);
499 msg_len += sprintf(msg + msg_len, " %s: %s\n", type_plg->id, errs[u]->msg);
500 }
501
502 if (!use_err_app_tag) {
503 free(err_app_tag);
504 err_app_tag = NULL;
505 }
506 rc = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, err_app_tag, "%s", msg);
507 err_app_tag = NULL;
508 } else if (type_idx) {
509 *type_idx = u;
510 }
511
512cleanup:
513 LYA_FOR(type_u->types, u) {
514 ly_err_free(errs[u]);
515 }
516 free(errs);
517 free(msg);
518 free(err_app_tag);
519 ly_temp_log_options(prev_lo);
520 return rc;
521}
522
541static LY_ERR
542union_prepare_subvalue(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
543 uint32_t *options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
544 struct lyd_value *storage, struct lyd_value_union **subvalue, struct ly_err_item **err)
545{
546 *err = NULL;
547
548 /* init storage */
549 memset(storage, 0, sizeof *storage);
550 LYPLG_TYPE_VAL_INLINE_PREPARE(storage, *subvalue);
551 LY_CHECK_RET(!*subvalue, ly_err_new_no_mem(err));
552
553 storage->realtype = type;
554 (*subvalue)->hints = hints;
555 (*subvalue)->ctx_node = ctx_node;
556
557 /* store the caller value as the subvalue original, it is needed for the member type store */
558 if (*options & LYPLG_TYPE_STORE_DYNAMIC) {
559 (*subvalue)->original = (void *)value;
560 *options &= ~LYPLG_TYPE_STORE_DYNAMIC;
561 } else if (value_size_bits) {
562 (*subvalue)->original = calloc(1, LYPLG_BITS2BYTES(value_size_bits));
563 LY_CHECK_RET(!(*subvalue)->original, ly_err_new_no_mem(err));
564 memcpy((*subvalue)->original, value, LYPLG_BITS2BYTES(value_size_bits));
565 } else {
566 (*subvalue)->original = strdup("");
567 LY_CHECK_RET(!(*subvalue)->original, ly_err_new_no_mem(err));
568 }
569 (*subvalue)->orig_size_bits = value_size_bits;
570
571 /* derive format-specific data of the value, needed for the member type store;
572 * the values in the LYB format must have no prefix data stored (see ly_dup_prefix_data()) */
573 return lyplg_type_prefix_data_new(ctx, value, LYPLG_BITS2BYTES(value_size_bits), format,
574 (format == LY_VALUE_LYB) ? NULL : prefix_data, &(*subvalue)->format, &(*subvalue)->prefix_data);
575}
576
577static LY_ERR
578lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
579 uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
580 struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
581{
582 LY_ERR rc = LY_SUCCESS, r;
583 struct lysc_type_union *type_u;
584 struct lyd_value_union *subvalue;
585 uint32_t type_idx = 0;
586
587 *err = NULL;
588
589 type_u = (struct lysc_type_union *)type;
590
591 /* initialize the storage and assign the caller value to the subvalue */
592 rc = union_prepare_subvalue(ctx, type, value, value_size_bits, &options, format, prefix_data, hints,
593 ctx_node, storage, &subvalue, err);
594 LY_CHECK_GOTO(rc, cleanup);
595
596 if (format == LY_VALUE_LYB) {
597 /* the binary value pins the member type to use, validate it and learn its index */
598 rc = union_validate_value_lyb(value, value_size_bits, type_u, err);
599 LY_CHECK_GOTO(rc, cleanup);
600 union_parse_value_lyb(value, 0, &type_idx, NULL, NULL);
601
602 /* use the pinned member type to store the value, its acceptance errors are propagated */
603 rc = union_read_store_type(ctx, type_u, type_idx, subvalue, options, NULL, NULL, unres, err);
604 LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
605 } else {
606 /* use the first usable and valid subtype to store the value */
607 rc = union_find_type(ctx, type_u, subvalue, options & ~LYPLG_TYPE_STORE_ONLY, NULL, NULL, NULL, unres, err);
608 if (rc && (rc != LY_EINCOMPLETE) && (options & LYPLG_TYPE_STORE_ONLY)) {
609 /* we tried to find the actual type by validating the value but no type matched, so try to find any type */
610 ly_err_free(*err);
611 rc = union_find_type(ctx, type_u, subvalue, options, NULL, NULL, NULL, unres, err);
612 }
613 LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
614 }
615
616 /* store canonical value, if any (use the specific type value) */
617 r = lydict_dup(ctx, subvalue->value._canonical, &storage->_canonical);
618 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
619
620cleanup:
621 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
622 free((void *)value);
623 }
624
625 if (rc && (rc != LY_EINCOMPLETE)) {
626 lyplg_type_free_union(ctx, storage);
627 }
628 return rc;
629}
630
631LIBYANG_API_DEF LY_ERR
632lyplg_type_store_union_idx(const struct ly_ctx *ctx, const struct lysc_type *type, uint32_t type_idx,
633 const void *value, uint64_t value_size_bits, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data,
634 uint32_t hints, const struct lysc_node *ctx_node, struct lyd_value *storage, struct ly_err_item **err)
635{
636 LY_ERR rc = LY_SUCCESS, r;
637 struct lysc_type_union *type_u = (struct lysc_type_union *)type;
638 struct lyd_value_union *subvalue;
639 void *lyb;
640 uint64_t lyb_size_bits;
641
642 LY_CHECK_ARG_RET(ctx, ctx, type, type->basetype == LY_TYPE_UNION, type_idx < LYA_COUNT(type_u->types),
643 !(options & LYPLG_TYPE_STORE_IMPLEMENT), storage, err, LY_EINVAL);
644
645 memset(storage, 0, sizeof *storage);
646 *err = NULL;
647
648 LYPLG_TYPE_VAL_INLINE_PREPARE(storage, subvalue);
649 LY_CHECK_ERR_GOTO(!subvalue, rc = LY_EMEM, cleanup);
650
651 /* store the value of the specific type */
652 rc = union_store_type(ctx, type_u->types[type_idx], value, value_size_bits, options & ~LYPLG_TYPE_STORE_DYNAMIC,
653 format, prefix_data, hints, ctx_node, NULL, NULL, &subvalue->value, NULL, err);
654 LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
655
656 /* create the union LYB value with the resolved type index */
657 r = union_create_value_lyb(ctx, type_idx, &subvalue->value, &lyb, &lyb_size_bits, err);
658 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
659
660 /* store it as the original value (hints, while not relevant for the LYB format, may be used by other formats) */
661 subvalue->original = lyb;
662 subvalue->orig_size_bits = lyb_size_bits;
663 subvalue->hints = hints;
664 subvalue->format = LY_VALUE_LYB;
665 subvalue->ctx_node = ctx_node;
666
667 /* store canonical value (use the specific type value) and realtype */
668 r = lydict_dup(ctx, subvalue->value._canonical, &storage->_canonical);
669 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
670 storage->realtype = type;
671
672cleanup:
673 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
674 free((void *)value);
675 }
676
677 if (rc && (rc != LY_EINCOMPLETE)) {
678 lyplg_type_free_union(ctx, storage);
679 memset(storage, 0, sizeof *storage);
680 }
681 return rc;
682}
683
684static LY_ERR
685lyplg_type_validate_tree_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
686 const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
687{
688 LY_ERR rc = LY_SUCCESS;
689 struct lysc_type_union *type_u = (struct lysc_type_union *)type;
690 struct lyd_value_union *subvalue = storage->subvalue;
691 struct lyd_value orig = {0};
692 uint32_t type_idx;
693 ly_bool validated = 0;
694 struct lyplg_type *realtype_plg;
695
696 *err = NULL;
697
698 /* because of types that do not store their own type as realtype (leafref), we are not able to call their
699 * validate callback (there is no way to get the type) but even if possible, the value may be invalid
700 * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
701 realtype_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
702 LY_CHECK_RET(realtype_plg->duplicate(ctx, &subvalue->value, &orig));
703 realtype_plg->free(ctx, &subvalue->value);
704
705 if (subvalue->format == LY_VALUE_LYB) {
706 /* use the specific type to store and validate the value */
707 union_parse_value_lyb(subvalue->original, 0, &type_idx, NULL, NULL);
708
709 if (union_read_store_type(ctx, type_u, type_idx, subvalue, 0, ctx_node, tree, NULL, err)) {
710 /* validation failed, we need to try storing the value again */
711 ly_err_free(*err);
712 *err = NULL;
713 } else {
714 validated = 1;
715 }
716 }
717
718 if (!validated) {
719 /* use the first usable subtype to store and validate the value */
720 rc = union_find_type(ctx, type_u, subvalue, 0, ctx_node, tree, NULL, NULL, err);
721 LY_CHECK_GOTO(rc, cleanup);
722 }
723
724 /* update the canonical value, if any generated */
725 lydict_remove(ctx, storage->_canonical);
726 storage->_canonical = NULL;
727 LY_CHECK_GOTO(rc = lydict_dup(ctx, subvalue->value._canonical, &storage->_canonical), cleanup);
728
729cleanup:
730 if (rc) {
731 /* restore the previous value */
732 subvalue->value = orig;
733 } else {
734 /* free the backup value */
735 LYSC_GET_TYPE_PLG(orig.realtype->plugin_ref)->free(ctx, &orig);
736 }
737 return rc;
738}
739
740static LY_ERR
741lyplg_type_compare_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
742{
743 if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
744 return LY_ENOT;
745 }
746 return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->compare(ctx,
747 &val1->subvalue->value, &val2->subvalue->value);
748}
749
750static int
751lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
752{
753 int rc;
754 LYA_COUNT_T u;
755 struct lysc_type **types, *type;
756
757 if (val1->subvalue->value.realtype == val2->subvalue->value.realtype) {
758 return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->sort(ctx,
759 &val1->subvalue->value, &val2->subvalue->value);
760 }
761
762 /* compare according to the order of types */
763 rc = 0;
764 types = ((struct lysc_type_union *)val1->realtype)->types;
765 LYA_FOR(types, u) {
766 if (types[u]->basetype == LY_TYPE_LEAFREF) {
767 type = ((struct lysc_type_leafref *)types[u])->realtype;
768 } else {
769 type = types[u];
770 }
771
772 if (type == val1->subvalue->value.realtype) {
773 rc = 1;
774 break;
775 } else if (type == val2->subvalue->value.realtype) {
776 rc = -1;
777 break;
778 }
779 }
780 assert(rc);
781
782 return rc;
783}
784
795static const void *
796union_print_value_lyb(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
797 uint64_t *value_size_bits)
798{
799 void *ret = NULL;
800 LY_ERR r;
801 struct ly_err_item *err;
802 uint32_t type_idx = 0;
803 struct lyd_value orig = {0};
804 struct lyplg_type *realtype_plg;
805
806 if (!ctx) {
807 assert(subvalue->ctx_node);
808 ctx = subvalue->ctx_node->module->ctx;
809 }
810
811 /* because of types that do not store their own type as realtype (leafref), we are not able to call their
812 * validate callback (there is no way to get the type) but even if possible, the value may be invalid
813 * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
814 realtype_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
815 LY_CHECK_RET(realtype_plg->duplicate(ctx, &subvalue->value, &orig), NULL);
816 realtype_plg->free(ctx, &subvalue->value);
817
818 /* learn the type index, may fail if LYPLG_TYPE_STORE_ONLY has been used before */
819 r = union_find_type(ctx, type_u, subvalue, 0, NULL, NULL, &type_idx, NULL, &err);
820 ly_err_free(err);
821 if (r && (r != LY_EINCOMPLETE)) {
822 /* use LYPLG_TYPE_STORE_ONLY to manage to print the value */
823 r = union_find_type(ctx, type_u, subvalue, LYPLG_TYPE_STORE_ONLY, NULL, NULL, &type_idx, NULL, &err);
824 ly_err_free(err);
825 }
826 LY_CHECK_ERR_RET(r && (r != LY_EINCOMPLETE), subvalue->value = orig, NULL);
827
828 /* create the LYB data of the resolved member type value */
829 r = union_create_value_lyb(NULL, type_idx, &subvalue->value, &ret, value_size_bits, &err);
830 ly_err_free(err);
831 LY_CHECK_ERR_RET(r, subvalue->value = orig, NULL);
832
833 /* restore backup (original) value */
834 realtype_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
835 realtype_plg->free(ctx, &subvalue->value);
836 subvalue->value = orig;
837 return ret;
838}
839
840static const void *
841lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
842 void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
843{
844 const void *ret;
845 struct lyd_value_union *subvalue = value->subvalue;
846 struct lysc_type_union *type_u = (struct lysc_type_union *)value->realtype;
847 uint64_t lyb_data_size_bits = 0;
848
849 if ((format == LY_VALUE_LYB) && (subvalue->format == LY_VALUE_LYB)) {
850 /* return value is ready */
851 *dynamic = 0;
852 if (value_size_bits) {
853 *value_size_bits = subvalue->orig_size_bits;
854 }
855 return subvalue->original;
856 } else if ((format == LY_VALUE_LYB) && (subvalue->format != LY_VALUE_LYB)) {
857 /* return LYB data value must be created */
858 *dynamic = 1;
859 ret = union_print_value_lyb(ctx, type_u, subvalue, &lyb_data_size_bits);
860 if (value_size_bits) {
861 *value_size_bits = lyb_data_size_bits;
862 }
863 return ret;
864 }
865
866 assert(format != LY_VALUE_LYB);
867 ret = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(ctx, &subvalue->value,
868 format, prefix_data, dynamic, value_size_bits);
869 if (!value->_canonical && (format == LY_VALUE_CANON)) {
870 /* the canonical value is supposed to be stored now */
871 lydict_dup(ctx, subvalue->value._canonical, (const char **)&value->_canonical);
872 }
873
874 return ret;
875}
876
877static LY_ERR
878lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
879{
880 LY_ERR ret = LY_SUCCESS;
881 struct lyd_value_union *orig_val = original->subvalue, *dup_val;
882
883 /* init dup value */
884 memset(dup, 0, sizeof *dup);
885 dup->realtype = original->realtype;
886
887 ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
888 LY_CHECK_GOTO(ret, cleanup);
889
890 dup_val = calloc(1, sizeof *dup_val);
891 LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
892 dup->subvalue = dup_val;
893
894 ret = LYSC_GET_TYPE_PLG(orig_val->value.realtype->plugin_ref)->duplicate(ctx, &orig_val->value, &dup_val->value);
895 LY_CHECK_GOTO(ret, cleanup);
896
897 if (orig_val->orig_size_bits) {
898 dup_val->original = calloc(1, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
899 LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
900 memcpy(dup_val->original, orig_val->original, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
901 } else {
902 dup_val->original = strdup("");
903 LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
904 }
905 dup_val->orig_size_bits = orig_val->orig_size_bits;
906
907 dup_val->format = orig_val->format;
908 dup_val->ctx_node = orig_val->ctx_node;
909 dup_val->hints = orig_val->hints;
910 ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
911 LY_CHECK_GOTO(ret, cleanup);
912
913cleanup:
914 if (ret) {
915 lyplg_type_free_union(ctx, dup);
916 }
917 return ret;
918}
919
920static void
921lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
922{
923 struct lyd_value_union *val;
924
926 value->_canonical = NULL;
927 LYD_VALUE_GET(value, val);
928 if (val) {
929 if (val->value.realtype) {
930 LYSC_GET_TYPE_PLG(val->value.realtype->plugin_ref)->free(ctx, &val->value);
931 }
933 free(val->original);
934
936 }
937}
938
947 {
948 .module = "",
949 .revision = NULL,
950 .name = LY_TYPE_UNION_STR,
951
952 .plugin.id = "ly2 union",
953 .plugin.lyb_size = lyplg_type_lyb_size_variable_bits,
954 .plugin.store = lyplg_type_store_union,
955 .plugin.validate_value = NULL,
956 .plugin.validate_tree = lyplg_type_validate_tree_union,
957 .plugin.compare = lyplg_type_compare_union,
958 .plugin.sort = lyplg_type_sort_union,
959 .plugin.print = lyplg_type_print_union,
960 .plugin.duplicate = lyplg_type_dup_union,
961 .plugin.free = lyplg_type_free_union,
962 },
963 {0}
964};
libyang dictionary
#define LYA_PRI_COUNT_T
Printing format specifier macro for LYA_COUNT_T values.
Definition ly_array.h:43
#define LYA_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition ly_array.h:78
#define LYA_FOR(ARRAY, INDEX)
Helper macro to go through sized-arrays with a numeric iterator.
Definition ly_array.h:55
#define LYA_COUNT_T
Type (i.e. size) of the sized array's size counter.
Definition ly_array.h:38
libyang context handler.
LIBYANG_API_DECL LY_ERR lydict_dup(const struct ly_ctx *ctx, const char *value, const char **str_p)
Duplicate string in dictionary. Only a reference counter is incremented.
LIBYANG_API_DECL LY_ERR lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len, const char **str_p)
Insert string into dictionary. If the string is already present, only a reference counter is incremen...
LIBYANG_API_DECL LY_ERR lydict_remove(const struct ly_ctx *ctx, const char *value)
Remove specified string from the dictionary. It decrement reference counter for the string and if it ...
LY_ERR err
Definition log.h:300
char * apptag
Definition log.h:306
char * msg
Definition log.h:302
LY_ERR
libyang's error codes returned by the libyang functions.
Definition log.h:252
@ LYVE_DATA
Definition log.h:290
@ LY_EINVAL
Definition log.h:256
@ LY_EMEM
Definition log.h:254
@ LY_ENOT
Definition log.h:266
@ LY_EVALID
Definition log.h:260
@ LY_SUCCESS
Definition log.h:253
@ LY_EINCOMPLETE
Definition log.h:262
Libyang full error structure.
Definition log.h:298
LIBYANG_API_DECL uint32_t * ly_temp_log_options(uint32_t *opts)
Set temporary thread-safe (thread-specific) logger options overwriting those set by ly_log_options().
lyplg_type_store_clb store
const char * id
lyplg_type_dup_clb duplicate
lyplg_type_validate_tree_clb validate_tree
lyplg_type_free_clb free
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
LIBYANG_API_DECL void ly_err_free(void *ptr)
Destructor for the error records created with ly_err_new().
LIBYANG_API_DEF LY_ERR lyplg_type_store_union_idx(const struct ly_ctx *ctx, const struct lysc_type *type, uint32_t type_idx, const void *value, uint64_t value_size_bits, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, struct lyd_value *storage, struct ly_err_item **err)
Store a union value with a specific member type index, keeping that member resolved (pinned),...
Definition union.c:632
#define LYPLG_TYPE_VAL_INLINE_DESTROY(type_val)
Destroy a prepared value.
LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_new(const struct ly_ctx *ctx, const void *value, uint32_t value_size, LY_VALUE_FORMAT format, const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Store used prefixes in a string into an internal libyang structure used in lyd_value.
LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *data_path, char *apptag, const char *err_format,...) _FORMAT_PRINTF(6
Create and fill an error structure.
LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_dup(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *orig, void **dup)
Duplicate prefix data.
#define LYPLG_BITS2BYTES(bits)
Convert bits to bytes.
LIBYANG_API_DECL LY_ERR LIBYANG_API_DECL LY_ERR ly_err_new_no_mem(struct ly_err_item **err)
Create and fill an error structure with a no-memory error.
LIBYANG_API_DECL void lyplg_type_prefix_data_free(LY_VALUE_FORMAT format, void *prefix_data)
Free internal prefix data.
Hold type-specific functions for various operations with the data values.
LIBYANG_API_DECL void lyplg_type_lyb_size_variable_bits(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint64_t *fixed_size_bits)
Implementation of lyplg_type_lyb_size_clb for a type with variable length in bits.
#define LYPLG_TYPE_STORE_DYNAMIC
#define LYPLG_TYPE_STORE_IMPLEMENT
#define LYPLG_TYPE_STORE_ONLY
LY_DATA_TYPE basetype
struct lyxp_expr * path
struct lys_module * module
uintptr_t plugin_ref
struct lysc_type * realtype
struct lysc_type ** types
struct ly_ctx * ctx
LY_DATA_TYPE basetype
LIBYANG_API_DECL const char * lyxp_get_expr(const struct lyxp_expr *path)
Getter for original XPath expression from a parsed expression.
Compiled YANG data node.
uint8_t ly_bool
Type to indicate boolean value.
Definition log.h:36
libyang sized array API.
API for (user) types plugins.
uint64_t orig_size_bits
Definition tree_data.h:669
const struct lysc_type * realtype
Definition tree_data.h:614
void * prefix_data
Definition tree_data.h:674
uint32_t hints
Definition tree_data.h:670
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition tree_data.h:653
struct lyd_value value
Definition tree_data.h:666
const char * _canonical
Definition tree_data.h:611
LY_VALUE_FORMAT format
Definition tree_data.h:671
const struct lysc_node * ctx_node
Definition tree_data.h:675
Generic structure for a data node.
Definition tree_data.h:875
YANG data representation.
Definition tree_data.h:610
Special lyd_value structure for built-in union values.
Definition tree_data.h:665
#define LYPLG_UNION_TYPE_IDX_SIZE
Size in bytes of the used type index in the LYB Binary Format.
Definition union.c:49
const struct lyplg_type_record plugins_union[]
Plugin information for union type implementation.
Definition union.c:946
@ LY_TYPE_LEAFREF
Definition utils.h:76
@ LY_TYPE_UNION
Definition utils.h:77
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition utils.h:93
@ LY_VALUE_CANON
Definition utils.h:94
@ LY_VALUE_LYB
Definition utils.h:100