libyang  6.4.7
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
61 static LY_ERR
62 union_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 
95 static LY_ERR
96 lyb_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 
129 static void
130 lyb_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 
167 static LY_ERR
168 union_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 
213 static LY_ERR
214 union_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 
299 cleanup:
300  if (dynamic) {
301  free((void *)value);
302  }
303  return rc;
304 }
305 
321 static LY_ERR
322 union_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 
401 cleanup:
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 
426 static LY_ERR
427 lyb_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 
463 static LY_ERR
464 lyplg_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 */
491  ret = lyplg_type_prefix_data_new(ctx, value, LYPLG_BITS2BYTES(value_size_bits), format, prefix_data,
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 
510 cleanup:
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 
521 static LY_ERR
522 lyplg_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 
574 static LY_ERR
575 lyplg_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 
584 static int
585 lyplg_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 
631 static const void *
632 lyb_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 
685 cleanup:
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 
692 static const void *
693 lyplg_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 
729 static LY_ERR
730 lyplg_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 
765 cleanup:
766  if (ret) {
767  lyplg_type_free_union(ctx, dup);
768  }
769  return ret;
770 }
771 
772 static void
773 lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
774 {
775  struct lyd_value_union *val;
776 
777  lydict_remove(ctx, value->_canonical);
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 };
#define LYA_COUNT_T
Type (i.e. size) of the sized array&#39;s size counter.
Definition: ly_array.h:38
struct lysc_type * realtype
Definition: tree_data.h:614
Compiled YANG data node.
Definition: tree_schema.h:1430
#define LYA_FOR(ARRAY, INDEX)
Helper macro to go through sized-arrays with a numeric iterator.
Definition: ly_array.h:55
struct ly_ctx * ctx
Definition: tree_schema.h:2264
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
const char * id
LY_DATA_TYPE basetype
Definition: tree_schema.h:1406
Hold type-specific functions for various operations with the data values.
Generic structure for a data node.
Definition: tree_data.h:877
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()...
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:255
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:29
lyplg_type_free_clb free
LY_ERR err
Definition: log.h:303
#define LYPLG_UNION_TYPE_IDX_SIZE
Size in bytes of the used type index in the LYB Binary Format.
Definition: union.c:49
libyang dictionary
Definition: log.h:269
#define LYPLG_TYPE_STORE_DYNAMIC
void * original
Definition: tree_data.h:668
uintptr_t plugin_ref
Definition: tree_schema.h:1295
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.
char * apptag
Definition: log.h:309
char * msg
Definition: log.h:305
struct lysc_node * ctx_node
Definition: tree_data.h:675
struct lysc_type ** types
Definition: tree_schema.h:1409
LYPLG_TYPE_VAL_INLINE_DESTROY(val)
Definition: log.h:257
lyplg_type_validate_tree_clb validate_tree
YANG data representation.
Definition: tree_data.h:610
const char * _canonical
Definition: tree_data.h:611
lyplg_type_store_clb store
struct lyxp_expr * path
Definition: tree_schema.h:1375
Libyang full error structure.
Definition: log.h:301
#define LYA_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: ly_array.h:78
Definition: log.h:293
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:653
LIBYANG_API_DECL LY_ERR LIBYANG_API_DECL void ly_err_free(void *ptr)
Destructor for the error records created with ly_err_new().
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 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.
struct lyplg_type_record plugins_union[]
Plugin information for union type implementation.
Definition: union.c:798
#define LYA_PRI_COUNT_T
Printing format specifier macro for LYA_COUNT_T values.
Definition: ly_array.h:43
uint32_t hints
Definition: tree_data.h:670
libyang sized array API.
void * prefix_data
Definition: tree_data.h:674
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 ...
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...
Definition: log.h:263
lyplg_type_dup_clb duplicate
const char * module
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.
LIBYANG_API_DECL void lyplg_type_prefix_data_free(LY_VALUE_FORMAT format, void *prefix_data)
Free internal prefix data.
struct lys_module * module
Definition: tree_schema.h:1434
if((v1->size!=v2->size)||memcmp(v1->data, v2->data, v1->size))
Definition: binary.c:382
LIBYANG_API_DECL const char * lyxp_get_expr(const struct lyxp_expr *path)
Getter for original XPath expression from a parsed expression.
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: utils.h:93
uint64_t orig_size_bits
Definition: tree_data.h:669
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
LY_DATA_TYPE basetype
Definition: tree_schema.h:1296
Special lyd_value structure for built-in union values.
Definition: tree_data.h:665
API for (user) types plugins.
LY_VALUE_FORMAT format
Definition: tree_data.h:671
libyang context handler.
#define LYPLG_BITS2BYTES(bits)
Convert bits to bytes.
struct lyd_value value
Definition: tree_data.h:666
#define LYPLG_TYPE_STORE_ONLY
assert(!value->_canonical)