libyang 6.4.3
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
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
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
61static LY_ERR
62union_subvalue_assignment(const void *value, uint64_t value_size_bits, void **original, uint64_t *orig_size_bits,
63 uint32_t *options)
64{
65 LY_ERR ret = LY_SUCCESS;
66
67 if (*options & LYPLG_TYPE_STORE_DYNAMIC) {
68 /* The allocated value is stored and spend. */
69 *original = (void *)value;
70 *options &= ~LYPLG_TYPE_STORE_DYNAMIC;
71 } else if (value_size_bits) {
72 /* Make a copy of the value. */
73 *original = calloc(1, LYPLG_BITS2BYTES(value_size_bits));
74 LY_CHECK_ERR_RET(!*original, ret = LY_EMEM, ret);
75 memcpy(*original, value, LYPLG_BITS2BYTES(value_size_bits));
76 } else {
77 /* Empty value. */
78 *original = strdup("");
79 LY_CHECK_ERR_RET(!*original, ret = LY_EMEM, ret);
80 }
81 *orig_size_bits = value_size_bits;
82
83 return ret;
84}
85
95static LY_ERR
96lyb_union_validate(const void *lyb_data, uint64_t lyb_data_size_bits, const struct lysc_type_union *type_u,
97 struct ly_err_item **err)
98{
99 uint32_t type_idx = 0;
100
101 /* basic validation */
102 if (lyb_data_size_bits < LYPLG_UNION_TYPE_IDX_SIZE * 8) {
103 return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB union value size %" PRIu64
104 " b (expected at least %" PRIu8 " b).", lyb_data_size_bits, LYPLG_UNION_TYPE_IDX_SIZE * 8);
105 }
106
107 /* get index in correct byte order */
108 memcpy(&type_idx, lyb_data, LYPLG_UNION_TYPE_IDX_SIZE);
109 type_idx = le32toh(type_idx);
110 if (type_idx >= LYA_COUNT(type_u->types)) {
111 return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
112 "Invalid LYB union type index %" PRIu32 " (type count %" LYA_PRI_COUNT_T ").",
113 type_idx, LYA_COUNT(type_u->types));
114 }
115
116 return LY_SUCCESS;
117}
118
129static void
130lyb_parse_union(const void *lyb_data, uint64_t lyb_data_size_bits, uint32_t *type_idx, const void **lyb_value,
131 uint64_t *lyb_value_size_bits)
132{
133 uint32_t num = 0;
134
135 assert(lyb_data && !(lyb_value && !lyb_value_size_bits));
136
137 if (type_idx) {
138 memcpy(&num, lyb_data, LYPLG_UNION_TYPE_IDX_SIZE);
139 num = le32toh(num);
140
141 *type_idx = num;
142 }
143
144 if (lyb_value && lyb_value_size_bits && lyb_data_size_bits) {
145 /* Get lyb_value and its length. */
146 if (lyb_data_size_bits == LYPLG_UNION_TYPE_IDX_SIZE * 8) {
147 *lyb_value_size_bits = 0;
148 *lyb_value = "";
149 } else {
150 *lyb_value_size_bits = lyb_data_size_bits - LYPLG_UNION_TYPE_IDX_SIZE * 8;
151 *lyb_value = (char *)lyb_data + LYPLG_UNION_TYPE_IDX_SIZE;
152 }
153 }
154}
155
167static LY_ERR
168union_update_lref_err(struct ly_err_item *err, const struct lysc_type *type, const void *value, uint64_t value_size_bits)
169{
170 const struct lysc_type_leafref *lref;
171 char *valstr = NULL;
172 int r;
173
174 if (!err || (type->basetype != LY_TYPE_LEAFREF)) {
175 /* nothing to do */
176 return LY_SUCCESS;
177 }
178
179 lref = (const struct lysc_type_leafref *)type;
180
181 /* update error-app-tag */
182 free(err->apptag);
183 err->apptag = strdup("instance-required");
184 LY_CHECK_ERR_RET(!err->apptag, LOGMEM(NULL), LY_EMEM);
185
186 valstr = strndup((const char *)value, value_size_bits / 8);
187 LY_CHECK_ERR_RET(!valstr, LOGMEM(NULL), LY_EMEM);
188
189 /* update error-message */
190 free(err->msg);
191 r = asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path));
192 free(valstr);
193 LY_CHECK_ERR_RET(r == -1, LOGMEM(NULL), LY_EMEM);
194
195 return LY_SUCCESS;
196}
197
213static LY_ERR
214union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint32_t type_idx, struct lyd_value_union *subvalue,
215 uint32_t options, ly_bool validate_tree, const struct lyd_node *ctx_node, const struct lyd_node *tree,
216 struct lys_glob_unres *unres, struct ly_err_item **err)
217{
218 LY_ERR rc = LY_SUCCESS;
219 struct lysc_type *type = type_u->types[type_idx];
220 const void *value = NULL;
221 ly_bool dynamic = 0;
222 LY_VALUE_FORMAT format;
223 void *prefix_data;
224 uint64_t value_size_bits = 0;
225 uint32_t opts = 0, ti;
226 struct lyplg_type *type_plg;
227
228 *err = NULL;
229
230 if (subvalue->format == LY_VALUE_LYB) {
231 lyb_parse_union(subvalue->original, subvalue->orig_size_bits, &ti, &value, &value_size_bits);
232 if (ti != type_idx) {
233 /* value of another type, first store the value properly and then use its JSON value for parsing */
234 type_plg = LYSC_GET_TYPE_PLG(type_u->types[ti]->plugin_ref);
235 rc = type_plg->store(ctx, type_u->types[ti], value, value_size_bits, LYPLG_TYPE_STORE_ONLY,
236 subvalue->format, subvalue->prefix_data, subvalue->hints, subvalue->ctx_node, &subvalue->value,
237 unres, err);
238 if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) {
239 /* clear any leftover/freed garbage */
240 memset(&subvalue->value, 0, sizeof subvalue->value);
241
242 /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
243 union_update_lref_err(*err, type_u->types[ti], value, value_size_bits);
244 goto cleanup;
245 }
246
247 assert(subvalue->value.realtype);
248 value = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(ctx, &subvalue->value,
249 LY_VALUE_JSON, NULL, &dynamic, &value_size_bits);
250 assert(!(value_size_bits % 8));
251
252 /* to avoid leaks, free subvalue->value, but we need the value, which may be stored there */
253 if (!dynamic) {
254 value = strndup(value, value_size_bits / 8);
255 dynamic = 1;
256 }
257 type_plg->free(ctx, &subvalue->value);
258
259 format = LY_VALUE_JSON;
260 prefix_data = NULL;
261 } else {
262 format = subvalue->format;
263 prefix_data = subvalue->prefix_data;
264 }
265 } else {
266 value = subvalue->original;
267 value_size_bits = subvalue->orig_size_bits;
268 format = subvalue->format;
269 prefix_data = subvalue->prefix_data;
270 }
271
272 if (options & LYPLG_TYPE_STORE_ONLY) {
273 opts |= LYPLG_TYPE_STORE_ONLY;
274 }
275
276 type_plg = LYSC_GET_TYPE_PLG(type->plugin_ref);
277
278 rc = type_plg->store(ctx, type, value, value_size_bits, opts, format, prefix_data, subvalue->hints,
279 subvalue->ctx_node, &subvalue->value, unres, err);
280 if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) {
281 /* clear any leftover/freed garbage */
282 memset(&subvalue->value, 0, sizeof subvalue->value);
283
284 /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
285 union_update_lref_err(*err, type, value, value_size_bits);
286 goto cleanup;
287 }
288
289 if (validate_tree && type_plg->validate_tree) {
290 /* we need the value validated in the data tree */
291 rc = type_plg->validate_tree(ctx, type, ctx_node, tree, &subvalue->value, err);
292 if (rc) {
293 /* validate failed, we need to free the stored value */
294 type_plg->free(ctx, &subvalue->value);
295 goto cleanup;
296 }
297 }
298
299cleanup:
300 if (dynamic) {
301 free((void *)value);
302 }
303 return rc;
304}
305
321static LY_ERR
322union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
323 uint32_t options, ly_bool validate_tree, const struct lyd_node *ctx_node, const struct lyd_node *tree,
324 uint32_t *type_idx, struct lys_glob_unres *unres, struct ly_err_item **err)
325{
326 LY_ERR ret = LY_SUCCESS;
327 LYA_COUNT_T u;
328 struct ly_err_item **errs = NULL, *e;
329 uint32_t *prev_lo, temp_lo = 0;
330 char *msg = NULL, *err_app_tag = NULL;
331 int msg_len = 0;
332 ly_bool use_err_app_tag = 0;
333 struct lyplg_type *type_plg;
334
335 *err = NULL;
336
337 /* alloc errors */
338 errs = calloc(LYA_COUNT(type_u->types), sizeof *errs);
339 LY_CHECK_RET(!errs, LY_EMEM);
340
341 /* turn logging temporarily off */
342 prev_lo = ly_temp_log_options(&temp_lo);
343
344 /* use the first usable subtype to store the value */
345 for (u = 0; u < LYA_COUNT(type_u->types); ++u) {
346 ret = union_store_type(ctx, type_u, u, subvalue, options, validate_tree, ctx_node, tree, unres, &e);
347 if ((ret == LY_SUCCESS) || (ret == LY_EINCOMPLETE)) {
348 break;
349 }
350
351 errs[u] = e;
352 }
353
354 if (u == LYA_COUNT(type_u->types)) {
355 /* create the full error */
356 if (subvalue->format == LY_VALUE_LYB) {
357 msg_len = asprintf(&msg, "Invalid LYB union value - no matching subtype found:\n");
358 } else {
359 msg_len = asprintf(&msg, "Invalid union value \"%.*s\" - no matching subtype found:\n",
360 (int)subvalue->orig_size_bits / 8, (char *)subvalue->original);
361 }
362 if (msg_len == -1) {
363 LY_CHECK_ERR_GOTO(!errs, ret = LY_EMEM, cleanup);
364 /* for further actions in function msg_len is just 0 */
365 msg_len = 0;
366 }
367 for (u = 0; u < LYA_COUNT(type_u->types); ++u) {
368 if (!errs[u]) {
369 /* no error for some reason */
370 continue;
371 }
372
373 /* use an app-tag if all the types set it or set none */
374 if (errs[u]->apptag) {
375 if (!err_app_tag) {
376 err_app_tag = strdup(errs[u]->apptag);
377 LY_CHECK_ERR_GOTO(!err_app_tag, ret = LY_EMEM, cleanup);
378 use_err_app_tag = 1;
379 } else if (strcmp(errs[u]->apptag, err_app_tag)) {
380 use_err_app_tag = 0;
381 }
382 }
383
384 type_plg = LYSC_GET_TYPE_PLG(type_u->types[u]->plugin_ref);
385
386 msg = ly_realloc(msg, msg_len + 4 + strlen(type_plg->id) + 2 + strlen(errs[u]->msg) + 2);
387 LY_CHECK_ERR_GOTO(!msg, ret = LY_EMEM, cleanup);
388 msg_len += sprintf(msg + msg_len, " %s: %s\n", type_plg->id, errs[u]->msg);
389 }
390
391 if (!use_err_app_tag) {
392 free(err_app_tag);
393 err_app_tag = NULL;
394 }
395 ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, err_app_tag, "%s", msg);
396 err_app_tag = NULL;
397 } else if (type_idx) {
398 *type_idx = u;
399 }
400
401cleanup:
402 for (u = 0; u < LYA_COUNT(type_u->types); ++u) {
403 ly_err_free(errs[u]);
404 }
405 free(errs);
406 free(msg);
407 free(err_app_tag);
408 ly_temp_log_options(prev_lo);
409 return ret;
410}
411
426static LY_ERR
427lyb_fill_subvalue(const struct ly_ctx *ctx, struct lysc_type_union *type_u, const void *lyb_data, uint64_t lyb_data_size_bits,
428 void *prefix_data, struct lyd_value_union *subvalue, uint32_t *options, struct lys_glob_unres *unres,
429 struct ly_err_item **err)
430{
431 LY_ERR ret;
432 uint64_t lyb_value_size_bits = 0;
433 uint32_t type_idx;
434 const void *lyb_value = NULL;
435
436 ret = lyb_union_validate(lyb_data, lyb_data_size_bits, type_u, err);
437 LY_CHECK_RET(ret);
438
439 /* parse lyb_data and set the lyb_value and lyb_value_size_bits */
440 lyb_parse_union(lyb_data, lyb_data_size_bits, &type_idx, &lyb_value, &lyb_value_size_bits);
441
442 /* store lyb_data to subvalue */
443 ret = union_subvalue_assignment(lyb_data, lyb_data_size_bits, &subvalue->original, &subvalue->orig_size_bits, options);
444 LY_CHECK_RET(ret);
445
446 if (lyb_value) {
447 /* resolve prefix_data and set format */
448 ret = lyplg_type_prefix_data_new(ctx, lyb_value, LYPLG_BITS2BYTES(lyb_value_size_bits), LY_VALUE_LYB,
449 prefix_data, &subvalue->format, &subvalue->prefix_data);
450 LY_CHECK_RET(ret);
451 assert(subvalue->format == LY_VALUE_LYB);
452 } else {
453 /* lyb_parse_union() did not find lyb_value, just set format */
454 subvalue->format = LY_VALUE_LYB;
455 }
456
457 /* use the specific type to store the value */
458 ret = union_store_type(ctx, type_u, type_idx, subvalue, *options, 0, NULL, NULL, unres, err);
459
460 return ret;
461}
462
463static LY_ERR
464lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
465 uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
466 struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
467{
468 LY_ERR ret = LY_SUCCESS, r;
469 struct lysc_type_union *type_u = (struct lysc_type_union *)type;
470 struct lyd_value_union *subvalue;
471
472 *err = NULL;
473
474 /* init storage */
475 memset(storage, 0, sizeof *storage);
476 LYPLG_TYPE_VAL_INLINE_PREPARE(storage, subvalue);
477 LY_CHECK_ERR_GOTO(!subvalue, ret = LY_EMEM, cleanup);
478 storage->realtype = type;
479 subvalue->hints = hints;
480 subvalue->ctx_node = ctx_node;
481
482 if (format == LY_VALUE_LYB) {
483 ret = lyb_fill_subvalue(ctx, type_u, value, value_size_bits, prefix_data, subvalue, &options, unres, err);
484 LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
485 } else {
486 /* store value to subvalue */
487 ret = union_subvalue_assignment(value, value_size_bits, &subvalue->original, &subvalue->orig_size_bits, &options);
488 LY_CHECK_GOTO(ret, cleanup);
489
490 /* store format-specific data for later prefix resolution */
492 &subvalue->format, &subvalue->prefix_data);
493 LY_CHECK_GOTO(ret, cleanup);
494
495 /* use the first usable and valid subtype to store the value */
496 ret = union_find_type(ctx, type_u, subvalue, options & ~LYPLG_TYPE_STORE_ONLY, 0, NULL, NULL, NULL, unres, err);
497 if (ret && (ret != LY_EINCOMPLETE) && (options & LYPLG_TYPE_STORE_ONLY)) {
498 /* we tried to find the actual type by validating the value but no type matched, so try to find any type */
499 ly_err_free(*err);
500 *err = NULL;
501 ret = union_find_type(ctx, type_u, subvalue, options, 0, NULL, NULL, NULL, unres, err);
502 }
503 LY_CHECK_GOTO(ret && (ret != LY_EINCOMPLETE), cleanup);
504 }
505
506 /* store canonical value, if any (use the specific type value) */
507 r = lydict_insert(ctx, subvalue->value._canonical, 0, &storage->_canonical);
508 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
509
510cleanup:
511 if (options & LYPLG_TYPE_STORE_DYNAMIC) {
512 free((void *)value);
513 }
514
515 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
516 lyplg_type_free_union(ctx, storage);
517 }
518 return ret;
519}
520
521static LY_ERR
522lyplg_type_validate_tree_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
523 const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
524{
525 LY_ERR rc = LY_SUCCESS;
526 struct lysc_type_union *type_u = (struct lysc_type_union *)type;
527 struct lyd_value_union *subvalue = storage->subvalue;
528 struct lyd_value orig = {0};
529 uint32_t type_idx;
530 ly_bool validated = 0;
531 struct lyplg_type *subvalue_type_plg;
532
533 *err = NULL;
534
535 /* because of types that do not store their own type as realtype (leafref), we are not able to call their
536 * validate callback (there is no way to get the type) but even if possible, the value may be invalid
537 * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
538 subvalue_type_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
539 LY_CHECK_RET(subvalue_type_plg->duplicate(ctx, &subvalue->value, &orig));
540 subvalue_type_plg->free(ctx, &subvalue->value);
541
542 if (subvalue->format == LY_VALUE_LYB) {
543 /* use the specific type to store and validate the value */
544 lyb_parse_union(subvalue->original, 0, &type_idx, NULL, NULL);
545
546 if (union_store_type(ctx, type_u, type_idx, subvalue, 0, 1, ctx_node, tree, NULL, err)) {
547 /* validation failed, we need to try storing the value again */
548 ly_err_free(*err);
549 *err = NULL;
550 } else {
551 validated = 1;
552 }
553 }
554
555 if (!validated) {
556 /* use the first usable subtype to store and validate the value */
557 rc = union_find_type(ctx, type_u, subvalue, 0, 1, ctx_node, tree, NULL, NULL, err);
558 if (rc) {
559 /* validation failed, restore the previous value */
560 subvalue->value = orig;
561 return rc;
562 }
563 }
564
565 /* update the canonical value, if any generated */
566 lydict_remove(ctx, storage->_canonical);
567 LY_CHECK_RET(lydict_insert(ctx, subvalue->value._canonical, 0, &storage->_canonical));
568
569 /* free backup value */
570 LYSC_GET_TYPE_PLG(orig.realtype->plugin_ref)->free(ctx, &orig);
571 return LY_SUCCESS;
572}
573
574static LY_ERR
575lyplg_type_compare_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
576{
577 if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
578 return LY_ENOT;
579 }
580 return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->compare(ctx,
581 &val1->subvalue->value, &val2->subvalue->value);
582}
583
584static int
585lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
586{
587 int rc;
588 LYA_COUNT_T u;
589 struct lysc_type **types, *type;
590
591 if (val1->subvalue->value.realtype == val2->subvalue->value.realtype) {
592 return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->sort(ctx,
593 &val1->subvalue->value, &val2->subvalue->value);
594 }
595
596 /* compare according to the order of types */
597 rc = 0;
598 types = ((struct lysc_type_union *)val1->realtype)->types;
599 LYA_FOR(types, u) {
600 if (types[u]->basetype == LY_TYPE_LEAFREF) {
601 type = ((struct lysc_type_leafref *)types[u])->realtype;
602 } else {
603 type = types[u];
604 }
605
606 if (type == val1->subvalue->value.realtype) {
607 rc = 1;
608 break;
609 } else if (type == val2->subvalue->value.realtype) {
610 rc = -1;
611 break;
612 }
613 }
614 assert(rc);
615
616 return rc;
617}
618
631static const void *
632lyb_union_print(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
633 void *prefix_data, uint64_t *value_size_bits)
634{
635 void *ret = NULL;
636 LY_ERR r;
637 struct ly_err_item *err;
638 uint64_t pval_size_bits;
639 uint32_t num = 0, type_idx = 0;
640 struct lyd_value orig = {0};
641 struct lyplg_type *subvalue_type_plg;
642 ly_bool dynamic;
643 void *pval;
644
645 if (!ctx) {
646 assert(subvalue->ctx_node);
647 ctx = subvalue->ctx_node->module->ctx;
648 }
649
650 /* because of types that do not store their own type as realtype (leafref), we are not able to call their
651 * validate callback (there is no way to get the type) but even if possible, the value may be invalid
652 * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
653 subvalue_type_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
654 LY_CHECK_RET(subvalue_type_plg->duplicate(ctx, &subvalue->value, &orig), NULL);
655 subvalue_type_plg->free(ctx, &subvalue->value);
656
657 /* learn the type index, may fail if LYPLG_TYPE_STORE_ONLY has been used before */
658 r = union_find_type(ctx, type_u, subvalue, 0, 0, NULL, NULL, &type_idx, NULL, &err);
659 ly_err_free(err);
660 if ((r != LY_SUCCESS) && (r != LY_EINCOMPLETE)) {
661 /* use LYPLG_TYPE_STORE_ONLY to manage to print the value */
662 r = union_find_type(ctx, type_u, subvalue, LYPLG_TYPE_STORE_ONLY, 0, NULL, NULL, &type_idx, NULL, &err);
663 ly_err_free(err);
664 }
665 LY_CHECK_ERR_RET((r != LY_SUCCESS) && (r != LY_EINCOMPLETE), subvalue->value = orig, NULL);
666
667 /* print subvalue in LYB format */
668 pval = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(NULL, &subvalue->value, LY_VALUE_LYB,
669 prefix_data, &dynamic, &pval_size_bits);
670 LY_CHECK_ERR_RET(!pval, subvalue->value = orig, NULL);
671
672 /* create LYB data */
673 *value_size_bits = LYPLG_UNION_TYPE_IDX_SIZE * 8 + pval_size_bits;
674 ret = malloc(LYPLG_BITS2BYTES(*value_size_bits));
675 LY_CHECK_GOTO(!ret, cleanup);
676
677 num = htole32(type_idx);
678 memcpy(ret, &num, LYPLG_UNION_TYPE_IDX_SIZE);
679 memcpy((char *)ret + LYPLG_UNION_TYPE_IDX_SIZE, pval, LYPLG_BITS2BYTES(pval_size_bits));
680
681 if (dynamic) {
682 free(pval);
683 }
684
685cleanup:
686 /* restore backup (original) value */
687 LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->free(ctx, &subvalue->value);
688 subvalue->value = orig;
689 return ret;
690}
691
692static const void *
693lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
694 void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
695{
696 const void *ret;
697 struct lyd_value_union *subvalue = value->subvalue;
698 struct lysc_type_union *type_u = (struct lysc_type_union *)value->realtype;
699 uint64_t lyb_data_size_bits = 0;
700
701 if ((format == LY_VALUE_LYB) && (subvalue->format == LY_VALUE_LYB)) {
702 /* The return value is already ready. */
703 *dynamic = 0;
704 if (value_size_bits) {
705 *value_size_bits = subvalue->orig_size_bits;
706 }
707 return subvalue->original;
708 } else if ((format == LY_VALUE_LYB) && (subvalue->format != LY_VALUE_LYB)) {
709 /* The return LYB data must be created. */
710 *dynamic = 1;
711 ret = lyb_union_print(ctx, type_u, subvalue, prefix_data, &lyb_data_size_bits);
712 if (value_size_bits) {
713 *value_size_bits = lyb_data_size_bits;
714 }
715 return ret;
716 }
717
718 assert(format != LY_VALUE_LYB);
719 ret = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(ctx, &subvalue->value,
720 format, prefix_data, dynamic, value_size_bits);
721 if (!value->_canonical && (format == LY_VALUE_CANON)) {
722 /* the canonical value is supposed to be stored now */
723 lydict_insert(ctx, subvalue->value._canonical, 0, (const char **)&value->_canonical);
724 }
725
726 return ret;
727}
728
729static LY_ERR
730lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
731{
732 LY_ERR ret = LY_SUCCESS;
733 struct lyd_value_union *orig_val = original->subvalue, *dup_val;
734
735 /* init dup value */
736 memset(dup, 0, sizeof *dup);
737 dup->realtype = original->realtype;
738
739 ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
740 LY_CHECK_GOTO(ret, cleanup);
741
742 dup_val = calloc(1, sizeof *dup_val);
743 LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
744 dup->subvalue = dup_val;
745
746 ret = LYSC_GET_TYPE_PLG(orig_val->value.realtype->plugin_ref)->duplicate(ctx, &orig_val->value, &dup_val->value);
747 LY_CHECK_GOTO(ret, cleanup);
748
749 if (orig_val->orig_size_bits) {
750 dup_val->original = calloc(1, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
751 LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
752 memcpy(dup_val->original, orig_val->original, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
753 } else {
754 dup_val->original = strdup("");
755 LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
756 }
757 dup_val->orig_size_bits = orig_val->orig_size_bits;
758
759 dup_val->format = orig_val->format;
760 dup_val->ctx_node = orig_val->ctx_node;
761 dup_val->hints = orig_val->hints;
762 ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
763 LY_CHECK_GOTO(ret, cleanup);
764
765cleanup:
766 if (ret) {
767 lyplg_type_free_union(ctx, dup);
768 }
769 return ret;
770}
771
772static void
773lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
774{
775 struct lyd_value_union *val;
776
778 value->_canonical = NULL;
779 LYD_VALUE_GET(value, val);
780 if (val) {
781 if (val->value.realtype) {
782 LYSC_GET_TYPE_PLG(val->value.realtype->plugin_ref)->free(ctx, &val->value);
783 }
785 free(val->original);
786
788 }
789}
790
799 {
800 .module = "",
801 .revision = NULL,
802 .name = LY_TYPE_UNION_STR,
803
804 .plugin.id = "ly2 union",
805 .plugin.lyb_size = lyplg_type_lyb_size_variable_bits,
806 .plugin.store = lyplg_type_store_union,
807 .plugin.validate_value = NULL,
808 .plugin.validate_tree = lyplg_type_validate_tree_union,
809 .plugin.compare = lyplg_type_compare_union,
810 .plugin.sort = lyplg_type_sort_union,
811 .plugin.print = lyplg_type_print_union,
812 .plugin.duplicate = lyplg_type_dup_union,
813 .plugin.free = lyplg_type_free_union,
814 },
815 {0}
816};
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_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_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().
const char *const char * revision
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 LY_ERR LIBYANG_API_DECL void ly_err_free(void *ptr)
Destructor for the error records created with ly_err_new().
#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 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 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_ONLY
LY_DATA_TYPE basetype
struct lyxp_expr * path
uintptr_t plugin_ref
struct lysc_type ** types
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:798
@ LY_TYPE_LEAFREF
Definition utils.h:76
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition utils.h:93
@ LY_VALUE_JSON
Definition utils.h:98
@ LY_VALUE_CANON
Definition utils.h:94
@ LY_VALUE_LYB
Definition utils.h:100