libyang  4.0.0
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, 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  } else if (type_idx) {
399  *type_idx = u;
400  }
401 
402 cleanup:
403  for (u = 0; u < LY_ARRAY_COUNT(type_u->types); ++u) {
404  ly_err_free(errs[u]);
405  }
406  free(errs);
407  free(msg);
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, uint32_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  uint32_t lyb_value_size_bits = 0, type_idx;
433  const void *lyb_value = NULL;
434 
435  ret = lyb_union_validate(lyb_data, lyb_data_size_bits, type_u, err);
436  LY_CHECK_RET(ret);
437 
438  /* parse lyb_data and set the lyb_value and lyb_value_size_bits */
439  lyb_parse_union(lyb_data, lyb_data_size_bits, &type_idx, &lyb_value, &lyb_value_size_bits);
440 
441  /* store lyb_data to subvalue */
442  ret = union_subvalue_assignment(lyb_data, lyb_data_size_bits, &subvalue->original, &subvalue->orig_size_bits, options);
443  LY_CHECK_RET(ret);
444 
445  if (lyb_value) {
446  /* resolve prefix_data and set format */
447  ret = lyplg_type_prefix_data_new(ctx, lyb_value, LYPLG_BITS2BYTES(lyb_value_size_bits), LY_VALUE_LYB,
448  prefix_data, &subvalue->format, &subvalue->prefix_data);
449  LY_CHECK_RET(ret);
450  assert(subvalue->format == LY_VALUE_LYB);
451  } else {
452  /* lyb_parse_union() did not find lyb_value, just set format */
453  subvalue->format = LY_VALUE_LYB;
454  }
455 
456  /* use the specific type to store the value */
457  ret = union_store_type(ctx, type_u, type_idx, subvalue, *options, 0, NULL, NULL, NULL, unres, err);
458 
459  return ret;
460 }
461 
462 static LY_ERR
463 lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint32_t value_size_bits,
464  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
465  const struct lysc_ext_instance *top_ext, struct lyd_value *storage, struct lys_glob_unres *unres,
466  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  subvalue->top_ext = top_ext;
482 
483  if (format == LY_VALUE_LYB) {
484  ret = lyb_fill_subvalue(ctx, type_u, value, value_size_bits, prefix_data, subvalue, &options, unres, err);
485  LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
486  } else {
487  /* to correctly resolve the union type, we need to always validate the value */
488  options &= ~LYPLG_TYPE_STORE_ONLY;
489 
490  /* store value to subvalue */
491  ret = union_subvalue_assignment(value, value_size_bits, &subvalue->original, &subvalue->orig_size_bits, &options);
492  LY_CHECK_GOTO(ret, cleanup);
493 
494  /* store format-specific data for later prefix resolution */
495  ret = lyplg_type_prefix_data_new(ctx, value, LYPLG_BITS2BYTES(value_size_bits), format, prefix_data,
496  &subvalue->format, &subvalue->prefix_data);
497  LY_CHECK_GOTO(ret, cleanup);
498 
499  /* use the first usable subtype to store the value */
500  ret = union_find_type(ctx, type_u, subvalue, options, 0, NULL, NULL, NULL, NULL, unres, err);
501  LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
502  }
503 
504  /* store canonical value, if any (use the specific type value) */
505  r = lydict_insert(ctx, subvalue->value._canonical, 0, &storage->_canonical);
506  LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
507 
508 cleanup:
509  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
510  free((void *)value);
511  }
512 
513  if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
514  lyplg_type_free_union(ctx, storage);
515  }
516  return ret;
517 }
518 
519 static LY_ERR
520 lyplg_type_validate_tree_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
521  const struct lyd_node *tree, const struct lysc_ext_instance *top_ext, struct lyd_value *storage,
522  struct ly_err_item **err)
523 {
524  LY_ERR rc = LY_SUCCESS;
525  struct lysc_type_union *type_u = (struct lysc_type_union *)type;
526  struct lyd_value_union *subvalue = storage->subvalue;
527  struct lyd_value orig = {0};
528  uint32_t type_idx;
529  ly_bool validated = 0;
530  struct lyplg_type *subvalue_type_plg;
531 
532  *err = NULL;
533 
534  /* because of types that do not store their own type as realtype (leafref), we are not able to call their
535  * validate callback (there is no way to get the type) but even if possible, the value may be invalid
536  * for the type, so we may have to perform union value storing again from scratch, but keep a value backup */
537  subvalue_type_plg = LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref);
538  LY_CHECK_RET(subvalue_type_plg->duplicate(ctx, &subvalue->value, &orig));
539  subvalue_type_plg->free(ctx, &subvalue->value);
540 
541  if (subvalue->format == LY_VALUE_LYB) {
542  /* use the specific type to store and validate the value */
543  lyb_parse_union(subvalue->original, 0, &type_idx, NULL, NULL);
544 
545  if (union_store_type(ctx, type_u, type_idx, subvalue, 0, 1, ctx_node, tree, top_ext, NULL, err)) {
546  /* validation failed, we need to try storing the value again */
547  ly_err_free(*err);
548  *err = NULL;
549  } else {
550  validated = 1;
551  }
552  }
553 
554  if (!validated) {
555  /* use the first usable subtype to store and validate the value */
556  rc = union_find_type(ctx, type_u, subvalue, 0, 1, ctx_node, tree, top_ext, NULL, NULL, err);
557  if (rc) {
558  /* validation failed, restore the previous value */
559  subvalue->value = orig;
560  return rc;
561  }
562  }
563 
564  /* update the canonical value, if any generated */
565  lydict_remove(ctx, storage->_canonical);
566  LY_CHECK_RET(lydict_insert(ctx, subvalue->value._canonical, 0, &storage->_canonical));
567 
568  /* free backup value */
569  LYSC_GET_TYPE_PLG(orig.realtype->plugin_ref)->free(ctx, &orig);
570  return LY_SUCCESS;
571 }
572 
573 static LY_ERR
574 lyplg_type_compare_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
575 {
576  if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
577  return LY_ENOT;
578  }
579  return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->compare(ctx,
580  &val1->subvalue->value, &val2->subvalue->value);
581 }
582 
583 static int
584 lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
585 {
586  int rc;
588  struct lysc_type **types, *type;
589 
590  if (val1->subvalue->value.realtype == val2->subvalue->value.realtype) {
591  return LYSC_GET_TYPE_PLG(val1->subvalue->value.realtype->plugin_ref)->sort(ctx,
592  &val1->subvalue->value, &val2->subvalue->value);
593  }
594 
595  /* compare according to the order of types */
596  rc = 0;
597  types = ((struct lysc_type_union *)val1->realtype)->types;
598  LY_ARRAY_FOR(types, u) {
599  if (types[u]->basetype == LY_TYPE_LEAFREF) {
600  type = ((struct lysc_type_leafref *)types[u])->realtype;
601  } else {
602  type = types[u];
603  }
604 
605  if (type == val1->subvalue->value.realtype) {
606  rc = 1;
607  break;
608  } else if (type == val2->subvalue->value.realtype) {
609  rc = -1;
610  break;
611  }
612  }
613  assert(rc);
614 
615  return rc;
616 }
617 
630 static const void *
631 lyb_union_print(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
632  void *prefix_data, uint32_t *value_size_bits)
633 {
634  void *ret = NULL;
635  LY_ERR r;
636  struct ly_err_item *err;
637  uint32_t num = 0, pval_size_bits, type_idx = 0;
638  ly_bool dynamic;
639  void *pval;
640 
641  /* learn the type index, must succeed because have been called before */
642  if (!ctx) {
643  assert(subvalue->ctx_node);
644  ctx = subvalue->ctx_node->module->ctx;
645  }
646  LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->free(ctx, &subvalue->value);
647  r = union_find_type(ctx, type_u, subvalue, 0, 0, NULL, NULL, NULL, &type_idx, NULL, &err);
648  ly_err_free(err);
649  LY_CHECK_RET((r != LY_SUCCESS) && (r != LY_EINCOMPLETE), NULL);
650 
651  /* print subvalue in LYB format */
652  pval = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(NULL, &subvalue->value, LY_VALUE_LYB,
653  prefix_data, &dynamic, &pval_size_bits);
654  LY_CHECK_RET(!pval, NULL);
655 
656  /* create LYB data */
657  *value_size_bits = LYPLG_UNION_TYPE_IDX_SIZE * 8 + pval_size_bits;
658  ret = malloc(LYPLG_BITS2BYTES(*value_size_bits));
659  LY_CHECK_RET(!ret, NULL);
660 
661  num = htole32(type_idx);
662  memcpy(ret, &num, LYPLG_UNION_TYPE_IDX_SIZE);
663  memcpy((char *)ret + LYPLG_UNION_TYPE_IDX_SIZE, pval, LYPLG_BITS2BYTES(pval_size_bits));
664 
665  if (dynamic) {
666  free(pval);
667  }
668 
669  return ret;
670 }
671 
672 static const void *
673 lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
674  void *prefix_data, ly_bool *dynamic, uint32_t *value_size_bits)
675 {
676  const void *ret;
677  struct lyd_value_union *subvalue = value->subvalue;
678  struct lysc_type_union *type_u = (struct lysc_type_union *)value->realtype;
679  uint32_t lyb_data_size_bits = 0;
680 
681  if ((format == LY_VALUE_LYB) && (subvalue->format == LY_VALUE_LYB)) {
682  /* The return value is already ready. */
683  *dynamic = 0;
684  if (value_size_bits) {
685  *value_size_bits = subvalue->orig_size_bits;
686  }
687  return subvalue->original;
688  } else if ((format == LY_VALUE_LYB) && (subvalue->format != LY_VALUE_LYB)) {
689  /* The return LYB data must be created. */
690  *dynamic = 1;
691  ret = lyb_union_print(ctx, type_u, subvalue, prefix_data, &lyb_data_size_bits);
692  if (value_size_bits) {
693  *value_size_bits = lyb_data_size_bits;
694  }
695  return ret;
696  }
697 
698  assert(format != LY_VALUE_LYB);
699  ret = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(ctx, &subvalue->value,
700  format, prefix_data, dynamic, value_size_bits);
701  if (!value->_canonical && (format == LY_VALUE_CANON)) {
702  /* the canonical value is supposed to be stored now */
703  lydict_insert(ctx, subvalue->value._canonical, 0, (const char **)&value->_canonical);
704  }
705 
706  return ret;
707 }
708 
709 static LY_ERR
710 lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
711 {
712  LY_ERR ret = LY_SUCCESS;
713  struct lyd_value_union *orig_val = original->subvalue, *dup_val;
714 
715  /* init dup value */
716  memset(dup, 0, sizeof *dup);
717  dup->realtype = original->realtype;
718 
719  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
720  LY_CHECK_GOTO(ret, cleanup);
721 
722  dup_val = calloc(1, sizeof *dup_val);
723  LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
724  dup->subvalue = dup_val;
725 
726  ret = LYSC_GET_TYPE_PLG(orig_val->value.realtype->plugin_ref)->duplicate(ctx, &orig_val->value, &dup_val->value);
727  LY_CHECK_GOTO(ret, cleanup);
728 
729  if (orig_val->orig_size_bits) {
730  dup_val->original = calloc(1, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
731  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
732  memcpy(dup_val->original, orig_val->original, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
733  } else {
734  dup_val->original = strdup("");
735  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
736  }
737  dup_val->orig_size_bits = orig_val->orig_size_bits;
738 
739  dup_val->format = orig_val->format;
740  dup_val->ctx_node = orig_val->ctx_node;
741  dup_val->hints = orig_val->hints;
742  ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
743  LY_CHECK_GOTO(ret, cleanup);
744 
745 cleanup:
746  if (ret) {
747  lyplg_type_free_union(ctx, dup);
748  }
749  return ret;
750 }
751 
752 static void
753 lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
754 {
755  struct lyd_value_union *val;
756 
757  lydict_remove(ctx, value->_canonical);
758  value->_canonical = NULL;
759  LYD_VALUE_GET(value, val);
760  if (val) {
761  if (val->value.realtype) {
762  LYSC_GET_TYPE_PLG(val->value.realtype->plugin_ref)->free(ctx, &val->value);
763  }
765  free(val->original);
766 
768  }
769 }
770 
779  {
780  .module = "",
781  .revision = NULL,
782  .name = LY_TYPE_UNION_STR,
783 
784  .plugin.id = "ly2 union",
785  .plugin.lyb_size = lyplg_type_lyb_size_variable_bits,
786  .plugin.store = lyplg_type_store_union,
787  .plugin.validate_value = NULL,
788  .plugin.validate_tree = lyplg_type_validate_tree_union,
789  .plugin.compare = lyplg_type_compare_union,
790  .plugin.sort = lyplg_type_sort_union,
791  .plugin.print = lyplg_type_print_union,
792  .plugin.duplicate = lyplg_type_dup_union,
793  .plugin.free = lyplg_type_free_union,
794  },
795  {0}
796 };
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:778
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)