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