hex string UPDATE canonize yang-types hex-strings
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8ed9695..762d259 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -103,6 +103,7 @@
src/plugins_types/ipv4_prefix.c
src/plugins_types/ipv6_prefix.c
src/plugins_types/date_and_time.c
+ src/plugins_types/hex_string.c
src/plugins_types/xpath1.0.c
src/plugins_types/node_instanceid.c)
diff --git a/src/plugins.c b/src/plugins.c
index d62da1c..011e464 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -70,6 +70,7 @@
* ietf-yang-types
*/
extern const struct lyplg_type_record plugins_date_and_time[];
+extern const struct lyplg_type_record plugins_hex_string[];
extern const struct lyplg_type_record plugins_xpath10[];
/*
@@ -475,6 +476,7 @@
/* ietf-yang-types */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
+ LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
/* ietf-netconf-acm */
diff --git a/src/plugins_types/hex_string.c b/src/plugins_types/hex_string.c
new file mode 100644
index 0000000..f72ce66
--- /dev/null
+++ b/src/plugins_types/hex_string.c
@@ -0,0 +1,171 @@
+/**
+ * @file hex_string.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief Built-in hex-string and associated types plugin.
+ *
+ * Copyright (c) 2023 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
+
+#include "plugins_types.h"
+
+#include <ctype.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"
+
+/**
+ * @page howtoDataLYB LYB Binary Format
+ * @subsection howtoDataLYBTypesHexString phys-address, mac-address, hex-string, uuid (ietf-yang-types)
+ *
+ * | Size (B) | Mandatory | Type | Meaning |
+ * | :------ | :-------: | :--: | :-----: |
+ * | string length | yes | `char *` | string itself |
+ */
+
+LIBYANG_API_DEF LY_ERR
+lyplg_type_store_hex_string(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)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysc_type_str *type_str = (struct lysc_type_str *)type;
+ uint32_t i;
+
+ /* init storage */
+ memset(storage, 0, sizeof *storage);
+ storage->realtype = type;
+
+ /* check hints */
+ ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* length restriction of the string */
+ if (type_str->length) {
+ /* value_len is in bytes, but we need number of characters here */
+ ret = lyplg_type_validate_range(LY_TYPE_STRING, type_str->length, ly_utf8len(value, value_len), value, value_len, err);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ /* pattern restrictions */
+ ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* make a copy, it is needed for canonization */
+ if ((format != LY_VALUE_CANON) && !(options & LYPLG_TYPE_STORE_DYNAMIC)) {
+ value = strndup(value, value_len);
+ LY_CHECK_ERR_GOTO(!value, ret = LY_EMEM, cleanup);
+ options |= LYPLG_TYPE_STORE_DYNAMIC;
+ }
+
+ /* store canonical value */
+ if (format != LY_VALUE_CANON) {
+ /* make lowercase and store, the value must be dynamic */
+ for (i = 0; i < value_len; ++i) {
+ ((char *)value)[i] = tolower(((char *)value)[i]);
+ }
+
+ ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
+ options &= ~LYPLG_TYPE_STORE_DYNAMIC;
+ LY_CHECK_GOTO(ret, cleanup);
+ } else {
+ /* store directly */
+ ret = lydict_insert(ctx, value_len ? 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;
+}
+
+/**
+ * @brief Plugin information for string type implementation.
+ *
+ * Note that external plugins are supposed to use:
+ *
+ * LYPLG_TYPES = {
+ */
+const struct lyplg_type_record plugins_hex_string[] = {
+ {
+ .module = "ietf-yang-types",
+ .revision = "2013-07-15",
+ .name = "phys-address",
+
+ .plugin.id = "libyang 2 - hex-string, version 1",
+ .plugin.store = lyplg_type_store_hex_string,
+ .plugin.validate = NULL,
+ .plugin.compare = lyplg_type_compare_simple,
+ .plugin.sort = NULL,
+ .plugin.print = lyplg_type_print_simple,
+ .plugin.duplicate = lyplg_type_dup_simple,
+ .plugin.free = lyplg_type_free_simple,
+ .plugin.lyb_data_len = -1,
+ },
+ {
+ .module = "ietf-yang-types",
+ .revision = "2013-07-15",
+ .name = "mac-address",
+
+ .plugin.id = "libyang 2 - hex-string, version 1",
+ .plugin.store = lyplg_type_store_hex_string,
+ .plugin.validate = NULL,
+ .plugin.compare = lyplg_type_compare_simple,
+ .plugin.sort = NULL,
+ .plugin.print = lyplg_type_print_simple,
+ .plugin.duplicate = lyplg_type_dup_simple,
+ .plugin.free = lyplg_type_free_simple,
+ .plugin.lyb_data_len = -1,
+ },
+ {
+ .module = "ietf-yang-types",
+ .revision = "2013-07-15",
+ .name = "hex-string",
+
+ .plugin.id = "libyang 2 - hex-string, version 1",
+ .plugin.store = lyplg_type_store_hex_string,
+ .plugin.validate = NULL,
+ .plugin.compare = lyplg_type_compare_simple,
+ .plugin.sort = NULL,
+ .plugin.print = lyplg_type_print_simple,
+ .plugin.duplicate = lyplg_type_dup_simple,
+ .plugin.free = lyplg_type_free_simple,
+ .plugin.lyb_data_len = -1,
+ },
+ {
+ .module = "ietf-yang-types",
+ .revision = "2013-07-15",
+ .name = "uuid",
+
+ .plugin.id = "libyang 2 - hex-string, version 1",
+ .plugin.store = lyplg_type_store_hex_string,
+ .plugin.validate = NULL,
+ .plugin.compare = lyplg_type_compare_simple,
+ .plugin.sort = NULL,
+ .plugin.print = lyplg_type_print_simple,
+ .plugin.duplicate = lyplg_type_dup_simple,
+ .plugin.free = lyplg_type_free_simple,
+ .plugin.lyb_data_len = -1,
+ },
+ {0}
+};
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index f0fe252..60649ef 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -84,7 +84,9 @@
/* xml test */
schema = MODULE_CREATE_YANG("a",
"leaf l {type yang:date-and-time;}"
- "leaf l2 {type yang:xpath1.0;}");
+ "leaf l21 {type yang:hex-string;}"
+ "leaf l22 {type yang:uuid;}"
+ "leaf l3 {type yang:xpath1.0;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
schema = MODULE_CREATE_YANG("b",
"");
@@ -114,24 +116,28 @@
"\"\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[\\+\\-]\\d{2}:\\d{2})\".",
"Schema location \"/a:l\", line number 1.");
+ /* hex-string */
+ TEST_SUCCESS_XML("a", "l21", "DB:BA:12:54:fa", STRING, "db:ba:12:54:fa");
+ TEST_SUCCESS_XML("a", "l22", "f81D4fAE-7dec-11d0-A765-00a0c91E6BF6", STRING, "f81d4fae-7dec-11d0-a765-00a0c91e6bf6");
+
/* xpath1.0 */
- TEST_SUCCESS_XML("a\" xmlns:aa=\"urn:tests:a", "l2", "/aa:l2[. = '4']", STRING, "/a:l2[.='4']");
+ TEST_SUCCESS_XML("a\" xmlns:aa=\"urn:tests:a", "l3", "/aa:l3[. = '4']", STRING, "/a:l3[.='4']");
TEST_SUCCESS_XML("a\" xmlns:yl=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
- "xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores", "l2",
+ "xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores", "l3",
"/yl:yang-library/yl:datastore/yl:name = 'ds:running'", STRING,
"/ietf-yang-library:yang-library/datastore/name='ietf-datastores:running'");
- TEST_SUCCESS_XML("a\" xmlns:a1=\"urn:tests:a\" xmlns:a2=\"urn:tests:a\" xmlns:bb=\"urn:tests:b", "l2",
+ TEST_SUCCESS_XML("a\" xmlns:a1=\"urn:tests:a\" xmlns:a2=\"urn:tests:a\" xmlns:bb=\"urn:tests:b", "l3",
"/a1:node1/a2:node2[a1:node3/bb:node4]/bb:node5 | bb:node6 and (bb:node7)", STRING,
"/a:node1/node2[node3/b:node4]/b:node5 | b:node6 and (b:node7)");
- TEST_SUCCESS_XML("a", "l2", "/l2[. = '4']", STRING, "/l2[.='4']");
+ TEST_SUCCESS_XML("a", "l3", "/l3[. = '4']", STRING, "/l3[.='4']");
- TEST_ERROR_XML("a", "l2", "/a:l2[. = '4']");
- CHECK_LOG_CTX("Failed to resolve prefix \"a\".", "Schema location \"/a:l2\", line number 1.");
- TEST_ERROR_XML("a\" xmlns:yl=\"urn:ietf:params:xml:ns:yang:ietf-yang-library", "l2",
+ TEST_ERROR_XML("a", "l3", "/a:l3[. = '4']");
+ CHECK_LOG_CTX("Failed to resolve prefix \"a\".", "Schema location \"/a:l3\", line number 1.");
+ TEST_ERROR_XML("a\" xmlns:yl=\"urn:ietf:params:xml:ns:yang:ietf-yang-library", "l3",
"/yl:yang-library/yl:datastore/yl::name");
- CHECK_LOG_CTX("Storing value failed.", "Schema location \"/a:l2\", line number 1.");
+ CHECK_LOG_CTX("Storing value failed.", "Schema location \"/a:l3\", line number 1.");
CHECK_LOG_CTX("Invalid character 'y'[31] of expression '/yl:yang-library/yl:datastore/yl::name'.",
- "Schema location \"/a:l2\", line number 1.");
+ "Schema location \"/a:l3\", line number 1.");
}
static void