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
bits.c
Go to the documentation of this file.
1 
16 #define _GNU_SOURCE /* strdup */
17 
18 #include "plugins_types.h"
19 
20 #include <ctype.h>
21 #include <stdint.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 "plugins_internal.h"
30 
40 static void lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value);
41 
45 #define BITS_LAST_BIT_POSITION(type_bits) ((type_bits)->bits[LYA_COUNT((type_bits)->bits) - 1].position)
46 
50 #ifdef IS_BIG_ENDIAN
51 # define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + (size - 1) - idx)
52 #else
53 # define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + idx)
54 #endif
55 
56 LIBYANG_API_DEF ly_bool
57 lyplg_type_bits_is_bit_set(const char *bitmap, uint32_t size_bits, uint32_t bit_position)
58 {
59  char bitmask;
60  uint32_t size;
61 
62  /* get size in bytes */
63  size = size_bits / 8 + ((size_bits % 8) ? 1 : 0);
64 
65  /* find the byte with our bit */
66  (void)size;
67  bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
68  bit_position %= 8;
69 
70  /* generate bitmask */
71  bitmask = 1;
72  bitmask <<= bit_position;
73 
74  /* check if bit set */
75  if (*bitmap & bitmask) {
76  return 1;
77  }
78  return 0;
79 }
80 
88 static void
89 bits_bit_set(char *bitmap, uint32_t size_bits, uint32_t bit_position)
90 {
91  char bitmask;
92  uint32_t size;
93 
94  /* get size in bytes */
95  size = size_bits / 8 + ((size_bits % 8) ? 1 : 0);
96 
97  /* find the byte with our bit */
98  (void)size;
99  bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
100  bit_position %= 8;
101 
102  /* generate bitmask */
103  bitmask = 1;
104  bitmask <<= bit_position;
105 
106  /* set the bit */
107  *bitmap |= bitmask;
108 }
109 
110 static void
111 lyplg_type_lyb_size_bits(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint64_t *fixed_size_bits)
112 {
113  const struct lysc_type_bits *type_bits = (struct lysc_type_bits *)type;
114 
115  /* position of the last bit, positions start at 0, add 1 */
116  *size_type = LYPLG_LYB_SIZE_FIXED_BITS;
117  *fixed_size_bits = BITS_LAST_BIT_POSITION(type_bits) + 1;
118 }
119 
130 static LY_ERR
131 bits_str2bitmap(const char *value, uint32_t value_len, struct lysc_type_bits *type, char *bitmap, struct ly_err_item **err)
132 {
133  uint32_t idx_start, idx_end;
134  LYA_COUNT_T u;
135  ly_bool found;
136 
137  idx_start = idx_end = 0;
138  while (idx_end < value_len) {
139  /* skip whitespaces */
140  while ((idx_end < value_len) && isspace(value[idx_end])) {
141  ++idx_end;
142  }
143  if (idx_end == value_len) {
144  break;
145  }
146 
147  /* parse bit name */
148  idx_start = idx_end;
149  while ((idx_end < value_len) && !isspace(value[idx_end])) {
150  ++idx_end;
151  }
152 
153  /* find the bit */
154  found = 0;
155  LYA_FOR(type->bits, u) {
156  if (!ly_strncmp(type->bits[u].name, value + idx_start, idx_end - idx_start)) {
157  found = 1;
158  break;
159  }
160  }
161 
162  /* check if name exists */
163  if (!found) {
164  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid bit \"%.*s\".", (int)(idx_end - idx_start),
165  value + idx_start);
166  }
167 
168  /* check for duplication */
169  if (lyplg_type_bits_is_bit_set(bitmap, BITS_LAST_BIT_POSITION(type) + 1, type->bits[u].position)) {
170  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Duplicate bit \"%s\".", type->bits[u].name);
171  }
172 
173  /* set the bit */
174  bits_bit_set(bitmap, BITS_LAST_BIT_POSITION(type) + 1, type->bits[u].position);
175  }
176 
177  return LY_SUCCESS;
178 }
179 
189 static LY_ERR
190 bits_add_item(uint32_t position, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items,
191  struct ly_err_item **err)
192 {
193  LYA_COUNT_T u;
194 
195  /* find the bit item */
196  LYA_FOR(type->bits, u) {
197  if (type->bits[u].position == position) {
198  break;
199  }
200  }
201  if (u == LYA_COUNT(type->bits)) {
202  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid bit at position #%" PRIu32 ".", position);
203  }
204 
205  /* add it at the end */
206  items[LYA_COUNT(items)] = &type->bits[u];
207  LYA_INCREMENT(items);
208 
209  return LY_SUCCESS;
210 }
211 
221 static LY_ERR
222 bits_bitmap2items(const char *bitmap, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items,
223  struct ly_err_item **err)
224 {
225  uint32_t bit_pos, i, bitmap_size;
226  uint8_t bitmask;
227  const uint8_t *byte;
228 
229  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION(type) + 1);
230 
231  bit_pos = 0;
232  for (i = 0; i < bitmap_size; ++i) {
233  /* check this byte (but not necessarily all bits in the last byte) */
234  byte = (uint8_t *)BITS_BITMAP_BYTE(bitmap, bitmap_size, i);
235  for (bitmask = 1; bitmask; bitmask <<= 1) {
236  if (*byte & bitmask) {
237  /* add this bit */
238  LY_CHECK_RET(bits_add_item(bit_pos, type, items, err));
239  }
240 
241  if (bit_pos == BITS_LAST_BIT_POSITION(type)) {
242  /* we have checked the last valid bit */
243  break;
244  }
245 
246  ++bit_pos;
247  }
248  }
249 
250  return LY_SUCCESS;
251 }
252 
260 static LY_ERR
261 bits_items2canon(struct lysc_type_bitenum_item **items, char **canonical)
262 {
263  char *ret;
264  uint32_t ret_len;
265  LYA_COUNT_T u;
266 
267  *canonical = NULL;
268 
269  /* init value */
270  ret = strdup("");
271  LY_CHECK_RET(!ret, LY_EMEM);
272  ret_len = 0;
273 
274  LYA_FOR(items, u) {
275  if (!ret_len) {
276  ret = ly_realloc(ret, strlen(items[u]->name) + 1);
277  LY_CHECK_RET(!ret, LY_EMEM);
278  strcpy(ret, items[u]->name);
279 
280  ret_len = strlen(ret);
281  } else {
282  ret = ly_realloc(ret, ret_len + 1 + strlen(items[u]->name) + 1);
283  LY_CHECK_RET(!ret, LY_EMEM);
284  sprintf(ret + ret_len, " %s", items[u]->name);
285 
286  ret_len += 1 + strlen(items[u]->name);
287  }
288  }
289 
290  *canonical = ret;
291  return LY_SUCCESS;
292 }
293 
294 static LY_ERR
295 lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
296  uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
297  const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
298  struct ly_err_item **err)
299 {
300  LY_ERR ret = LY_SUCCESS;
301  struct lysc_type_bits *type_bits = (struct lysc_type_bits *)type;
302  struct lyd_value_bits *val;
303  uint32_t value_size;
304 
305  /* init storage */
306  memset(storage, 0, sizeof *storage);
307  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
308  LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);
309  storage->realtype = type;
310 
311  /* check value length */
312  ret = lyplg_type_check_value_size("bits", format, value_size_bits, LYPLG_LYB_SIZE_FIXED_BITS,
313  BITS_LAST_BIT_POSITION(type_bits) + 1, &value_size, err);
314  LY_CHECK_GOTO(ret, cleanup);
315 
316  if (format == LY_VALUE_LYB) {
317  /* store value (bitmap) */
318  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
319  val->bitmap = (char *)value;
320  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
321  } else {
322  val->bitmap = malloc(value_size);
323  LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
324  memcpy(val->bitmap, value, value_size);
325  }
326 
327  /* allocate and fill the bit item array */
328  LYA_PREALLOC(val->items, LYA_COUNT(type_bits->bits), LOGMEM(ctx); ret = LY_EMEM; goto cleanup);
329  LY_CHECK_GOTO(ret = bits_bitmap2items(val->bitmap, type_bits, val->items, err), cleanup);
330 
331  /* success */
332  goto cleanup;
333  }
334 
335  /* check hints */
336  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
337  LY_CHECK_GOTO(ret, cleanup);
338 
339  /* allocate the bitmap */
340  val->bitmap = calloc(1, LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION(type_bits) + 1));
341  LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
342 
343  /* fill the bitmap */
344  ret = bits_str2bitmap(value, value_size, type_bits, val->bitmap, err);
345  LY_CHECK_GOTO(ret, cleanup);
346 
347  /* allocate and fill the bit item array */
348  LYA_PREALLOC(val->items, LYA_COUNT(type_bits->bits), LOGMEM(ctx); ret = LY_EMEM; goto cleanup);
349  LY_CHECK_GOTO(ret = bits_bitmap2items(val->bitmap, type_bits, val->items, err), cleanup);
350 
351  if (format == LY_VALUE_CANON) {
352  /* store canonical value */
353  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
354  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
355  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
356  LY_CHECK_GOTO(ret, cleanup);
357  } else {
358  ret = lydict_insert(ctx, value_size ? value : "", value_size, &storage->_canonical);
359  LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
360  }
361  }
362 
363 cleanup:
364  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
365  free((void *)value);
366  }
367 
368  if (ret) {
369  lyplg_type_free_bits(ctx, storage);
370  }
371  return ret;
372 }
373 
374 static LY_ERR
375 lyplg_type_compare_bits(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
376 {
377  struct lyd_value_bits *v1, *v2;
378  uint32_t bitmap_size;
379 
380  LYD_VALUE_GET(val1, v1);
381  LYD_VALUE_GET(val2, v2);
382 
383  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION((struct lysc_type_bits *)val1->realtype) + 1);
384 
385  if (memcmp(v1->bitmap, v2->bitmap, bitmap_size)) {
386  return LY_ENOT;
387  }
388  return LY_SUCCESS;
389 }
390 
391 static int
392 lyplg_type_sort_bits(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
393 {
394  struct lyd_value_binary *v1, *v2;
395  uint32_t bitmap_size;
396 
397  LYD_VALUE_GET(val1, v1);
398  LYD_VALUE_GET(val2, v2);
399 
400  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION((struct lysc_type_bits *)val1->realtype) + 1);
401 
402  return memcmp(v1->data, v2->data, bitmap_size);
403 }
404 
405 static const void *
406 lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
407  void *UNUSED(prefix_data), ly_bool *dynamic, uint64_t *value_len_bits)
408 {
409  struct lyd_value_bits *val;
410  char *ret;
411 
412  LYD_VALUE_GET(value, val);
413 
414  if (format == LY_VALUE_LYB) {
415  *dynamic = 0;
416  if (value_len_bits) {
417  *value_len_bits = BITS_LAST_BIT_POSITION((struct lysc_type_bits *)value->realtype) + 1;
418  }
419  return val->bitmap;
420  }
421 
422  /* generate canonical value if not already */
423  if (!value->_canonical) {
424  /* get the canonical value */
425  if (bits_items2canon(val->items, &ret)) {
426  return NULL;
427  }
428 
429  /* store it */
430  if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) {
431  LOGMEM(ctx);
432  return NULL;
433  }
434  }
435 
436  /* use the cached canonical value */
437  if (dynamic) {
438  *dynamic = 0;
439  }
440  if (value_len_bits) {
441  *value_len_bits = strlen(value->_canonical) * 8;
442  }
443  return value->_canonical;
444 }
445 
446 static LY_ERR
447 lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
448 {
449  LY_ERR ret;
450  LYA_COUNT_T u;
451  struct lyd_value_bits *orig_val, *dup_val;
452  uint32_t bitmap_size;
453 
454  memset(dup, 0, sizeof *dup);
455 
456  bitmap_size = LYPLG_BITS2BYTES(BITS_LAST_BIT_POSITION((struct lysc_type_bits *)original->realtype) + 1);
457 
458  /* optional canonical value */
459  ret = lydict_insert(ctx, original->_canonical, 0, &dup->_canonical);
460  LY_CHECK_GOTO(ret, error);
461 
462  /* allocate value */
463  LYPLG_TYPE_VAL_INLINE_PREPARE(dup, dup_val);
464  LY_CHECK_ERR_GOTO(!dup_val, ret = LY_EMEM, error);
465 
466  LYD_VALUE_GET(original, orig_val);
467 
468  /* duplicate bitmap */
469  dup_val->bitmap = malloc(bitmap_size);
470  LY_CHECK_ERR_GOTO(!dup_val->bitmap, ret = LY_EMEM, error);
471  memcpy(dup_val->bitmap, orig_val->bitmap, bitmap_size);
472 
473  /* duplicate bit item pointers */
474  LYA_PREALLOC(dup_val->items, LYA_COUNT(orig_val->items), LOGMEM(ctx); ret = LY_EMEM; goto error);
475  LYA_FOR(orig_val->items, u) {
476  LYA_INCREMENT(dup_val->items);
477  dup_val->items[u] = orig_val->items[u];
478  }
479 
480  dup->realtype = original->realtype;
481  return LY_SUCCESS;
482 
483 error:
484  lyplg_type_free_bits(ctx, dup);
485  return ret;
486 }
487 
488 static void
489 lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value)
490 {
491  struct lyd_value_bits *val;
492 
493  lydict_remove(ctx, value->_canonical);
494  value->_canonical = NULL;
495  LYD_VALUE_GET(value, val);
496  if (val) {
497  free(val->bitmap);
498  LYA_FREE(val->items);
500  }
501 }
502 
510 const struct lyplg_type_record plugins_bits[] = {
511  {
512  .module = "",
513  .revision = NULL,
514  .name = LY_TYPE_BITS_STR,
515 
516  .plugin.id = "ly2 bits",
517  .plugin.lyb_size = lyplg_type_lyb_size_bits,
518  .plugin.store = lyplg_type_store_bits,
519  .plugin.validate_value = NULL,
520  .plugin.validate_tree = NULL,
521  .plugin.compare = lyplg_type_compare_bits,
522  .plugin.sort = lyplg_type_sort_bits,
523  .plugin.print = lyplg_type_print_bits,
524  .plugin.duplicate = lyplg_type_dup_bits,
525  .plugin.free = lyplg_type_free_bits,
526  },
527  {0}
528 };
#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
LIBYANG_API_DECL ly_bool lyplg_type_bits_is_bit_set(const char *bitmap, uint32_t size_bits, uint32_t bit_position)
Check whether a particular bit of a bitmap is set.
Definition: bits.c:57
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 lysc_type_bitenum_item * bits
Definition: tree_schema.h:1364
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
lyplg_lyb_size_type
Type of the LYB size of a value of a particular type.
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
LIBYANG_API_DECL LY_ERR lyplg_type_check_value_size(const char *type_name, LY_VALUE_FORMAT format, uint64_t value_size_bits, enum lyplg_lyb_size_type lyb_size_type, uint64_t lyb_fixed_size_bits, uint32_t *value_size, struct ly_err_item **err)
Check a value type in bits is correct and as expected.
libyang dictionary
Definition: log.h:269
#define LYPLG_TYPE_STORE_DYNAMIC
#define BITS_BITMAP_BYTE(bitmap, size, idx)
Get a specific byte in a bitmap.
Definition: bits.c:53
struct lyplg_type_record plugins_bits[]
Plugin information for bits type implementation.
Definition: bits.c:510
const char * name
Definition: tree_schema.h:1358
uint32_t bitmap_size
Definition: bits.c:378
LYPLG_TYPE_VAL_INLINE_DESTROY(val)
Definition: log.h:257
struct lysc_type_bitenum_item ** items
Definition: tree_data.h:685
#define BITS_LAST_BIT_POSITION(type_bits)
Get the position of the last bit.
Definition: bits.c:45
YANG data representation.
Definition: tree_data.h:610
const char * _canonical
Definition: tree_data.h:611
#define LYA_FREE(ARRAY)
Free the space allocated for a sized array.
Definition: ly_array.h:199
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 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 sized array API.
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
const char * module
#define LYA_INCREMENT(ARRAY)
Increment the items counter of a sized array.
Definition: ly_array.h:166
LIBYANG_API_DECL LY_ERR lydict_insert_zc(const struct ly_ctx *ctx, char *value, const char **str_p)
Insert string into dictionary - zerocopy version. If the string is already present, only a reference counter is incremented and no memory allocation is performed. This insert function variant avoids duplication of specified value - it is inserted into the dictionary directly.
#define LYA_PREALLOC(ARRAY, COUNT, EACTION)
Allocate memory of a sized array or resize an existing array.
Definition: ly_array.h:97
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: utils.h:93
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
char * bitmap
Definition: tree_data.h:682
LY_DATA_TYPE basetype
Definition: tree_schema.h:1296
return memcmp(v1->data, v2->data, bitmap_size)
Special lyd_value structure for built-in bits values.
Definition: tree_data.h:681
LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, uint32_t value_len, LY_DATA_TYPE type, int *base, struct ly_err_item **err)
Check that the type is suitable for the parser&#39;s hints (if any) in the specified format.
API for (user) types plugins.
libyang context handler.
#define LYPLG_BITS2BYTES(bits)
Convert bits to bytes.
Special lyd_value structure for built-in binary values.
Definition: tree_data.h:692