libyang  5.4.9
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, uint64_t value_size_bits, void **original, uint64_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, uint64_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 %" PRIu64
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, uint64_t lyb_data_size_bits, uint32_t *type_idx, const void **lyb_value,
132  uint64_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, uint64_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 
214 static LY_ERR
215 union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint32_t type_idx, struct lyd_value_union *subvalue,
216  uint32_t options, ly_bool validate_tree, const struct lyd_node *ctx_node, const struct lyd_node *tree,
217  struct lys_glob_unres *unres, struct ly_err_item **err)
218 {
219  LY_ERR rc = LY_SUCCESS;
220  struct lysc_type *type = type_u->types[type_idx];
221  const void *value = NULL;
222  ly_bool dynamic = 0;
223  LY_VALUE_FORMAT format;
224  void *prefix_data;
225  uint64_t value_size_bits = 0;
226  uint32_t 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->value,
238  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->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, &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 
322 static LY_ERR
323 union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct lyd_value_union *subvalue,
324  uint32_t options, ly_bool validate_tree, const struct lyd_node *ctx_node, const struct lyd_node *tree,
325  uint32_t *type_idx, struct lys_glob_unres *unres, struct ly_err_item **err)
326 {
327  LY_ERR ret = LY_SUCCESS;
329  struct ly_err_item **errs = NULL, *e;
330  uint32_t *prev_lo, temp_lo = 0;
331  char *msg = NULL, *err_app_tag = NULL;
332  int msg_len = 0;
333  ly_bool use_err_app_tag = 0;
334  struct lyplg_type *type_plg;
335 
336  *err = NULL;
337 
338  /* alloc errors */
339  errs = calloc(LY_ARRAY_COUNT(type_u->types), sizeof *errs);
340  LY_CHECK_RET(!errs, LY_EMEM);
341 
342  /* turn logging temporarily off */
343  prev_lo = ly_temp_log_options(&temp_lo);
344 
345  /* use the first usable subtype to store the value */
346  for (u = 0; u < LY_ARRAY_COUNT(type_u->types); ++u) {
347  ret = union_store_type(ctx, type_u, u, subvalue, options, validate_tree, ctx_node, tree, unres, &e);
348  if ((ret == LY_SUCCESS) || (ret == LY_EINCOMPLETE)) {
349  break;
350  }
351 
352  errs[u] = e;
353  }
354 
355  if (u == LY_ARRAY_COUNT(type_u->types)) {
356  /* create the full error */
357  if (subvalue->format == LY_VALUE_LYB) {
358  msg_len = asprintf(&msg, "Invalid LYB union value - no matching subtype found:\n");
359  } else {
360  msg_len = asprintf(&msg, "Invalid union value \"%.*s\" - no matching subtype found:\n",
361  (int)subvalue->orig_size_bits / 8, (char *)subvalue->original);
362  }
363  if (msg_len == -1) {
364  LY_CHECK_ERR_GOTO(!errs, ret = LY_EMEM, cleanup);
365  /* for further actions in function msg_len is just 0 */
366  msg_len = 0;
367  }
368  for (u = 0; u < LY_ARRAY_COUNT(type_u->types); ++u) {
369  if (!errs[u]) {
370  /* no error for some reason */
371  continue;
372  }
373 
374  /* use an app-tag if all the types set it or set none */
375  if (errs[u]->apptag) {
376  if (!err_app_tag) {
377  err_app_tag = strdup(errs[u]->apptag);
378  LY_CHECK_ERR_GOTO(!err_app_tag, ret = LY_EMEM, cleanup);
379  use_err_app_tag = 1;
380  } else if (strcmp(errs[u]->apptag, err_app_tag)) {
381  use_err_app_tag = 0;
382  }
383  }
384 
385  type_plg = LYSC_GET_TYPE_PLG(type_u->types[u]->plugin_ref);
386 
387  msg = ly_realloc(msg, msg_len + 4 + strlen(type_plg->id) + 2 + strlen(errs[u]->msg) + 2);
388  LY_CHECK_ERR_GOTO(!msg, ret = LY_EMEM, cleanup);
389  msg_len += sprintf(msg + msg_len, " %s: %s\n", type_plg->id, errs[u]->msg);
390  }
391 
392  if (!use_err_app_tag) {
393  free(err_app_tag);
394  err_app_tag = NULL;
395  }
396  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, err_app_tag, "%s", msg);
397  err_app_tag = NULL;
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  free(err_app_tag);
409  ly_temp_log_options(prev_lo);
410  return ret;
411 }
412 
427 static LY_ERR
428 lyb_fill_subvalue(const struct ly_ctx *ctx, struct lysc_type_union *type_u, const void *lyb_data, uint64_t lyb_data_size_bits,
429  void *prefix_data, struct lyd_value_union *subvalue, uint32_t *options, struct lys_glob_unres *unres,
430  struct ly_err_item **err)
431 {
432  LY_ERR ret;
433  uint64_t lyb_value_size_bits = 0;
434  uint32_t 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, 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, uint64_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  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
468 {
469  LY_ERR ret = LY_SUCCESS, r;
470  struct lysc_type_union *type_u = (struct lysc_type_union *)type;
471  struct lyd_value_union *subvalue;
472 
473  *err = NULL;
474 
475  /* init storage */
476  memset(storage, 0, sizeof *storage);
477  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, subvalue);
478  LY_CHECK_ERR_GOTO(!subvalue, ret = LY_EMEM, cleanup);
479  storage->realtype = type;
480  subvalue->hints = hints;
481  subvalue->ctx_node = ctx_node;
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  /* store value to subvalue */
488  ret = union_subvalue_assignment(value, value_size_bits, &subvalue->original, &subvalue->orig_size_bits, &options);
489  LY_CHECK_GOTO(ret, cleanup);
490 
491  /* store format-specific data for later prefix resolution */
492  ret = lyplg_type_prefix_data_new(ctx, value, LYPLG_BITS2BYTES(value_size_bits), format, prefix_data,
493  &subvalue->format, &subvalue->prefix_data);
494  LY_CHECK_GOTO(ret, cleanup);
495 
496  /* use the first usable and valid subtype to store the value */
497  ret = union_find_type(ctx, type_u, subvalue, options & ~LYPLG_TYPE_STORE_ONLY, 0, NULL, NULL, NULL, unres, err);
498  if (ret && (ret != LY_EINCOMPLETE) && (options & LYPLG_TYPE_STORE_ONLY)) {
499  /* we tried to find the actual type by validating the value but no type matched, so try to find any type */
500  ly_err_free(*err);
501  *err = NULL;
502  ret = union_find_type(ctx, type_u, subvalue, options, 0, NULL, NULL, NULL, unres, err);
503  }
504  LY_CHECK_GOTO(ret && (ret != LY_EINCOMPLETE), cleanup);
505  }
506 
507  /* store canonical value, if any (use the specific type value) */
508  r = lydict_insert(ctx, subvalue->value._canonical, 0, &storage->_canonical);
509  LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
510 
511 cleanup:
512  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
513  free((void *)value);
514  }
515 
516  if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
517  lyplg_type_free_union(ctx, storage);
518  }
519  return ret;
520 }
521 
522 static LY_ERR
523 lyplg_type_validate_tree_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
524  const struct lyd_node *tree, struct lyd_value *storage, 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, 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, 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, uint64_t *value_size_bits)
635 {
636  void *ret = NULL;
637  LY_ERR r;
638  struct ly_err_item *err;
639  uint64_t pval_size_bits;
640  uint32_t num = 0, type_idx = 0;
641  ly_bool dynamic;
642  void *pval;
643 
644  /* learn the type index, must succeed because have been called before */
645  if (!ctx) {
646  assert(subvalue->ctx_node);
647  ctx = subvalue->ctx_node->module->ctx;
648  }
649  LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->free(ctx, &subvalue->value);
650  r = union_find_type(ctx, type_u, subvalue, 0, 0, NULL, NULL, &type_idx, NULL, &err);
651  ly_err_free(err);
652  LY_CHECK_RET((r != LY_SUCCESS) && (r != LY_EINCOMPLETE), NULL);
653 
654  /* print subvalue in LYB format */
655  pval = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(NULL, &subvalue->value, LY_VALUE_LYB,
656  prefix_data, &dynamic, &pval_size_bits);
657  LY_CHECK_RET(!pval, NULL);
658 
659  /* create LYB data */
660  *value_size_bits = LYPLG_UNION_TYPE_IDX_SIZE * 8 + pval_size_bits;
661  ret = malloc(LYPLG_BITS2BYTES(*value_size_bits));
662  LY_CHECK_RET(!ret, NULL);
663 
664  num = htole32(type_idx);
665  memcpy(ret, &num, LYPLG_UNION_TYPE_IDX_SIZE);
666  memcpy((char *)ret + LYPLG_UNION_TYPE_IDX_SIZE, pval, LYPLG_BITS2BYTES(pval_size_bits));
667 
668  if (dynamic) {
669  free(pval);
670  }
671 
672  return ret;
673 }
674 
675 static const void *
676 lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
677  void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
678 {
679  const void *ret;
680  struct lyd_value_union *subvalue = value->subvalue;
681  struct lysc_type_union *type_u = (struct lysc_type_union *)value->realtype;
682  uint64_t lyb_data_size_bits = 0;
683 
684  if ((format == LY_VALUE_LYB) && (subvalue->format == LY_VALUE_LYB)) {
685  /* The return value is already ready. */
686  *dynamic = 0;
687  if (value_size_bits) {
688  *value_size_bits = subvalue->orig_size_bits;
689  }
690  return subvalue->original;
691  } else if ((format == LY_VALUE_LYB) && (subvalue->format != LY_VALUE_LYB)) {
692  /* The return LYB data must be created. */
693  *dynamic = 1;
694  ret = lyb_union_print(ctx, type_u, subvalue, prefix_data, &lyb_data_size_bits);
695  if (value_size_bits) {
696  *value_size_bits = lyb_data_size_bits;
697  }
698  return ret;
699  }
700 
701  assert(format != LY_VALUE_LYB);
702  ret = (void *)LYSC_GET_TYPE_PLG(subvalue->value.realtype->plugin_ref)->print(ctx, &subvalue->value,
703  format, prefix_data, dynamic, value_size_bits);
704  if (!value->_canonical && (format == LY_VALUE_CANON)) {
705  /* the canonical value is supposed to be stored now */
706  lydict_insert(ctx, subvalue->value._canonical, 0, (const char **)&value->_canonical);
707  }
708 
709  return ret;
710 }
711 
712 static LY_ERR
713 lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
714 {
715  LY_ERR ret = LY_SUCCESS;
716  struct lyd_value_union *orig_val = original->subvalue, *dup_val;
717 
718  /* init dup value */
719  memset(dup, 0, sizeof *dup);
720  dup->realtype = original->realtype;
721 
722  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
723  LY_CHECK_GOTO(ret, cleanup);
724 
725  dup_val = calloc(1, sizeof *dup_val);
726  LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
727  dup->subvalue = dup_val;
728 
729  ret = LYSC_GET_TYPE_PLG(orig_val->value.realtype->plugin_ref)->duplicate(ctx, &orig_val->value, &dup_val->value);
730  LY_CHECK_GOTO(ret, cleanup);
731 
732  if (orig_val->orig_size_bits) {
733  dup_val->original = calloc(1, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
734  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
735  memcpy(dup_val->original, orig_val->original, LYPLG_BITS2BYTES(orig_val->orig_size_bits));
736  } else {
737  dup_val->original = strdup("");
738  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
739  }
740  dup_val->orig_size_bits = orig_val->orig_size_bits;
741 
742  dup_val->format = orig_val->format;
743  dup_val->ctx_node = orig_val->ctx_node;
744  dup_val->hints = orig_val->hints;
745  ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
746  LY_CHECK_GOTO(ret, cleanup);
747 
748 cleanup:
749  if (ret) {
750  lyplg_type_free_union(ctx, dup);
751  }
752  return ret;
753 }
754 
755 static void
756 lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
757 {
758  struct lyd_value_union *val;
759 
760  lydict_remove(ctx, value->_canonical);
761  value->_canonical = NULL;
762  LYD_VALUE_GET(value, val);
763  if (val) {
764  if (val->value.realtype) {
765  LYSC_GET_TYPE_PLG(val->value.realtype->plugin_ref)->free(ctx, &val->value);
766  }
768  free(val->original);
769 
771  }
772 }
773 
782  {
783  .module = "",
784  .revision = NULL,
785  .name = LY_TYPE_UNION_STR,
786 
787  .plugin.id = "ly2 union",
788  .plugin.lyb_size = lyplg_type_lyb_size_variable_bits,
789  .plugin.store = lyplg_type_store_union,
790  .plugin.validate_value = NULL,
791  .plugin.validate_tree = lyplg_type_validate_tree_union,
792  .plugin.compare = lyplg_type_compare_union,
793  .plugin.sort = lyplg_type_sort_union,
794  .plugin.print = lyplg_type_print_union,
795  .plugin.duplicate = lyplg_type_dup_union,
796  .plugin.free = lyplg_type_free_union,
797  },
798  {0}
799 };
struct lysc_type * realtype
Definition: tree_data.h:527
Compiled YANG data node.
Definition: tree_schema.h:1431
#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:2257
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
const char * id
LY_DATA_TYPE basetype
Definition: tree_schema.h:1407
Hold type-specific functions for various operations with the data values.
Generic structure for a data node.
Definition: tree_data.h:783
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:302
#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:269
#define LYPLG_TYPE_STORE_DYNAMIC
void * original
Definition: tree_data.h:581
uintptr_t plugin_ref
Definition: tree_schema.h:1296
#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:308
char * msg
Definition: log.h:304
struct lysc_node * ctx_node
Definition: tree_data.h:588
struct lysc_type ** types
Definition: tree_schema.h:1410
LYPLG_TYPE_VAL_INLINE_DESTROY(val)
Definition: log.h:257
The main libyang public header.
lyplg_type_validate_tree_clb validate_tree
YANG data representation.
Definition: tree_data.h:523
const char * _canonical
Definition: tree_data.h:524
lyplg_type_store_clb store
struct lyxp_expr * path
Definition: tree_schema.h:1376
Libyang full error structure.
Definition: log.h:300
Definition: log.h:292
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:566
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:781
uint32_t hints
Definition: tree_data.h:583
void * prefix_data
Definition: tree_data.h:587
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.
#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:1435
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.
uint64_t orig_size_bits
Definition: tree_data.h:582
#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:1297
Special lyd_value structure for built-in union values.
Definition: tree_data.h:578
API for (user) types plugins.
LY_VALUE_FORMAT format
Definition: tree_data.h:584
libyang context handler.
#define LYPLG_BITS2BYTES(bits)
Convert bits to bytes.
struct lyd_value value
Definition: tree_data.h:579
#define LYPLG_TYPE_STORE_ONLY
assert(!value->_canonical)