libyang  4.0.4
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 <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 
45 static void lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value);
46 
50 #define LYPLG_UNION_TYPE_IDX_SIZE 1
51 
62 static LY_ERR
63 union_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 
96 static LY_ERR
97 lyb_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 
130 static void
131 lyb_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 
168 static LY_ERR
169 union_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 
215 static LY_ERR
216 union_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 
300 cleanup:
301  if (dynamic) {
302  free((void *)value);
303  }
304  return rc;
305 }
306 
323 static LY_ERR
324 union_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 
403 cleanup:
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 
428 static LY_ERR
429 lyb_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 
464 static LY_ERR
465 lyplg_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  /* to correctly resolve the union type, we need to always validate the value */
490  options &= ~LYPLG_TYPE_STORE_ONLY;
491 
492  /* store value to subvalue */
493  ret = union_subvalue_assignment(value, value_size_bits, &subvalue->original, &subvalue->orig_size_bits, &options);
494  LY_CHECK_GOTO(ret, cleanup);
495 
496  /* store format-specific data for later prefix resolution */
497  ret = lyplg_type_prefix_data_new(ctx, value, LYPLG_BITS2BYTES(value_size_bits), format, prefix_data,
498  &subvalue->format, &subvalue->prefix_data);
499  LY_CHECK_GOTO(ret, cleanup);
500 
501  /* use the first usable subtype to store the value */
502  ret = union_find_type(ctx, type_u, subvalue, options, 0, NULL, NULL, NULL, NULL, unres, err);
503  LY_CHECK_GOTO((ret != LY_SUCCESS) && (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, const struct lysc_ext_instance *top_ext, struct lyd_value *storage,
524  struct ly_err_item **err)
525 {
526  LY_ERR rc = LY_SUCCESS;
527  struct lysc_type_union *type_u = (struct lysc_type_union *)type;
528  struct lyd_value_union *subvalue = storage->subvalue;
529  struct lyd_value orig = {0};
530  uint32_t type_idx;
531  ly_bool validated = 0;
532  struct lyplg_type *subvalue_type_plg;
533 
534  *err = NULL;
535 
536  /* because of types that do not store their own type as realtype (leafref), we are not able to call their
537  * validate callback (there is no way to get the type) but even if possible, the value may be invalid
538  * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
539  subvalue_type_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
540  LY_CHECK_RET(subvalue_type_plg->duplicate(ctx, &subvalue->value, &orig));
541  subvalue_type_plg->free(ctx, &subvalue->value);
542 
543  if (subvalue->format == LY_VALUE_LYB) {
544  /* use the specific type to store and validate the value */
545  lyb_parse_union(subvalue->original, 0, &type_idx, NULL, NULL);
546 
547  if (union_store_type(ctx, type_u, type_idx, subvalue, 0, 1, ctx_node, tree, top_ext, NULL, err)) {
548  /* validation failed, we need to try storing the value again */
549  ly_err_free(*err);
550  *err = NULL;
551  } else {
552  validated = 1;
553  }
554  }
555 
556  if (!validated) {
557  /* use the first usable subtype to store and validate the value */
558  rc = union_find_type(ctx, type_u, subvalue, 0, 1, ctx_node, tree, top_ext, NULL, NULL, err);
559  if (rc) {
560  /* validation failed, restore the previous value */
561  subvalue->value = orig;
562  return rc;
563  }
564  }
565 
566  /* update the canonical value, if any generated */
567  lydict_remove(ctx, storage->_canonical);
568  LY_CHECK_RET(lydict_insert(ctx, subvalue->value._canonical, 0, &storage->_canonical));
569 
570  /* free backup value */
571  LYSC_GET_TYPE_PLG(orig.realtype->plugin_ref)->free(ctx, &orig);
572  return LY_SUCCESS;
573 }
574 
575 static LY_ERR
576 lyplg_type_compare_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
577 {
578  if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
579  return LY_ENOT;
580  }
581  return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->compare(ctx,
582  &val1->subvalue->value, &val2->subvalue->value);
583 }
584 
585 static int
586 lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
587 {
588  int rc;
590  struct lysc_type **types, *type;
591 
592  if (val1->subvalue->value.realtype == val2->subvalue->value.realtype) {
593  return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->sort(ctx,
594  &val1->subvalue->value, &val2->subvalue->value);
595  }
596 
597  /* compare according to the order of types */
598  rc = 0;
599  types = ((struct lysc_type_union *)val1->realtype)->types;
600  LY_ARRAY_FOR(types, u) {
601  if (types[u]->basetype == LY_TYPE_LEAFREF) {
602  type = ((struct lysc_type_leafref *)types[u])->realtype;
603  } else {
604  type = types[u];
605  }
606 
607  if (type == val1->subvalue->value.realtype) {
608  rc = 1;
609  break;
610  } else if (type == val2->subvalue->value.realtype) {
611  rc = -1;
612  break;
613  }
614  }
615  assert(rc);
616 
617  return rc;
618 }
619 
632 static const void *
633 lyb_union_print(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
634  void *prefix_data, uint32_t *value_size_bits)
635 {
636  void *ret = NULL;
637  LY_ERR r;
638  struct ly_err_item *err;
639  uint32_t num = 0, pval_size_bits, type_idx = 0;
640  ly_bool dynamic;
641  void *pval;
642 
643  /* learn the type index, must succeed because have been called before */
644  if (!ctx) {
645  assert(subvalue->ctx_node);
646  ctx = subvalue->ctx_node->module->ctx;
647  }
648  LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->free(ctx, &subvalue->value);
649  r = union_find_type(ctx, type_u, subvalue, 0, 0, NULL, NULL, NULL, &type_idx, NULL, &err);
650  ly_err_free(err);
651  LY_CHECK_RET((r != LY_SUCCESS) && (r != LY_EINCOMPLETE), NULL);
652 
653  /* print subvalue in LYB format */
654  pval = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(NULL, &subvalue->value, LY_VALUE_LYB,
655  prefix_data, &dynamic, &pval_size_bits);
656  LY_CHECK_RET(!pval, NULL);
657 
658  /* create LYB data */
659  *value_size_bits = LYPLG_UNION_TYPE_IDX_SIZE * 8 + pval_size_bits;
660  ret = malloc(LYPLG_BITS2BYTES(*value_size_bits));
661  LY_CHECK_RET(!ret, NULL);
662 
663  num = htole32(type_idx);
664  memcpy(ret, &num, LYPLG_UNION_TYPE_IDX_SIZE);
665  memcpy((char *)ret + LYPLG_UNION_TYPE_IDX_SIZE, pval, LYPLG_BITS2BYTES(pval_size_bits));
666 
667  if (dynamic) {
668  free(pval);
669  }
670 
671  return ret;
672 }
673 
674 static const void *
675 lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
676  void *prefix_data, ly_bool *dynamic, uint32_t *value_size_bits)
677 {
678  const void *ret;
679  struct lyd_value_union *subvalue = value->subvalue;
680  struct lysc_type_union *type_u = (struct lysc_type_union *)value->realtype;
681  uint32_t lyb_data_size_bits = 0;
682 
683  if ((format == LY_VALUE_LYB) && (subvalue->format == LY_VALUE_LYB)) {
684  /* The return value is already ready. */
685  *dynamic = 0;
686  if (value_size_bits) {
687  *value_size_bits = subvalue->orig_size_bits;
688  }
689  return subvalue->original;
690  } else if ((format == LY_VALUE_LYB) && (subvalue->format != LY_VALUE_LYB)) {
691  /* The return LYB data must be created. */
692  *dynamic = 1;
693  ret = lyb_union_print(ctx, type_u, subvalue, prefix_data, &lyb_data_size_bits);
694  if (value_size_bits) {
695  *value_size_bits = lyb_data_size_bits;
696  }
697  return ret;
698  }
699 
700  assert(format != LY_VALUE_LYB);
701  ret = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(ctx, &subvalue->value,
702  format, prefix_data, dynamic, value_size_bits);
703  if (!value->_canonical && (format == LY_VALUE_CANON)) {
704  /* the canonical value is supposed to be stored now */
705  lydict_insert(ctx, subvalue->value._canonical, 0, (const char **)&value->_canonical);
706  }
707 
708  return ret;
709 }
710 
711 static LY_ERR
712 lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
713 {
714  LY_ERR ret = LY_SUCCESS;
715  struct lyd_value_union *orig_val = original->subvalue, *dup_val;
716 
717  /* init dup value */
718  memset(dup, 0, sizeof *dup);
719  dup->realtype = original->realtype;
720 
721  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
722  LY_CHECK_GOTO(ret, cleanup);
723 
724  dup_val = calloc(1, sizeof *dup_val);
725  LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
726  dup->subvalue = dup_val;
727 
728  ret = LYSC_GET_TYPE_PLG(orig_val->value.realtype->plugin_ref)->duplicate(ctx, &orig_val->value, &dup_val->value);
729  LY_CHECK_GOTO(ret, cleanup);
730 
731  if (orig_val->orig_size_bits) {
732  dup_val->original = calloc(1, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
733  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
734  memcpy(dup_val->original, orig_val->original, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
735  } else {
736  dup_val->original = strdup("");
737  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
738  }
739  dup_val->orig_size_bits = orig_val->orig_size_bits;
740 
741  dup_val->format = orig_val->format;
742  dup_val->ctx_node = orig_val->ctx_node;
743  dup_val->hints = orig_val->hints;
744  ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
745  LY_CHECK_GOTO(ret, cleanup);
746 
747 cleanup:
748  if (ret) {
749  lyplg_type_free_union(ctx, dup);
750  }
751  return ret;
752 }
753 
754 static void
755 lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
756 {
757  struct lyd_value_union *val;
758 
759  lydict_remove(ctx, value->_canonical);
760  value->_canonical = NULL;
761  LYD_VALUE_GET(value, val);
762  if (val) {
763  if (val->value.realtype) {
764  LYSC_GET_TYPE_PLG(val->value.realtype->plugin_ref)->free(ctx, &val->value);
765  }
767  free(val->original);
768 
770  }
771 }
772 
781  {
782  .module = "",
783  .revision = NULL,
784  .name = LY_TYPE_UNION_STR,
785 
786  .plugin.id = "ly2 union",
787  .plugin.lyb_size = lyplg_type_lyb_size_variable_bits,
788  .plugin.store = lyplg_type_store_union,
789  .plugin.validate_value = NULL,
790  .plugin.validate_tree = lyplg_type_validate_tree_union,
791  .plugin.compare = lyplg_type_compare_union,
792  .plugin.sort = lyplg_type_sort_union,
793  .plugin.print = lyplg_type_print_union,
794  .plugin.duplicate = lyplg_type_dup_union,
795  .plugin.free = lyplg_type_free_union,
796  },
797  {0}
798 };
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.
struct lysc_type * realtype
Definition: tree_data.h:567
Compiled YANG data node.
Definition: tree_schema.h:1434
#define LY_PRI_ARRAY_COUNT_TYPE
Printing format specifier macro for LY_ARRAY_SIZE_TYPE values.
Definition: tree.h:109
struct ly_ctx * ctx
Definition: tree_schema.h:2185
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
const char * id
LY_DATA_TYPE basetype
Definition: tree_schema.h:1410
Hold type-specific functions for various operations with the data values.
Generic structure for a data node.
Definition: tree_data.h:792
YANG extension compiled instance.
Definition: plugins_exts.h:436
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().
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:240
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:28
lyplg_type_free_clb free
LY_ERR err
Definition: log.h:287
#define LYPLG_UNION_TYPE_IDX_SIZE
Size in bytes of the used type index in the LYB Binary Format.
Definition: union.c:50
Definition: log.h:254
#define LYPLG_TYPE_STORE_DYNAMIC
void * original
Definition: tree_data.h:621
uintptr_t plugin_ref
Definition: tree_schema.h:1299
#define LOGMEM(CTX)
Definition: tree_edit.h:22
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:293
char * msg
Definition: log.h:289
struct lysc_node * ctx_node
Definition: tree_data.h:628
struct lysc_type ** types
Definition: tree_schema.h:1413
LYPLG_TYPE_VAL_INLINE_DESTROY(val)
Definition: log.h:242
The main libyang public header.
lyplg_type_validate_tree_clb validate_tree
YANG data representation.
Definition: tree_data.h:563
const char * _canonical
Definition: tree_data.h:564
lyplg_type_store_clb store
struct lyxp_expr * path
Definition: tree_schema.h:1379
Libyang full error structure.
Definition: log.h:285
Definition: log.h:277
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:606
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.
struct lyplg_type_record plugins_union[]
Plugin information for union type implementation.
Definition: union.c:780
uint32_t hints
Definition: tree_data.h:623
uint32_t orig_size_bits
Definition: tree_data.h:622
void * prefix_data
Definition: tree_data.h:627
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:248
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.
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
LIBYANG_API_DECL void lyplg_type_prefix_data_free(LY_VALUE_FORMAT format, void *prefix_data)
Free internal prefix data.
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 LY_ARRAY_FOR(ARRAY,...)
Sized-array iterator (for-loop).
Definition: tree.h:167
#define LY_ARRAY_COUNT_TYPE
Type (i.e. size) of the sized array&#39;s size counter.
Definition: tree.h:104
struct lys_module * module
Definition: tree_schema.h:1438
if((v1->size!=v2->size)||memcmp(v1->data, v2->data, v1->size))
Definition: binary.c:384
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:234
LIBYANG_API_DECL const char * lyxp_get_expr(const struct lyxp_expr *path)
Getter for original XPath expression from a parsed expression.
#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:1300
Special lyd_value structure for built-in union values.
Definition: tree_data.h:618
API for (user) types plugins.
LY_VALUE_FORMAT format
Definition: tree_data.h:624
libyang context handler.
#define LYPLG_BITS2BYTES(bits)
Convert bits to bytes.
struct lyd_value value
Definition: tree_data.h:619
struct lysc_ext_instance * top_ext
Definition: tree_data.h:629
#define LYPLG_TYPE_STORE_ONLY
assert(!value->_canonical)