libyang  6.4.26
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
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 
44 static void lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value);
45 
49 #define LYPLG_UNION_TYPE_IDX_SIZE 1
50 
60 static LY_ERR
61 union_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 
94 static void
95 union_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 
133 static LY_ERR
134 union_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 
167 cleanup:
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 
189 static LY_ERR
190 union_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 
237 static LY_ERR
238 union_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 
293 cleanup:
294  return rc;
295 }
296 
316 static LY_ERR
317 union_store_type(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
318  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_snode,
319  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
320 {
321  LY_ERR rc = LY_SUCCESS;
322  struct lyplg_type *type_plg;
323  ly_bool dynamic = 0;
324 
325  *err = NULL;
326 
327  type_plg = LYSC_GET_TYPE_PLG(type->plugin_ref);
328 
329  /* do not free the value (yet) */
330  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
331  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
332  dynamic = 1;
333  }
334 
335  rc = type_plg->store(ctx, type, value, value_size_bits, options, format, prefix_data, hints, ctx_snode, storage,
336  unres, err);
337 
338  if (rc && (rc != LY_EINCOMPLETE)) {
339  /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
340  union_update_lref_err(*err, type, value, value_size_bits);
341 
342  /* clear any leftover/freed garbage */
343  memset(storage, 0, sizeof *storage);
344  }
345  if (dynamic) {
346  free((void *)value);
347  }
348  return rc;
349 }
350 
369 static LY_ERR
370 union_read_store_type(const struct ly_ctx *ctx, const struct lysc_type_union *type_u, uint32_t type_idx,
371  struct lyd_value_union *subvalue, uint32_t options, const struct lyd_node *ctx_node,
372  const struct lyd_node *tree, const struct ly_ht *unres_ht, struct lys_glob_unres *unres, struct ly_err_item **err)
373 {
374  LY_ERR rc = LY_SUCCESS, r;
375  const void *value;
376  uint64_t value_size_bits;
377  ly_bool dynamic;
378  LY_VALUE_FORMAT format;
379  void *prefix_data;
380  struct lyplg_type *type_plg;
381 
382  /* get the input value in a suitable format from the original value */
383  r = union_subvalue_get_input_value(ctx, type_u, type_idx, subvalue, &value, &value_size_bits, &dynamic, &format,
384  &prefix_data, err);
385  if (r && (r != LY_EINCOMPLETE)) {
386  rc = r;
387  goto cleanup;
388  }
389 
390  if (dynamic) {
391  options |= LYPLG_TYPE_STORE_DYNAMIC;
392  } else {
393  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
394  }
395 
396  /* store the value as the specific type */
397  rc = union_store_type(ctx, type_u->types[type_idx], value, value_size_bits, options, format, prefix_data,
398  subvalue->hints, subvalue->ctx_node, &subvalue->value, unres, err);
399  if (rc && (rc != LY_EINCOMPLETE)) {
400  goto cleanup;
401  }
402 
403  /* validate the value */
404  type_plg = LYSC_GET_TYPE_PLG(type_u->types[type_idx]->plugin_ref);
405  if (tree && type_plg->validate_tree) {
406  rc = type_plg->validate_tree(ctx, type_u->types[type_idx], ctx_node, tree, unres_ht, &subvalue->value, err);
407  if (rc) {
408  /* validate failed, we need to free the stored value */
409  type_plg->free(ctx, &subvalue->value);
410  memset(&subvalue->value, 0, sizeof subvalue->value);
411  goto cleanup;
412  }
413  }
414 
415 cleanup:
416  return rc;
417 }
418 
434 static LY_ERR
435 union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
436  uint32_t options, const struct lyd_node *ctx_node, const struct lyd_node *tree, const struct ly_ht *unres_ht,
437  uint32_t *type_idx, struct lys_glob_unres *unres, struct ly_err_item **err)
438 {
439  LY_ERR rc = LY_SUCCESS, r;
440  LYA_COUNT_T u;
441  struct ly_err_item **errs = NULL, *e;
442  uint32_t *prev_lo, temp_lo = 0;
443  char *msg = NULL, *err_app_tag = NULL;
444  uint32_t msg_size = 0, msg_len = 0;
445  ly_bool use_err_app_tag = 0;
446  struct lyplg_type *type_plg;
447 
448  *err = NULL;
449 
450  /* alloc errors */
451  errs = calloc(LYA_COUNT(type_u->types), sizeof *errs);
452  LY_CHECK_RET(!errs, LY_EMEM);
453 
454  /* turn logging temporarily off */
455  prev_lo = ly_temp_log_options(&temp_lo);
456 
457  /* use the first usable subtype to store the value */
458  LYA_FOR(type_u->types, u) {
459  rc = union_read_store_type(ctx, type_u, u, subvalue, options, ctx_node, tree, unres_ht, unres, &e);
460  if (!rc || (rc == LY_EINCOMPLETE)) {
461  /* success */
462  break;
463  }
464 
465  errs[u] = e;
466  }
467 
468  if (u == LYA_COUNT(type_u->types)) {
469  /* create the full error */
470  if (subvalue->format == LY_VALUE_LYB) {
471  r = ly_append_str(&msg, &msg_size, &msg_len, "Invalid LYB union value - no matching subtype found:\n");
472  } else {
473  r = ly_append_str(&msg, &msg_size, &msg_len, "Invalid union value \"%.*s\" - no matching subtype found:\n",
474  (int)subvalue->orig_size_bits / 8, (char *)subvalue->original);
475  }
476  LY_CHECK_ERR_GOTO(r, rc = LY_EMEM, cleanup);
477  LYA_FOR(type_u->types, u) {
478  if (!errs[u]) {
479  /* no error for some reason */
480  continue;
481  }
482 
483  /* use an app-tag if all the types set it or set none */
484  if (errs[u]->apptag) {
485  if (!err_app_tag) {
486  err_app_tag = strdup(errs[u]->apptag);
487  LY_CHECK_ERR_GOTO(!err_app_tag, rc = LY_EMEM, cleanup);
488  use_err_app_tag = 1;
489  } else if (strcmp(errs[u]->apptag, err_app_tag)) {
490  use_err_app_tag = 0;
491  }
492  }
493 
494  type_plg = LYSC_GET_TYPE_PLG(type_u->types[u]->plugin_ref);
495 
496  r = ly_append_str(&msg, &msg_size, &msg_len, " %s: %s\n", type_plg->id, errs[u]->msg);
497  LY_CHECK_ERR_GOTO(r, rc = LY_EMEM, cleanup);
498  }
499 
500  if (!use_err_app_tag) {
501  free(err_app_tag);
502  err_app_tag = NULL;
503  }
504  rc = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, err_app_tag, "%s", msg);
505  err_app_tag = NULL;
506  } else if (type_idx) {
507  *type_idx = u;
508  }
509 
510 cleanup:
511  LYA_FOR(type_u->types, u) {
512  ly_err_free(errs[u]);
513  }
514  free(errs);
515  free(msg);
516  free(err_app_tag);
517  ly_temp_log_options(prev_lo);
518  return rc;
519 }
520 
539 static LY_ERR
540 union_prepare_subvalue(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
541  uint32_t *options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
542  struct lyd_value *storage, struct lyd_value_union **subvalue, struct ly_err_item **err)
543 {
544  *err = NULL;
545 
546  /* init storage */
547  memset(storage, 0, sizeof *storage);
548  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, *subvalue);
549  LY_CHECK_RET(!*subvalue, ly_err_new_no_mem(err));
550 
551  storage->realtype = type;
552  (*subvalue)->hints = hints;
553  (*subvalue)->ctx_node = ctx_node;
554 
555  /* store the caller value as the subvalue original, it is needed for the member type store */
556  if (*options & LYPLG_TYPE_STORE_DYNAMIC) {
557  (*subvalue)->original = (void *)value;
558  *options &= ~LYPLG_TYPE_STORE_DYNAMIC;
559  } else if (value_size_bits) {
560  (*subvalue)->original = calloc(1, LYPLG_BITS2BYTES(value_size_bits));
561  LY_CHECK_RET(!(*subvalue)->original, ly_err_new_no_mem(err));
562  memcpy((*subvalue)->original, value, LYPLG_BITS2BYTES(value_size_bits));
563  } else {
564  (*subvalue)->original = strdup("");
565  LY_CHECK_RET(!(*subvalue)->original, ly_err_new_no_mem(err));
566  }
567  (*subvalue)->orig_size_bits = value_size_bits;
568 
569  /* derive format-specific data of the value, needed for the member type store;
570  * the values in the LYB format must have no prefix data stored (see ly_dup_prefix_data()) */
571  return lyplg_type_prefix_data_new(ctx, value, LYPLG_BITS2BYTES(value_size_bits), format,
572  (format == LY_VALUE_LYB) ? NULL : prefix_data, &(*subvalue)->format, &(*subvalue)->prefix_data);
573 }
574 
575 static LY_ERR
576 lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
577  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
578  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
579 {
580  LY_ERR rc = LY_SUCCESS, r;
581  struct lysc_type_union *type_u;
582  struct lyd_value_union *subvalue;
583  uint32_t type_idx = 0;
584 
585  *err = NULL;
586 
587  type_u = (struct lysc_type_union *)type;
588 
589  /* initialize the storage and assign the caller value to the subvalue */
590  rc = union_prepare_subvalue(ctx, type, value, value_size_bits, &options, format, prefix_data, hints,
591  ctx_node, storage, &subvalue, err);
592  LY_CHECK_GOTO(rc, cleanup);
593 
594  if (format == LY_VALUE_LYB) {
595  /* the binary value pins the member type to use, validate it and learn its index */
596  rc = union_validate_value_lyb(value, value_size_bits, type_u, err);
597  LY_CHECK_GOTO(rc, cleanup);
598  union_parse_value_lyb(value, 0, &type_idx, NULL, NULL);
599 
600  /* use the pinned member type to store the value, its acceptance errors are propagated */
601  rc = union_read_store_type(ctx, type_u, type_idx, subvalue, options, NULL, NULL, NULL, unres, err);
602  LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
603  } else {
604  /* use the first usable and valid subtype to store the value */
605  rc = union_find_type(ctx, type_u, subvalue, options & ~LYPLG_TYPE_STORE_ONLY, NULL, NULL, NULL, NULL, unres, err);
606  if (rc && (rc != LY_EINCOMPLETE) && (options & LYPLG_TYPE_STORE_ONLY)) {
607  /* we tried to find the actual type by validating the value but no type matched, so try to find any type */
608  ly_err_free(*err);
609  rc = union_find_type(ctx, type_u, subvalue, options, NULL, NULL, NULL, NULL, unres, err);
610  }
611  LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
612  }
613 
614  /* store canonical value, if any (use the specific type value) */
615  r = lydict_dup(ctx, subvalue->value._canonical, &storage->_canonical);
616  LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
617 
618 cleanup:
619  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
620  free((void *)value);
621  }
622 
623  if (rc && (rc != LY_EINCOMPLETE)) {
624  lyplg_type_free_union(ctx, storage);
625  }
626  return rc;
627 }
628 
629 LIBYANG_API_DEF LY_ERR
630 lyplg_type_store_union_idx(const struct ly_ctx *ctx, const struct lysc_type *type, uint32_t type_idx,
631  const void *value, uint64_t value_size_bits, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data,
632  uint32_t hints, const struct lysc_node *ctx_node, struct lyd_value *storage, struct ly_err_item **err)
633 {
634  LY_ERR rc = LY_SUCCESS, r;
635  struct lysc_type_union *type_u = (struct lysc_type_union *)type;
636  struct lyd_value_union *subvalue;
637  void *lyb;
638  uint64_t lyb_size_bits;
639 
640  LY_CHECK_ARG_RET(ctx, ctx, type, type->basetype == LY_TYPE_UNION, type_idx < LYA_COUNT(type_u->types),
641  !(options & LYPLG_TYPE_STORE_IMPLEMENT), storage, err, LY_EINVAL);
642 
643  memset(storage, 0, sizeof *storage);
644  *err = NULL;
645 
646  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, subvalue);
647  LY_CHECK_ERR_GOTO(!subvalue, rc = LY_EMEM, cleanup);
648 
649  /* store the value of the specific type */
650  rc = union_store_type(ctx, type_u->types[type_idx], value, value_size_bits, options & ~LYPLG_TYPE_STORE_DYNAMIC,
651  format, prefix_data, hints, ctx_node, &subvalue->value, NULL, err);
652  LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
653 
654  /* create the union LYB value with the resolved type index */
655  r = union_create_value_lyb(ctx, type_idx, &subvalue->value, &lyb, &lyb_size_bits, err);
656  LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
657 
658  /* store it as the original value (hints, while not relevant for the LYB format, may be used by other formats) */
659  subvalue->original = lyb;
660  subvalue->orig_size_bits = lyb_size_bits;
661  subvalue->hints = hints;
662  subvalue->format = LY_VALUE_LYB;
663  subvalue->ctx_node = ctx_node;
664 
665  /* store canonical value (use the specific type value) and realtype */
666  r = lydict_dup(ctx, subvalue->value._canonical, &storage->_canonical);
667  LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
668  storage->realtype = type;
669 
670 cleanup:
671  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
672  free((void *)value);
673  }
674 
675  if (rc && (rc != LY_EINCOMPLETE)) {
676  lyplg_type_free_union(ctx, storage);
677  memset(storage, 0, sizeof *storage);
678  }
679  return rc;
680 }
681 
682 static LY_ERR
683 lyplg_type_validate_tree_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
684  const struct lyd_node *tree, const struct ly_ht *unres_ht, struct lyd_value *storage, struct ly_err_item **err)
685 {
686  LY_ERR rc = LY_SUCCESS;
687  struct lysc_type_union *type_u = (struct lysc_type_union *)type;
688  struct lyd_value_union *subvalue = storage->subvalue;
689  struct lyd_value orig = {0};
690  uint32_t type_idx;
691  ly_bool validated = 0;
692  struct lyplg_type *realtype_plg;
693 
694  *err = NULL;
695 
696  /* because of types that do not store their own type as realtype (leafref), we are not able to call their
697  * validate callback (there is no way to get the type) but even if possible, the value may be invalid
698  * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
699  realtype_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
700  LY_CHECK_RET(realtype_plg->duplicate(ctx, &subvalue->value, &orig));
701  realtype_plg->free(ctx, &subvalue->value);
702 
703  if (subvalue->format == LY_VALUE_LYB) {
704  /* use the specific type to store and validate the value */
705  union_parse_value_lyb(subvalue->original, 0, &type_idx, NULL, NULL);
706 
707  if (union_read_store_type(ctx, type_u, type_idx, subvalue, 0, ctx_node, tree, unres_ht, NULL, err)) {
708  /* validation failed, we need to try storing the value again */
709  ly_err_free(*err);
710  *err = NULL;
711  } else {
712  validated = 1;
713  }
714  }
715 
716  if (!validated) {
717  /* use the first usable subtype to store and validate the value */
718  rc = union_find_type(ctx, type_u, subvalue, 0, ctx_node, tree, unres_ht, NULL, NULL, err);
719  LY_CHECK_GOTO(rc, cleanup);
720  }
721 
722  /* update the canonical value, if any generated */
723  lydict_remove(ctx, storage->_canonical);
724  storage->_canonical = NULL;
725  LY_CHECK_GOTO(rc = lydict_dup(ctx, subvalue->value._canonical, &storage->_canonical), cleanup);
726 
727 cleanup:
728  if (rc) {
729  /* restore the previous value */
730  subvalue->value = orig;
731  } else {
732  /* free the backup value */
733  LYSC_GET_TYPE_PLG(orig.realtype->plugin_ref)->free(ctx, &orig);
734  }
735  return rc;
736 }
737 
738 static LY_ERR
739 lyplg_type_compare_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
740 {
741  if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
742  return LY_ENOT;
743  }
744  return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->compare(ctx,
745  &val1->subvalue->value, &val2->subvalue->value);
746 }
747 
748 static int
749 lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
750 {
751  int rc;
752  LYA_COUNT_T u;
753  struct lysc_type **types, *type;
754 
755  if (val1->subvalue->value.realtype == val2->subvalue->value.realtype) {
756  return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->sort(ctx,
757  &val1->subvalue->value, &val2->subvalue->value);
758  }
759 
760  /* compare according to the order of types */
761  rc = 0;
762  types = ((struct lysc_type_union *)val1->realtype)->types;
763  LYA_FOR(types, u) {
764  if (types[u]->basetype == LY_TYPE_LEAFREF) {
765  type = ((struct lysc_type_leafref *)types[u])->realtype;
766  } else {
767  type = types[u];
768  }
769 
770  if (type == val1->subvalue->value.realtype) {
771  rc = 1;
772  break;
773  } else if (type == val2->subvalue->value.realtype) {
774  rc = -1;
775  break;
776  }
777  }
778  assert(rc);
779 
780  return rc;
781 }
782 
793 static const void *
794 union_print_value_lyb(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
795  uint64_t *value_size_bits)
796 {
797  void *ret = NULL;
798  LY_ERR r;
799  struct ly_err_item *err;
800  uint32_t type_idx = 0;
801  struct lyd_value orig = {0};
802  struct lyplg_type *realtype_plg;
803 
804  if (!ctx) {
805  assert(subvalue->ctx_node);
806  ctx = subvalue->ctx_node->module->ctx;
807  }
808 
809  /* because of types that do not store their own type as realtype (leafref), we are not able to call their
810  * validate callback (there is no way to get the type) but even if possible, the value may be invalid
811  * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
812  realtype_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
813  LY_CHECK_RET(realtype_plg->duplicate(ctx, &subvalue->value, &orig), NULL);
814  realtype_plg->free(ctx, &subvalue->value);
815 
816  /* learn the type index, may fail if LYPLG_TYPE_STORE_ONLY has been used before */
817  r = union_find_type(ctx, type_u, subvalue, 0, NULL, NULL, NULL, &type_idx, NULL, &err);
818  ly_err_free(err);
819  if (r && (r != LY_EINCOMPLETE)) {
820  /* use LYPLG_TYPE_STORE_ONLY to manage to print the value */
821  r = union_find_type(ctx, type_u, subvalue, LYPLG_TYPE_STORE_ONLY, NULL, NULL, NULL, &type_idx, NULL, &err);
822  ly_err_free(err);
823  }
824  LY_CHECK_ERR_RET(r && (r != LY_EINCOMPLETE), subvalue->value = orig, NULL);
825 
826  /* create the LYB data of the resolved member type value */
827  r = union_create_value_lyb(NULL, type_idx, &subvalue->value, &ret, value_size_bits, &err);
828  ly_err_free(err);
829  LY_CHECK_ERR_RET(r, subvalue->value = orig, NULL);
830 
831  /* restore backup (original) value */
832  realtype_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
833  realtype_plg->free(ctx, &subvalue->value);
834  subvalue->value = orig;
835  return ret;
836 }
837 
838 static const void *
839 lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
840  void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
841 {
842  const void *ret;
843  struct lyd_value_union *subvalue = value->subvalue;
844  struct lysc_type_union *type_u = (struct lysc_type_union *)value->realtype;
845  uint64_t lyb_data_size_bits = 0;
846 
847  if ((format == LY_VALUE_LYB) && (subvalue->format == LY_VALUE_LYB)) {
848  /* return value is ready */
849  *dynamic = 0;
850  if (value_size_bits) {
851  *value_size_bits = subvalue->orig_size_bits;
852  }
853  return subvalue->original;
854  } else if ((format == LY_VALUE_LYB) && (subvalue->format != LY_VALUE_LYB)) {
855  /* return LYB data value must be created */
856  *dynamic = 1;
857  ret = union_print_value_lyb(ctx, type_u, subvalue, &lyb_data_size_bits);
858  if (value_size_bits) {
859  *value_size_bits = lyb_data_size_bits;
860  }
861  return ret;
862  }
863 
864  assert(format != LY_VALUE_LYB);
865  ret = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(ctx, &subvalue->value,
866  format, prefix_data, dynamic, value_size_bits);
867  if (!value->_canonical && (format == LY_VALUE_CANON)) {
868  /* the canonical value is supposed to be stored now */
869  lydict_dup(ctx, subvalue->value._canonical, (const char **)&value->_canonical);
870  }
871 
872  return ret;
873 }
874 
875 static LY_ERR
876 lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
877 {
878  LY_ERR ret = LY_SUCCESS;
879  struct lyd_value_union *orig_val = original->subvalue, *dup_val;
880 
881  /* init dup value */
882  memset(dup, 0, sizeof *dup);
883  dup->realtype = original->realtype;
884 
885  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
886  LY_CHECK_GOTO(ret, cleanup);
887 
888  dup_val = calloc(1, sizeof *dup_val);
889  LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
890  dup->subvalue = dup_val;
891 
892  ret = LYSC_GET_TYPE_PLG(orig_val->value.realtype->plugin_ref)->duplicate(ctx, &orig_val->value, &dup_val->value);
893  LY_CHECK_GOTO(ret, cleanup);
894 
895  if (orig_val->orig_size_bits) {
896  dup_val->original = calloc(1, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
897  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
898  memcpy(dup_val->original, orig_val->original, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
899  } else {
900  dup_val->original = strdup("");
901  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
902  }
903  dup_val->orig_size_bits = orig_val->orig_size_bits;
904 
905  dup_val->format = orig_val->format;
906  dup_val->ctx_node = orig_val->ctx_node;
907  dup_val->hints = orig_val->hints;
908  ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
909  LY_CHECK_GOTO(ret, cleanup);
910 
911 cleanup:
912  if (ret) {
913  lyplg_type_free_union(ctx, dup);
914  }
915  return ret;
916 }
917 
918 static void
919 lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
920 {
921  struct lyd_value_union *val;
922 
924  value->_canonical = NULL;
925  LYD_VALUE_GET(value, val);
926  if (val) {
927  if (val->value.realtype) {
928  LYSC_GET_TYPE_PLG(val->value.realtype->plugin_ref)->free(ctx, &val->value);
929  }
931  free(val->original);
932 
934  }
935 }
936 
944 const struct lyplg_type_record plugins_union[] = {
945  {
946  .module = "",
947  .revision = NULL,
948  .name = LY_TYPE_UNION_STR,
949 
950  .plugin.id = "ly2 union",
951  .plugin.lyb_size = lyplg_type_lyb_size_variable_bits,
952  .plugin.store = lyplg_type_store_union,
953  .plugin.validate_value = NULL,
954  .plugin.validate_tree = lyplg_type_validate_tree_union,
955  .plugin.compare = lyplg_type_compare_union,
956  .plugin.sort = lyplg_type_sort_union,
957  .plugin.print = lyplg_type_print_union,
958  .plugin.duplicate = lyplg_type_dup_union,
959  .plugin.free = lyplg_type_free_union,
960  },
961  {0}
962 };
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().
const char * module
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:630
#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
Definition: tree_schema.h:1278
struct lyxp_expr * path
Definition: tree_schema.h:1357
struct lys_module * module
Definition: tree_schema.h:1416
uintptr_t plugin_ref
Definition: tree_schema.h:1277
struct lysc_type ** types
Definition: tree_schema.h:1391
struct ly_ctx * ctx
Definition: tree_schema.h:2243
LY_DATA_TYPE basetype
Definition: tree_schema.h:1388
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.
Definition: tree_schema.h:1412
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:29
libyang sized array API.
libyang hash table.
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 * original
Definition: tree_data.h:668
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:944
@ 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