plugins types FEATURE bits LYB value support
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 56e6ebc..28ec7af 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -39,6 +39,7 @@
struct lysc_pattern;
struct lysc_range;
struct lysc_type;
+struct lysc_type_bits;
struct lysc_type_leafref;
/**
@@ -248,6 +249,27 @@
LY_ERR lyplg_type_make_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
/**
+ * @brief Get the bitmap size of a bits value bitmap.
+ *
+ * Bitmap size is rounded up to the smallest integer size (1, 2, 4, or 8 bytes).
+ * If more than 8 bytes are needed to hold all the bit positions, no rounding is performed.
+ *
+ * @param[in] type Bits type.
+ * @return Bitmap size in bytes.
+ */
+size_t lyplg_type_bits_bitmap_size(const struct lysc_type_bits *type);
+
+/**
+ * @brief Check whether a particular bit of a bitmap is set.
+ *
+ * @param[in] bitmap Bitmap to read from.
+ * @param[in] size Size of @p bitmap.
+ * @param[in] bit_position Bit position to check.
+ * @return Whether the bit is set or not.
+ */
+ly_bool lyplg_type_bits_is_bit_set(const char *bitmap, size_t size, uint32_t bit_position);
+
+/**
* @brief Get format-specific prefix for a module.
*
* Use only in implementations of ::lyplg_type_print_clb which provide all the necessary parameters for this function.
@@ -603,22 +625,35 @@
*/
/**
- * @brief Validate, canonize and store value of the YANG built-in bits type.
- * Implementation of the ::lyplg_type_store_clb.
+ * @brief Implementation of the ::lyplg_type_store_clb for the built-in bits type.
*/
LY_ERR lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
- * @brief Duplication callback of the bits values.
- * Implementation of the ::lyplg_type_dup_clb.
+ * @brief Implementation of the ::lyplg_type_compare_clb for the built-in bits type.
+ */
+LY_ERR lyplg_type_compare_bits(const struct lyd_value *val1, const struct lyd_value *val2);
+
+/**
+ * @brief Implementation of the ::lyplg_type_print_clb for the built-in bits type.
+ */
+const void *lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
+ void *prefix_data, ly_bool *dynamic, size_t *value_len);
+
+/**
+ * @brief Implementation of the ::lyplg_type_hash_clb for the built-in bits type.
+ */
+const void *lyplg_type_hash_bits(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len);
+
+/**
+ * @brief Implementation of the ::lyplg_type_dup_clb for the built-in bits type.
*/
LY_ERR lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
/**
- * @brief Free value of the YANG built-in bits type.
- * Implementation of the ::lyplg_type_free_clb.
+ * @brief Implementation of the ::lyplg_type_free_clb for the built-in bits type.
*/
void lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value);
diff --git a/src/plugins_types/bits.c b/src/plugins_types/bits.c
index a74ada4..bac38e2 100644
--- a/src/plugins_types/bits.c
+++ b/src/plugins_types/bits.c
@@ -12,7 +12,8 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
-#define _GNU_SOURCE
+#define _GNU_SOURCE /* asprintf, strdup */
+#include <sys/cdefs.h>
#include "plugins_types.h"
@@ -29,197 +30,479 @@
#include "compat.h"
#include "plugins_internal.h" /* LY_TYPE_*_STR */
+/**
+ * @page howtoDataLYB LYB Binary Format
+ * @subsection howtoDataLYBTypesBits bits (built-in)
+ *
+ * | Size (B) | Mandatory | Type | Meaning |
+ * | :------ | :-------: | :--: | :-----: |
+ * | returned by ::lyplg_type_bits_bitmap_size() | yes | pointer to integer type of the specific size, if size more than 8 use `char *` | bitmap of the set bits |
+ */
+
+/**
+ * @brief Get the position of the last bit.
+ */
+#define BITS_LAST_BIT_POSITION(type_bits) (type_bits->bits[LY_ARRAY_COUNT(type_bits->bits) - 1].position)
+
+/**
+ * @brief Get a specific byte in a bitmap.
+ */
+#ifdef IS_BIG_ENDIAN
+# define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + (size - 1) - idx)
+#else
+# define BITS_BITMAP_BYTE(bitmap, size, idx) (bitmap + idx)
+#endif
+
+API size_t
+lyplg_type_bits_bitmap_size(const struct lysc_type_bits *type)
+{
+ size_t needed_bytes, size;
+
+ LY_CHECK_ARG_RET(NULL, type, type->basetype == LY_TYPE_BITS, 0);
+
+ /* minimum needed bytes to hold all the bit positions */
+ needed_bytes = (BITS_LAST_BIT_POSITION(type) / 8) + (BITS_LAST_BIT_POSITION(type) % 8 ? 1 : 0);
+ LY_CHECK_ERR_RET(!needed_bytes, LOGINT(NULL), 0);
+
+ if ((needed_bytes == 1) || (needed_bytes == 2)) {
+ /* uint8_t or uint16_t */
+ size = needed_bytes;
+ } else if (needed_bytes < 5) {
+ /* uint32_t */
+ size = 4;
+ } else if (needed_bytes < 9) {
+ /* uint64_t */
+ size = 8;
+ } else {
+ /* no basic type, do not round */
+ size = needed_bytes;
+ }
+
+ return size;
+}
+
+API ly_bool
+lyplg_type_bits_is_bit_set(const char *bitmap, size_t size, uint32_t bit_position)
+{
+ char bitmask;
+
+ /* find the byte with our bit */
+ (void)size;
+ bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
+ bit_position %= 8;
+
+ /* generate bitmask */
+ bitmask = 1;
+ bitmask <<= bit_position;
+
+ /* check if bit set */
+ if (*bitmap & bitmask) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Set bit at a specific position.
+ *
+ * @param[in,out] bitmap Bitmap to modify.
+ * @param[in] size Size of @p bitmap.
+ * @param[in] bit_position Bit position to set.
+ */
+static void
+bits_bit_set(char *bitmap, size_t size, uint32_t bit_position)
+{
+ char bitmask;
+
+ /* find the byte with our bit */
+ (void)size;
+ bitmap = BITS_BITMAP_BYTE(bitmap, size, bit_position / 8);
+ bit_position %= 8;
+
+ /* generate bitmask */
+ bitmask = 1;
+ bitmask <<= bit_position;
+
+ /* set the bit */
+ *bitmap |= bitmask;
+}
+
+/**
+ * @brief Convert a list of bit names separated by whitespaces to a bitmap.
+ *
+ * @param[in] value Value to convert.
+ * @param[in] value_len Length of @p value.
+ * @param[in] type Type of the value.
+ * @param[in,out] bitmap Zeroed bitmap, is filled (set).
+ * @param[out] err Error information.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+bits_str2bitmap(const char *value, size_t value_len, struct lysc_type_bits *type, char *bitmap, struct ly_err_item **err)
+{
+ size_t idx_start, idx_end;
+ LY_ARRAY_COUNT_TYPE u;
+ ly_bool found;
+
+ idx_start = idx_end = 0;
+ while (idx_end < value_len) {
+ /* skip whitespaces */
+ while ((idx_end < value_len) && isspace(value[idx_end])) {
+ ++idx_end;
+ }
+ if (idx_end == value_len) {
+ break;
+ }
+
+ /* parse bit name */
+ idx_start = idx_end;
+ while ((idx_end < value_len) && !isspace(value[idx_end])) {
+ ++idx_end;
+ }
+
+ /* find the bit */
+ found = 0;
+ LY_ARRAY_FOR(type->bits, u) {
+ if (!ly_strncmp(type->bits[u].name, value + idx_start, idx_end - idx_start)) {
+ found = 1;
+ break;
+ }
+ }
+
+ /* check if name exists */
+ if (!found) {
+ return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid bit \"%.*s\".", (int)(idx_end - idx_start),
+ value + idx_start);
+ }
+
+ /* check for duplication */
+ if (lyplg_type_bits_is_bit_set(bitmap, lyplg_type_bits_bitmap_size(type), type->bits[u].position)) {
+ return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Duplicate bit \"%s\".", type->bits[u].name);
+ }
+
+ /* set the bit */
+ bits_bit_set(bitmap, lyplg_type_bits_bitmap_size(type), type->bits[u].position);
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Add a bit item into an array.
+ *
+ * @param[in] position Bit position to add.
+ * @param[in] type Bitis type to read the bit positions and names from.
+ * @param[in,out] items Array of bit item pointers to add to.
+ */
+static void
+bits_add_item(uint32_t position, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items)
+{
+ LY_ARRAY_COUNT_TYPE u;
+
+ /* find the bit item */
+ LY_ARRAY_FOR(type->bits, u) {
+ if (type->bits[u].position == position) {
+ break;
+ }
+ }
+
+ /* add it at the end */
+ items[LY_ARRAY_COUNT(items)] = &type->bits[u];
+ LY_ARRAY_INCREMENT(items);
+}
+
+/**
+ * @brief Convert a bitmap to a sized array of pointers to their bit definitions.
+ *
+ * @param[in] bitmap Bitmap to read from.
+ * @param[in] type Bits type.
+ * @param[in,out] items Allocated sized array to fill with the set bits.
+ */
+static void
+bits_bitmap2items(const char *bitmap, struct lysc_type_bits *type, struct lysc_type_bitenum_item **items)
+{
+ size_t i, bitmap_size = lyplg_type_bits_bitmap_size(type);
+ uint32_t bit_pos;
+ char bitmask;
+ const char *byte;
+
+ bit_pos = 0;
+ for (i = 0; i < bitmap_size; ++i) {
+ /* check this byte (but not necessarily all bits in the last byte) */
+ byte = BITS_BITMAP_BYTE(bitmap, bitmap_size, i);
+ for (bitmask = 1; bitmask; bitmask <<= 1) {
+ if (*byte & bitmask) {
+ /* add this bit */
+ bits_add_item(bit_pos, type, items);
+ }
+
+ if (bit_pos == BITS_LAST_BIT_POSITION(type)) {
+ /* we have checked the last valid bit */
+ break;
+ }
+
+ ++bit_pos;
+ }
+ }
+}
+
+/**
+ * @brief Generate canonical value from ordered array of set bit items.
+ *
+ * @param[in] items Sized array of set bit items.
+ * @param[out] canonical Canonical string value.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+bits_items2canon(struct lysc_type_bitenum_item **items, char **canonical)
+{
+ char *ret;
+ size_t ret_len;
+ LY_ARRAY_COUNT_TYPE u;
+
+ *canonical = NULL;
+
+ /* init value */
+ ret = strdup("");
+ LY_CHECK_RET(!ret, LY_EMEM);
+ ret_len = 0;
+
+ LY_ARRAY_FOR(items, u) {
+ if (!ret_len) {
+ ret = ly_realloc(ret, strlen(items[u]->name) + 1);
+ LY_CHECK_RET(!ret, LY_EMEM);
+ strcpy(ret, items[u]->name);
+
+ ret_len = strlen(ret);
+ } else {
+ ret = ly_realloc(ret, ret_len + 1 + strlen(items[u]->name) + 1);
+ LY_CHECK_RET(!ret, LY_EMEM);
+ sprintf(ret + ret_len, " %s", items[u]->name);
+
+ ret_len += 1 + strlen(items[u]->name);
+ }
+ }
+
+ *canonical = ret;
+ return LY_SUCCESS;
+}
+
API LY_ERR
lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT UNUSED(format), void *UNUSED(prefix_data), uint32_t hints,
+ uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
struct ly_err_item **err)
{
LY_ERR ret = LY_SUCCESS;
struct lysc_type_bits *type_bits = (struct lysc_type_bits *)type;
- struct lysc_type_bitenum_item **bits_items = NULL;
- struct ly_set *items = NULL;
- const char *value_str = value;
+ struct lyd_value_bits *val;
- uint32_t index_start; /* start index of bit name */
- uint32_t index_end = 0; /* end index of bit name */
- uint32_t item_len; /* length of bit name */
- uint32_t buf_len = 0;
- uint32_t item_pos;
- uint32_t item_pos_expected;
- char *buf = NULL;
- const char *item = NULL;
+ /* clear storage */
+ memset(storage, 0, sizeof *storage);
- ly_bool item_present;
- LY_ARRAY_COUNT_TYPE item_present_index;
- LY_ARRAY_COUNT_TYPE it;
+ if (format == LY_VALUE_LYB) {
+ /* validation */
+ if (value_len != lyplg_type_bits_bitmap_size(type_bits)) {
+ ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB bits value size %zu (expected %zu).",
+ value_len, lyplg_type_bits_bitmap_size(type_bits));
+ goto cleanup;
+ }
- *err = NULL;
+ /* allocate the value */
+ val = malloc(sizeof *val);
+ LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);
+
+ /* init storage */
+ storage->_canonical = NULL;
+ storage->ptr = val;
+ storage->realtype = type;
+
+ /* store value (bitmap) */
+ if (options & LYPLG_TYPE_STORE_DYNAMIC) {
+ val->bitmap = (char *)value;
+ options &= ~LYPLG_TYPE_STORE_DYNAMIC;
+ } else {
+ val->bitmap = malloc(value_len);
+ LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
+ memcpy(val->bitmap, value, value_len);
+ }
+
+ /* allocate and fill the bit item array */
+ LY_ARRAY_CREATE_GOTO(ctx, val->items, LY_ARRAY_COUNT(type_bits->bits), ret, cleanup);
+ bits_bitmap2items(val->bitmap, type_bits, val->items);
+
+ /* success */
+ goto cleanup;
+ }
/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
- LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup_value);
+ LY_CHECK_GOTO(ret, cleanup);
- /* remember the present items for further work */
- ret = ly_set_new(&items);
- LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup_value);
+ /* allocate the value */
+ val = calloc(1, sizeof *val);
+ LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);
- /* get all values */
- while (index_end < value_len) {
- /* skip leading spaces */
- index_start = index_end;
- while ((index_start < value_len) && isspace(value_str[index_start])) {
- index_start++;
- }
-
- index_end = index_start;
- /* find end of word */
- while ((index_end < value_len) && !isspace(value_str[index_end])) {
- index_end++;
- }
-
- /* check if name of bit is valid */
- item = &value_str[index_start];
- item_len = index_end - index_start;
- if (item_len == 0) {
- /* loop read all bits names*/
- break;
- }
-
- /* looking for correct name */
- item_present = 0;
- LY_ARRAY_FOR(type_bits->bits, it) {
- if (!ly_strncmp(type_bits->bits[it].name, item, item_len)) {
- item_present = 1;
- item_present_index = it;
- }
- }
-
- /* check if name exists */
- if (!item_present) {
- ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
- "Invalid bit value \"%.*s\".", (int)item_len, item);
- goto cleanup;
- }
-
- /* add item to set */
- item_pos_expected = items->count;
- ret = ly_set_add(items, &type_bits->bits[item_present_index], 0, &item_pos);
- LY_CHECK_GOTO(ret, cleanup);
- if (item_pos != item_pos_expected) {
- ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
- "Bit \"%s\" used multiple times.", type_bits->bits[item_present_index].name);
- goto cleanup;
- }
- /* count require buff size */
- buf_len += item_len + 1;
- }
-
- /* creating buffer for cannonical value */
- if (buf_len != 0) {
- uint32_t buf_index = 0;
- LY_ARRAY_COUNT_TYPE it;
-
- /* create space for cannonical value and array for bits*/
- buf = malloc(buf_len * sizeof *buf);
- if (buf == NULL) {
- ret = LY_EMEM;
- LOGMEM(ctx);
- goto cleanup;
- }
- LY_ARRAY_CREATE_GOTO(ctx, bits_items, items->count, ret, cleanup);
-
- /* generate ordered bits list and cannonical value*/
- LY_ARRAY_FOR(type_bits->bits, it) {
- if (ly_set_contains(items, &type_bits->bits[it], NULL)) {
- uint32_t name_index = 0;
-
- /* write space */
- if (buf_index != 0) {
- buf[buf_index] = ' ';
- buf_index++;
- }
-
- /* write bit name*/
- while (type_bits->bits[it].name[name_index]) {
- buf[buf_index] = type_bits->bits[it].name[name_index];
- buf_index++;
- name_index++;
- }
-
- bits_items[LY_ARRAY_COUNT(bits_items)] = &type_bits->bits[it];
- LY_ARRAY_INCREMENT(bits_items);
- }
- }
- buf[buf_index] = 0;
-
- ret = lydict_insert_zc(ctx, buf, &storage->_canonical);
- buf = NULL;
- LY_CHECK_GOTO(ret, cleanup);
- } else {
- bits_items = NULL;
- ret = lydict_insert(ctx, "", 0, &storage->_canonical);
- buf = NULL;
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* store value */
- storage->bits_items = bits_items;
+ /* init storage */
+ storage->_canonical = NULL;
+ storage->ptr = val;
storage->realtype = type;
- /* RETURN LY_SUCCESS */
- ly_set_free(items, NULL);
+ /* allocate the bitmap */
+ val->bitmap = malloc(lyplg_type_bits_bitmap_size(type_bits));
+ LY_CHECK_ERR_GOTO(!val->bitmap, ret = LY_EMEM, cleanup);
+ memset(val->bitmap, 0, lyplg_type_bits_bitmap_size(type_bits));
+
+ /* fill the bitmap */
+ ret = bits_str2bitmap(value, value_len, type_bits, val->bitmap, err);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* allocate and fill the bit item array */
+ LY_ARRAY_CREATE_GOTO(ctx, val->items, LY_ARRAY_COUNT(type_bits->bits), ret, cleanup);
+ bits_bitmap2items(val->bitmap, type_bits, val->items);
+
+ if (format == LY_VALUE_CANON) {
+ /* store canonical value */
+ if (options & LYPLG_TYPE_STORE_DYNAMIC) {
+ ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
+ options &= ~LYPLG_TYPE_STORE_DYNAMIC;
+ LY_CHECK_GOTO(ret, cleanup);
+ } else {
+ ret = lydict_insert(ctx, value_len ? value : "", value_len, &storage->_canonical);
+ LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
+ }
+ }
+
+cleanup:
if (options & LYPLG_TYPE_STORE_DYNAMIC) {
- free((char *)value);
+ free((void *)value);
+ }
+
+ if (ret) {
+ lyplg_type_free_bits(ctx, storage);
+ }
+ return ret;
+}
+
+API LY_ERR
+lyplg_type_compare_bits(const struct lyd_value *val1, const struct lyd_value *val2)
+{
+ struct lyd_value_bits *v1 = val1->ptr, *v2 = val2->ptr;
+ struct lysc_type_bits *type_bits = (struct lysc_type_bits *)val1->realtype;
+
+ if (val1->realtype != val2->realtype) {
+ return LY_ENOT;
+ }
+
+ if (memcmp(v1->bitmap, v2->bitmap, lyplg_type_bits_bitmap_size(type_bits))) {
+ return LY_ENOT;
}
return LY_SUCCESS;
+}
- /* ERROR HANDLING */
-cleanup:
- LY_ARRAY_FREE(bits_items);
- free(buf);
- ly_set_free(items, NULL);
-cleanup_value:
- if (options & LYPLG_TYPE_STORE_DYNAMIC) {
- free((char *)value);
+API const void *
+lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
+ void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len)
+{
+ struct lysc_type_bits *type_bits = (struct lysc_type_bits *)value->realtype;
+ struct lyd_value_bits *val = value->ptr;
+ char *ret;
+
+ if (format == LY_VALUE_LYB) {
+ *dynamic = 0;
+ if (value_len) {
+ *value_len = lyplg_type_bits_bitmap_size(type_bits);
+ }
+ return val->bitmap;
}
- return ret;
+ /* generate canonical value if not already */
+ if (!value->_canonical) {
+ /* get the canonical value */
+ if (bits_items2canon(val->items, &ret)) {
+ return NULL;
+ }
+
+ /* store it */
+ if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) {
+ LOGMEM(ctx);
+ return NULL;
+ }
+ }
+
+ /* use the cached canonical value */
+ if (dynamic) {
+ *dynamic = 0;
+ }
+ if (value_len) {
+ *value_len = strlen(value->_canonical);
+ }
+ return value->_canonical;
+}
+
+API const void *
+lyplg_type_hash_bits(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len)
+{
+ struct lysc_type_bits *type_bits = (struct lysc_type_bits *)value->realtype;
+ struct lyd_value_bits *val = value->ptr;
+
+ /* return the bitmap */
+ *dynamic = 0;
+ *key_len = lyplg_type_bits_bitmap_size(type_bits);
+ return val->bitmap;
}
API LY_ERR
lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR ret;
+ struct lysc_type_bits *type_bits = (struct lysc_type_bits *)original->realtype;
LY_ARRAY_COUNT_TYPE u;
- struct lysc_type_bitenum_item **bits_items = NULL;
+ struct lyd_value_bits *orig_val = original->ptr, *dup_val;
- LY_ARRAY_CREATE_RET(ctx, bits_items, LY_ARRAY_COUNT(original->bits_items), LY_EMEM);
- LY_ARRAY_FOR(original->bits_items, u) {
- LY_ARRAY_INCREMENT(bits_items);
- bits_items[u] = original->bits_items[u];
+ memset(dup, 0, sizeof *dup);
+
+ /* optional canonical value */
+ ret = lydict_insert(ctx, original->_canonical, ly_strlen(original->_canonical), &dup->_canonical);
+ LY_CHECK_GOTO(ret, error);
+
+ /* allocate value */
+ dup_val = calloc(1, sizeof *dup_val);
+ LY_CHECK_ERR_GOTO(!dup_val, ret = LY_EMEM, error);
+ dup->ptr = dup_val;
+
+ /* duplicate bitmap */
+ dup_val->bitmap = malloc(lyplg_type_bits_bitmap_size(type_bits));
+ LY_CHECK_ERR_GOTO(!dup_val->bitmap, ret = LY_EMEM, error);
+ memcpy(dup_val->bitmap, orig_val->bitmap, lyplg_type_bits_bitmap_size(type_bits));
+
+ /* duplicate bit item pointers */
+ LY_ARRAY_CREATE_GOTO(ctx, dup_val->items, LY_ARRAY_COUNT(orig_val->items), ret, error);
+ LY_ARRAY_FOR(orig_val->items, u) {
+ LY_ARRAY_INCREMENT(dup_val->items);
+ dup_val->items[u] = orig_val->items[u];
}
- ret = lydict_insert(ctx, original->_canonical, strlen(original->_canonical), &dup->_canonical);
- LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
- dup->bits_items = bits_items;
+ dup->ptr = dup_val;
dup->realtype = original->realtype;
return LY_SUCCESS;
- /* ERROR HANDLING */
-cleanup:
- LY_ARRAY_FREE(bits_items);
+error:
+ lyplg_type_free_bits(ctx, dup);
return ret;
}
API void
lyplg_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value)
{
- LY_ARRAY_FREE(value->bits_items);
- value->bits_items = NULL;
+ struct lyd_value_bits *val = value->ptr;
lydict_remove(ctx, value->_canonical);
- value->_canonical = NULL;
+ if (val) {
+ free(val->bitmap);
+ LY_ARRAY_FREE(val->items);
+ free(val);
+ }
}
/**
@@ -238,9 +521,9 @@
.plugin.id = "libyang 2 - bits, version 1",
.plugin.store = lyplg_type_store_bits,
.plugin.validate = NULL,
- .plugin.compare = lyplg_type_compare_simple,
- .plugin.print = lyplg_type_print_simple,
- .plugin.hash = lyplg_type_hash_simple,
+ .plugin.compare = lyplg_type_compare_bits,
+ .plugin.print = lyplg_type_print_bits,
+ .plugin.hash = lyplg_type_hash_bits,
.plugin.duplicate = lyplg_type_dup_bits,
.plugin.free = lyplg_type_free_bits
},
diff --git a/src/tree_data.h b/src/tree_data.h
index f6ecbf1..3d5ddc7 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -535,7 +535,7 @@
uint32_t uint32; /**< 32-bit unsigned integer */
uint64_t uint64; /**< 64-bit unsigned integer */
struct lysc_type_bitenum_item *enum_item; /**< pointer to the definition of the enumeration value */
- struct lysc_type_bitenum_item **bits_items; /**< list of set pointers to the specification of the set bits ([sized array](@ref sizedarrays)) */
+ struct lyd_value_bits *bits; /**< bits value */
struct lysc_ident *ident; /**< pointer to the schema definition of the identityref value */
struct ly_path *target; /**< Instance-identifier target path. */
struct lyd_value_subvalue *subvalue; /** Union value with some metadata. */
@@ -573,6 +573,20 @@
};
/**
+ * @brief Special lyd_value structure for bits.
+ *
+ * Note that the allocate memory is rounded to bytes. Meaning that if a type defines a bit with the highest position
+ * 18, for example, only 3 bytes will be allocated and casting to a 4-byte type will not work!
+ */
+struct lyd_value_bits {
+ char *bitmap; /**< bitmap of size ::lyplg_type_bits_bitmap_size(), if its value is
+ cast to an integer type of the corresponding size, can be used
+ directly as a bitmap */
+ struct lysc_type_bitenum_item **items; /**< list of set pointers to the specification of the set
+ bits ([sized array](@ref sizedarrays)) */
+};
+
+/**
* @brief Special lyd_value structure for binary.
*
* Represents an arbitrary binary value.
diff --git a/tests/utests/types/bits.c b/tests/utests/types/bits.c
index 437c9ab..7688967 100644
--- a/tests/utests/types/bits.c
+++ b/tests/utests/types/bits.c
@@ -586,13 +586,13 @@
TEST_SUCCESS_XML("T0", "\n\t", BITS, "");
TEST_ERROR_XML("T0", "twelvea");
- CHECK_LOG_CTX("Invalid bit value \"twelvea\".",
+ CHECK_LOG_CTX("Invalid bit \"twelvea\".",
"Schema location /T0:port, line number 1.");
TEST_ERROR_XML("T0", "twelve t");
- CHECK_LOG_CTX("Invalid bit value \"t\".",
+ CHECK_LOG_CTX("Invalid bit \"t\".",
"Schema location /T0:port, line number 1.");
TEST_ERROR_XML("T0", "ELEVEN");
- CHECK_LOG_CTX("Invalid bit value \"ELEVEN\".",
+ CHECK_LOG_CTX("Invalid bit \"ELEVEN\".",
"Schema location /T0:port, line number 1.");
/* empty value */
diff --git a/tests/utests/utests.h b/tests/utests/utests.h
index 9b15c05..e71a8d7 100644
--- a/tests/utests/utests.h
+++ b/tests/utests/utests.h
@@ -929,9 +929,9 @@
{ \
const char *arr[] = { __VA_ARGS__ }; \
LY_ARRAY_COUNT_TYPE arr_size = sizeof(arr) / sizeof(arr[0]); \
- assert_int_equal(arr_size, LY_ARRAY_COUNT((NODE).bits_items)); \
+ assert_int_equal(arr_size, LY_ARRAY_COUNT(((struct lyd_value_bits *)(NODE).ptr)->items)); \
for (LY_ARRAY_COUNT_TYPE it = 0; it < arr_size; it++) { \
- assert_string_equal(arr[it], (NODE).bits_items[it]->name); \
+ assert_string_equal(arr[it], ((struct lyd_value_bits *)(NODE).ptr)->items[it]->name); \
} \
}