From ac3748517e3324b94ff0f9a07a35984d2ebdf605 Mon Sep 17 00:00:00 2001 From: IrfanMohammad Date: Sat, 5 Aug 2023 05:11:29 +0000 Subject: [PATCH] lyd_new_path handle json encoded string leaves According to ietf rfc 8259, strings are always surrounded by double quotes. This means, for storing within libyang, we must strip input data of these, and take the value as the stripped portion. Example: const char * data = "\"Great View\""; should yield const char *value = "Great View"; For this, a new option is used `LYD_NEW_PATH_JSON_VALUE` --- src/tree_data.h | 6 ++++++ src/tree_data_new.c | 11 +++++++++++ tests/utests/data/test_new.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/src/tree_data.h b/src/tree_data.h index fd8137c40..89c19fc7c 100644 --- a/src/tree_data.h +++ b/src/tree_data.h @@ -1529,6 +1529,12 @@ LIBYANG_API_DECL LY_ERR lyd_new_attr2(struct lyd_node *parent, const char *modul to unexpected behavior. */ #define LYD_NEW_PATH_WITH_OPAQ 0x20 /**< Consider opaque nodes normally when searching for existing nodes. */ +#define LYD_NEW_PATH_JSON_VALUE 0x40 /**< Interpret the provided leaf/leaf-list @p value as being in the JSON format. + Specifically, strings are quoted as per IETF rfc 8259 + `string = quotation-mark *char quotation-mark` + Example, `const char * data = "\"Great View\"";` should be processed as + `const value = "Great View";` */ + /** @} pathoptions */ /** diff --git a/src/tree_data_new.c b/src/tree_data_new.c index 66c35f34d..762cddeb1 100644 --- a/src/tree_data_new.c +++ b/src/tree_data_new.c @@ -1616,6 +1616,7 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly const struct lyd_value *val = NULL; LY_ARRAY_COUNT_TYPE path_idx = 0, orig_count = 0; LY_VALUE_FORMAT format; + const char *str_value = value; assert(parent || ctx); assert(path && ((path[0] == '/') || parent)); @@ -1627,6 +1628,16 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly if (value && !value_len) { value_len = strlen(value); } + if (options & LYD_NEW_PATH_JSON_VALUE) { + /* if it starts and ends in double-quotes, it can only be a string value */ + if ((value_len > 1) && str_value && + ('"' == str_value[0]) && ('"' == str_value[value_len - 1])) { + /* remove the quotes */ + value = ++str_value; + value_len -= 2; + } + } + if (options & LYD_NEW_PATH_BIN_VALUE) { format = LY_VALUE_LYB; } else if (options & LYD_NEW_PATH_CANON_VALUE) { diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c index 5cee9032e..30c963b5d 100644 --- a/tests/utests/data/test_new.c +++ b/tests/utests/data/test_new.c @@ -495,6 +495,41 @@ test_path_ext(void **state) lyd_free_tree(root); } +static void +test_path_json_val(void **state) +{ + LY_ERR ret; + struct ly_ctx *ctx; + struct lyd_node *root, *node, *parent; + struct lys_module *mod; + LYD_ANYDATA_VALUETYPE type = LYD_ANYDATA_STRING; + uint32_t opts[2] = {LYD_NEW_PATH_JSON_VALUE, 0}; + char *val[5][2] = {{"val", "\"val\""}, {"val2", "\"val2\""}, {"val3", "\"val3\""}, {"val4", "val4"}, {"", "\"\""}}; + char *exp_val[5][2] = {{"val", "val"}, {"val2", "\"val2\""}, {"val3", "\"val3\""}, {"val4", "val4"}, {"", "\"\""}}; + char *path[5] = {"/a:c/x[.='val']", "/a:c/x", "x", "x", "x"}; + + int i, j; + UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod); + + for (i = 0; i < 2; i++) { + root = node = parent = NULL; + ctx = UTEST_LYCTX; + + for (j = 0; j < 5; j++) { + ret = lyd_new_path2(root, ctx, path[j], val[j][i], 0, type, opts[i], root ? &parent : &root, &node); + assert_int_equal(ret, LY_SUCCESS); + assert_non_null(root); + assert_string_equal(root->schema->name, "c"); + assert_non_null(node); + assert_string_equal(node->schema->name, "x"); + assert_string_equal(lyd_get_value(node), exp_val[j][i]); + node = NULL; + ctx = NULL; + } + lyd_free_tree(root); + } +} + int main(void) { @@ -503,6 +538,7 @@ main(void) UTEST(test_opaq), UTEST(test_path), UTEST(test_path_ext), + UTEST(test_path_json_val), }; return cmocka_run_group_tests(tests, NULL, NULL);