libyang 6.4.3
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
Loading...
Searching...
No Matches
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
40static 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
56LIBYANG_API_DEF ly_bool
57lyplg_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
88static void
89bits_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
110static void
111lyplg_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
130static LY_ERR
131bits_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
189static LY_ERR
190bits_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
221static LY_ERR
222bits_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
260static LY_ERR
261bits_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
294static LY_ERR
295lyplg_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
363cleanup:
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
374static LY_ERR
375lyplg_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
391static int
392lyplg_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
405static const void *
406lyplg_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
446static LY_ERR
447lyplg_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
483error:
484 lyplg_type_free_bits(ctx, dup);
485 return ret;
486}
487
488static void
489lyplg_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
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};
const struct lyplg_type_record plugins_bits[]
Plugin information for bits type implementation.
Definition bits.c:510
#define BITS_BITMAP_BYTE(bitmap, size, idx)
Get a specific byte in a bitmap.
Definition bits.c:53
#define BITS_LAST_BIT_POSITION(type_bits)
Get the position of the last bit.
Definition bits.c:45
libyang dictionary
#define LYA_PREALLOC(ARRAY, COUNT, EACTION)
Allocate memory of a sized array or resize an existing array.
Definition ly_array.h:97
#define LYA_INCREMENT(ARRAY)
Increment the items counter of a sized array.
Definition ly_array.h:164
#define LYA_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition ly_array.h:78
#define LYA_FOR(ARRAY, INDEX)
Helper macro to go through sized-arrays with a numeric iterator.
Definition ly_array.h:55
#define LYA_FREE(ARRAY)
Free the space allocated for a sized array.
Definition ly_array.h:197
#define LYA_COUNT_T
Type (i.e. size) of the sized array's size counter.
Definition ly_array.h:38
libyang context handler.
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...
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_zc(const struct ly_ctx *ctx, char *value, const char **str_p)
Insert string into dictionary - zerocopy version. If the string is already present,...
LY_ERR
libyang's error codes returned by the libyang functions.
Definition log.h:252
@ LYVE_DATA
Definition log.h:290
@ LY_EMEM
Definition log.h:254
@ LY_ENOT
Definition log.h:266
@ LY_EVALID
Definition log.h:260
@ LY_SUCCESS
Definition log.h:253
Libyang full error structure.
Definition log.h:298
const char *const char * revision
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
LIBYANG_API_DEF 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
lyplg_lyb_size_type
Type of the LYB size of a value of a particular type.
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's hints (if any) in the specified format.
#define LYPLG_TYPE_VAL_INLINE_DESTROY(type_val)
Destroy a prepared value.
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_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.
#define LYPLG_BITS2BYTES(bits)
Convert bits to bytes.
@ LYPLG_LYB_SIZE_FIXED_BITS
#define LYPLG_TYPE_STORE_DYNAMIC
LY_DATA_TYPE basetype
struct lysc_type_bitenum_item * bits
const char * name
Compiled YANG data node.
uint8_t ly_bool
Type to indicate boolean value.
Definition log.h:36
libyang sized array API.
API for (user) types plugins.
const struct lysc_type * realtype
Definition tree_data.h:614
struct lysc_type_bitenum_item ** items
Definition tree_data.h:685
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition tree_data.h:653
const char * _canonical
Definition tree_data.h:611
YANG data representation.
Definition tree_data.h:610
Special lyd_value structure for built-in binary values.
Definition tree_data.h:692
Special lyd_value structure for built-in bits values.
Definition tree_data.h:681
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition utils.h:93
@ LY_VALUE_CANON
Definition utils.h:94
@ LY_VALUE_LYB
Definition utils.h:100