diff options
Diffstat (limited to '')
-rw-r--r-- | src/plugins_types/enumeration.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/plugins_types/enumeration.c b/src/plugins_types/enumeration.c new file mode 100644 index 0000000..91ca822 --- /dev/null +++ b/src/plugins_types/enumeration.c @@ -0,0 +1,202 @@ +/** + * @file enumeration.c + * @author Radek Krejci <rkrejci@cesnet.cz> + * @brief Built-in enumeration type plugin. + * + * Copyright (c) 2019-2021 CESNET, z.s.p.o. + * + * This source code is licensed under BSD 3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + */ + +#define _GNU_SOURCE /* strdup */ + +#include "plugins_types.h" + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "libyang.h" + +/* additional internal headers for some useful simple macros */ +#include "common.h" +#include "compat.h" +#include "plugins_internal.h" /* LY_TYPE_*_STR */ + +/** + * @page howtoDataLYB LYB Binary Format + * @subsection howtoDataLYBTypesEnumeration enumeration (built-in) + * + * | Size (B) | Mandatory | Type | Meaning | + * | :------ | :-------: | :--: | :-----: | + * | 4 | yes | `int32 *` | assigned little-endian value of the enum | + */ + +LIBYANG_API_DEF LY_ERR +lyplg_type_store_enum(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 *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) +{ + struct lysc_type_enum *type_enum = (struct lysc_type_enum *)type; + LY_ERR ret = LY_SUCCESS; + LY_ARRAY_COUNT_TYPE u; + ly_bool found = 0; + int64_t num = 0; + int32_t num_val; + + /* init storage */ + memset(storage, 0, sizeof *storage); + storage->realtype = type; + + if (format == LY_VALUE_LYB) { + /* validation */ + if (value_len != 4) { + ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB enumeration value size %zu (expected 4).", + value_len); + goto cleanup; + } + + /* convert the value to host byte order */ + memcpy(&num, value, value_len); + num = le64toh(num); + num_val = num; + + /* find the matching enumeration value item */ + LY_ARRAY_FOR(type_enum->enums, u) { + if (type_enum->enums[u].value == num_val) { + found = 1; + break; + } + } + + if (!found) { + /* value not found */ + ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid enumeration value % " PRIi32 ".", num_val); + goto cleanup; + } + + /* store value */ + storage->enum_item = &type_enum->enums[u]; + + /* canonical settings via dictionary due to free callback */ + ret = lydict_insert(ctx, type_enum->enums[u].name, 0, &storage->_canonical); + LY_CHECK_GOTO(ret, cleanup); + + /* success */ + goto cleanup; + } + + /* check hints */ + ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err); + LY_CHECK_GOTO(ret, cleanup); + + /* find the matching enumeration value item */ + LY_ARRAY_FOR(type_enum->enums, u) { + if (!ly_strncmp(type_enum->enums[u].name, value, value_len)) { + found = 1; + break; + } + } + + if (!found) { + /* enum not found */ + ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid enumeration value \"%.*s\".", (int)value_len, + (char *)value); + goto cleanup; + } + + /* store value */ + storage->enum_item = &type_enum->enums[u]; + + /* store canonical value, it always is */ + 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, value_len, &storage->_canonical); + LY_CHECK_GOTO(ret, cleanup); + } + +cleanup: + if (options & LYPLG_TYPE_STORE_DYNAMIC) { + free((void *)value); + } + + if (ret) { + lyplg_type_free_simple(ctx, storage); + } + return ret; +} + +LIBYANG_API_DEF const void * +lyplg_type_print_enum(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format, + void *UNUSED(prefix_data), ly_bool *dynamic, size_t *value_len) +{ + int64_t prev_num = 0, num = 0; + void *buf; + + if (format == LY_VALUE_LYB) { + prev_num = num = value->enum_item->value; + num = htole64(num); + if (num == prev_num) { + /* values are equal, little-endian */ + *dynamic = 0; + if (value_len) { + *value_len = 4; + } + return &value->enum_item->value; + } else { + /* values differ, big-endian */ + buf = calloc(1, 4); + LY_CHECK_RET(!buf, NULL); + + *dynamic = 1; + if (value_len) { + *value_len = 4; + } + memcpy(buf, &num, 4); + return buf; + } + } + + /* use the cached canonical value */ + if (dynamic) { + *dynamic = 0; + } + if (value_len) { + *value_len = strlen(value->_canonical); + } + return value->_canonical; +} + +/** + * @brief Plugin information for enumeration type implementation. + * + * Note that external plugins are supposed to use: + * + * LYPLG_TYPES = { + */ +const struct lyplg_type_record plugins_enumeration[] = { + { + .module = "", + .revision = NULL, + .name = LY_TYPE_ENUM_STR, + + .plugin.id = "libyang 2 - enumeration, version 1", + .plugin.store = lyplg_type_store_enum, + .plugin.validate = NULL, + .plugin.compare = lyplg_type_compare_simple, + .plugin.sort = NULL, + .plugin.print = lyplg_type_print_enum, + .plugin.duplicate = lyplg_type_dup_simple, + .plugin.free = lyplg_type_free_simple, + .plugin.lyb_data_len = 4, + }, + {0} +}; |