lyb parser & printer CHANGE base implementation finished
All basic features should be implemented, practically
not tested at all.
diff --git a/src/common.c b/src/common.c
index e08dba4..0f03b43 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1372,7 +1372,7 @@
static int
lyb_ht_build_equal_cb(void *UNUSED(val1_p), void *UNUSED(val2_p), int UNUSED(mod), void *UNUSED(cb_data))
{
- /* for this purpose, if hash matches, the value must also */
+ /* for this purpose, if hash matches, the value does also, we do not want 2 values to have the same hash */
return 1;
}
@@ -1389,12 +1389,18 @@
}
LYB_HASH
-lyb_hash(const struct lys_node *sibling, uint8_t collision_id)
+lyb_hash(struct lys_node *sibling, uint8_t collision_id)
{
struct lys_module *mod;
uint32_t full_hash;
LYB_HASH hash;
+#ifdef LY_ENABLED_CACHE
+ if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
+ return sibling->hash[collision_id];
+ }
+#endif
+
mod = lys_node_module(sibling);
full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
@@ -1414,11 +1420,33 @@
/* add colision identificator */
hash |= LYB_HASH_COLLISION_ID >> collision_id;
+ /* save this hash */
+#ifdef LY_ENABLED_CACHE
+ if (collision_id < LYS_NODE_HASH_COUNT) {
+ sibling->hash[collision_id] = hash;
+ }
+#endif
+
return hash;
}
+int
+lyb_has_schema_model(struct lys_node *sibling, const struct lys_module **models, int mod_count)
+{
+ int i;
+ const struct lys_module *mod = lys_node_module(sibling);
+
+ for (i = 0; i < mod_count; ++i) {
+ if (mod == models[i]) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
struct hash_table *
-lyb_hash_siblings(struct lys_node *sibling)
+lyb_hash_siblings(struct lys_node *sibling, const struct lys_module **models, int mod_count)
{
LYB_HASH hash;
struct hash_table *ht;
@@ -1432,10 +1460,15 @@
ht = lyht_new(1, sizeof(struct lys_node *), lyb_ht_build_equal_cb, NULL, 1);
LY_CHECK_ERR_RETURN(!ht, LOGMEM(sibling->module->ctx), NULL);
- parent = lys_parent(sibling);
+ for (parent = lys_parent(sibling); parent && (parent->nodetype == LYS_USES); parent = lys_parent(parent));
mod = lys_node_module(sibling);
sibling = NULL;
while ((sibling = (struct lys_node *)lys_getnext(sibling, parent, mod, 0))) {
+ if (models && !lyb_has_schema_model(sibling, models, mod_count)) {
+ /* ignore models not present during printing */
+ continue;
+ }
+
for (i = 0; i < LYB_HASH_BITS; ++i) {
hash = lyb_hash(sibling, i);
if (!hash) {
@@ -1454,10 +1487,6 @@
lyht_free(ht);
return NULL;
}
-
-#ifdef LY_ENABLED_CACHE
- sibling->hash = hash;
-#endif
}
/* change val equal callback so that the HT is usable for finding value hashes */
@@ -1465,28 +1494,3 @@
return ht;
}
-
-LYB_HASH
-lyb_hash_find(struct hash_table *ht, const struct lys_node *node)
-{
- LYB_HASH hash;
- uint32_t i;
-
- for (i = 0; i < LYB_HASH_BITS; ++i) {
- hash = lyb_hash(node, i);
- if (!hash) {
- lyht_free(ht);
- return 0;
- }
-
- if (!lyht_find(ht, &node, hash, NULL)) {
- /* success, no collision */
- break;
- }
- }
- /* cannot happen, we already calculated the hash */
- assert(i <= LYB_HASH_BITS);
-
- return hash;
-}
-
diff --git a/src/parser.h b/src/parser.h
index 44596f7..d680378 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -58,8 +58,8 @@
* @defgroup lybdata LYB data format support
* @{
*/
-struct lyd_node *lyd_parse_lyb(struct ly_ctx *ctx, const char *data, int options, const struct lyd_node *rpc_act,
- const struct lyd_node *data_tree, const char *yang_data_name, int *parsed);
+struct lyd_node *lyd_parse_lyb(struct ly_ctx *ctx, const char *data, int options, const struct lyd_node *data_tree,
+ const char *yang_data_name, int *parsed);
/**@} lybdata */
diff --git a/src/parser_json.c b/src/parser_json.c
index f75e6b5..1f720f8 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1485,7 +1485,7 @@
ly_set_free(set);
/* add/validate default values, unres */
- if (lyd_defaults_add_unres(&result, options, ctx, data_tree, act_notif, unres)) {
+ if (lyd_defaults_add_unres(&result, options, ctx, data_tree, act_notif, unres, 1)) {
goto error;
}
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 0a85f56..b4cd9bc 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -54,7 +54,9 @@
/* we are actually reading some data, not just finishing another chunk */
if (to_read) {
- memcpy(buf, data + ret, to_read);
+ if (buf) {
+ memcpy(buf, data + ret, to_read);
+ }
for (i = 0; i < lybs->used; ++i) {
/* decrease all written counters */
@@ -62,7 +64,9 @@
}
/* decrease count/buf */
count -= to_read;
- buf += to_read;
+ if (buf) {
+ buf += to_read;
+ }
ret += to_read;
}
@@ -84,15 +88,16 @@
lyb_read_number(uint64_t *num, uint64_t max_num, const char *data, struct lyb_state *lybs)
{
int max_bits, max_bytes, i, r, ret = 0;
+ uint8_t byte;
for (max_bits = 0; max_num; max_num >>= 1, ++max_bits);
max_bytes = max_bits / 8 + (max_bits % 8 ? 1 : 0);
- *num = 0;
for (i = 0; i < max_bytes; ++i) {
- *num <<= 8;
- ret += (r = lyb_read(data, (uint8_t *)num, 1, lybs));
+ ret += (r = lyb_read(data, &byte, 1, lybs));
LYB_HAVE_READ_RETURN(r, data, -1);
+
+ *(((uint8_t *)num) + i) = byte;
}
return ret;
@@ -247,7 +252,7 @@
/* read anydata content */
if (any->value_type == LYD_ANYDATA_DATATREE) {
- any->value.tree = lyd_parse_lyb(node->schema->module->ctx, data, 0, NULL, NULL, NULL, &r);
+ any->value.tree = lyd_parse_lyb(node->schema->module->ctx, data, 0, NULL, NULL, &r);
ret += r;
LYB_HAVE_READ_RETURN(r, data, -1);
} else {
@@ -261,8 +266,10 @@
static int
lyb_parse_val(struct lyd_node_leaf_list *node, const char *data, struct lyb_state *lybs)
{
- int ret;
+ int r, ret;
+ size_t i;
uint8_t byte;
+ uint64_t num;
struct ly_ctx *ctx = node->schema->module->ctx;
struct lys_type *type = &((struct lys_node_leaf *)node->schema)->type;
@@ -292,7 +299,21 @@
LY_CHECK_ERR_RETURN(!node->value.bit, LOGMEM(ctx), -1);
/* read values */
- /* TODO */
+ ret = 0;
+ for (i = 0; i < type->info.bits.count; ++i) {
+ if (i % 8 == 0) {
+ /* read another byte */
+ ret += (r = lyb_read(data, &byte, sizeof byte, lybs));
+ if (r < 0) {
+ return -1;
+ }
+ }
+
+ if (byte & (0x01 << (i % 8))) {
+ /* bit is set */
+ node->value.bit[i] = &type->info.bits.bit[i];
+ }
+ }
break;
case LY_TYPE_BOOL:
/* read byte */
@@ -307,9 +328,13 @@
break;
case LY_TYPE_ENUM:
/* find the correct structure */
- for (; !type->info.bits.count; type = &type->der->type);
+ for (; !type->info.enums.count; type = &type->der->type);
- /* TODO */
+ num = 0;
+ ret = lyb_read_number(&num, type->info.enums.enm[type->info.enums.count - 1].value, data, lybs);
+ if ((ret > 0) && (num < type->info.enums.count)) {
+ node->value.enm = &type->info.enums.enm[num];
+ }
break;
case LY_TYPE_INT8:
case LY_TYPE_UINT8:
@@ -336,11 +361,12 @@
}
static int
-lyb_parse_val_str(struct lyd_node_leaf_list *node)
+lyb_parse_val_str(struct lyd_node_leaf_list *node, struct unres_data *unres)
{
struct ly_ctx *ctx = node->schema->module->ctx;
struct lys_type *type = &((struct lys_node_leaf *)node->schema)->type;
- char num_str[21];
+ char num_str[22], *str;
+ uint32_t i, str_len;
if (node->value_flags & LY_VALUE_UNRES) {
/* nothing to do */
@@ -363,8 +389,10 @@
switch (node->value_type) {
case LY_TYPE_INST:
- /* fill the instance-identifier target now */
- /* TODO */
+ /* try to fill the instance-identifier target now */
+ if (unres_data_add(unres, (struct lyd_node *)node, UNRES_INSTID)) {
+ return -1;
+ }
break;
case LY_TYPE_IDENT:
/* fill the identity pointer now */
@@ -380,7 +408,25 @@
node->value_str = node->value.string;
break;
case LY_TYPE_BITS:
- /* TODO */
+ for (; !type->info.bits.count; type = &type->der->type);
+
+ /* print the set bits */
+ str = malloc(1);
+ LY_CHECK_ERR_RETURN(!str, LOGMEM(ctx), -1);
+ str[0] = '\0';
+ str_len = 1;
+ for (i = 0; i < type->info.bits.count; ++i) {
+ if (node->value.bit[i]) {
+ str = ly_realloc(str, str_len + strlen(node->value.bit[i]->name) + 1);
+ LY_CHECK_ERR_RETURN(!str, LOGMEM(ctx), -1);
+
+ sprintf(str + str_len, "%s%s", str_len == 1 ? "" : " ", node->value.bit[i]->name);
+
+ str_len += strlen(node->value.bit[i]->name) + 1;
+ }
+ }
+
+ node->value_str = lydict_insert_zc(ctx, str);
break;
case LY_TYPE_BOOL:
node->value_str = lydict_insert(ctx, (node->value.bln ? "true" : "false"), 0);
@@ -390,7 +436,8 @@
/* leave value empty */
break;
case LY_TYPE_ENUM:
- /* TODO */
+ /* print the value */
+ node->value_str = lydict_insert(ctx, node->value.enm->name, 0);
break;
case LY_TYPE_INT8:
sprintf(num_str, "%d", node->value.int8);
@@ -425,7 +472,8 @@
node->value_str = lydict_insert(ctx, num_str, 0);
break;
case LY_TYPE_DEC64:
- /* TODO */
+ sprintf(num_str, "%ld.%ld", node->value.dec64 / (type->info.dec64.dig * 10), node->value.dec64 % (type->info.dec64.dig * 10));
+ node->value_str = lydict_insert(ctx, num_str, 0);
break;
default:
return -1;
@@ -435,7 +483,7 @@
}
static int
-lyb_parse_leaf(struct lyd_node *node, const char *data, struct lyb_state *lybs)
+lyb_parse_leaf(struct lyd_node *node, const char *data, struct unres_data *unres, struct lyb_state *lybs)
{
int r, ret = 0;
uint8_t start_byte;
@@ -460,19 +508,34 @@
ret += (r = lyb_parse_val(leaf, data, lybs));
LYB_HAVE_READ_RETURN(r, data, -1);
- ret += (r = lyb_parse_val_str(leaf));
+ ret += (r = lyb_parse_val_str(leaf, unres));
LYB_HAVE_READ_RETURN(r, data, -1);
return ret;
}
static int
-lyb_parse_schema_hash(const struct lys_node *sparent, const struct lys_module *mod, const char *data,
- struct hash_table **sibling_ht, struct lys_node **snode, struct lyb_state *lybs)
+lyb_is_schema_hash_match(struct lys_node *sibling, LYB_HASH hash)
+{
+ LYB_HASH sibling_hash;
+ uint8_t collision_id;
+
+ /* get collision ID */
+ for (collision_id = 0; !(hash & (LYB_HASH_COLLISION_ID >> collision_id)); ++collision_id);
+
+ /* get correct collision ID node hash */
+ sibling_hash = lyb_hash(sibling, collision_id);
+
+ return hash == sibling_hash;
+}
+
+static int
+lyb_parse_schema_hash(const struct lys_node *sparent, const struct lys_module *mod, const char *data, const char *yang_data_name,
+ int options, struct lys_node **snode, struct lyb_state *lybs)
{
int r, ret = 0;
- const struct lys_node *sibling = NULL;
- LYB_HASH hash, cur_hash;
+ struct lys_node *sibling = NULL;
+ LYB_HASH hash = 0;
struct ly_ctx *ctx;
assert((sparent || mod) && (!sparent || !mod));
@@ -481,37 +544,20 @@
/* read the hash */
ret += (r = lyb_read(data, &hash, sizeof hash, lybs));
LYB_HAVE_READ_RETURN(r, data, -1);
+ if (!hash) {
+ return -1;
+ }
- while ((sibling = lys_getnext(sibling, sparent, mod, 0))) {
-
- /* make sure hashes are ready and get the current one */
- cur_hash = 0;
-#ifdef LY_ENABLED_CACHE
- if (sibling->hash) {
- cur_hash = sibling->hash;
- } else
-#endif
- if (!*sibling_ht) {
- *sibling_ht = lyb_hash_siblings((struct lys_node *)sibling);
- if (!*sibling_ht) {
- return -1;
- }
- }
- if (!cur_hash) {
- cur_hash = lyb_hash_find(*sibling_ht, sibling);
- if (!cur_hash) {
- return -1;
- }
- }
-
- if (hash == cur_hash) {
+ while ((sibling = (struct lys_node *)lys_getnext(sibling, sparent, mod, 0))) {
+ /* skip schema nodes from models not present during printing */
+ if (lyb_has_schema_model(sibling, lybs->models, lybs->mod_count) && lyb_is_schema_hash_match(sibling, hash)) {
/* match found */
- *snode = (struct lys_node *)sibling;
break;
}
}
- if (!sibling) {
+ *snode = sibling;
+ if (!sibling && (options & LYD_OPT_STRICT)) {
if (mod) {
LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Failed to find matching hash for a top-level node from \"%s\".", mod->name);
} else {
@@ -525,10 +571,9 @@
static int
lyb_parse_subtree(struct ly_ctx *ctx, const char *data, struct lyd_node *parent, struct lyd_node **first_sibling,
- struct hash_table **sibling_ht, struct lyb_state *lybs)
+ const char *yang_data_name, int options, struct unres_data *unres, struct lyb_state *lybs)
{
int r, ret = 0;
- struct hash_table *children_ht = NULL;
struct lyd_node *node = NULL, *iter;
const struct lys_module *mod;
struct lys_node *sparent, *snode;
@@ -551,9 +596,15 @@
}
/* read hash, find the schema node */
- ret += (r = lyb_parse_schema_hash(sparent, mod, data, sibling_ht, &snode, lybs));
+ ret += (r = lyb_parse_schema_hash(sparent, mod, data, yang_data_name, options, &snode, lybs));
LYB_HAVE_READ_GOTO(r, data, error);
+ if (!snode) {
+ /* unknown data subtree, skip it */
+ ret += (r = lyb_read(data, NULL, lybs->written[lybs->used - 1], lybs));
+ goto stop_subtree;
+ }
+
/*
* read the node
*/
@@ -564,8 +615,6 @@
/* TODO read attributes */
- /* TODO read hash if flag */
-
/* read node content */
switch (snode->nodetype) {
case LYS_CONTAINER:
@@ -574,7 +623,7 @@
break;
case LYS_LEAF:
case LYS_LEAFLIST:
- ret += (r = lyb_parse_leaf(node, data, lybs));
+ ret += (r = lyb_parse_leaf(node, data, unres, lybs));
LYB_HAVE_READ_GOTO(r, data, error);
break;
case LYS_ANYXML:
@@ -610,15 +659,9 @@
/* read all descendants */
while (lybs->written[lybs->used - 1]) {
- ret += (r = lyb_parse_subtree(ctx, data, node, NULL, &children_ht, lybs));
+ ret += (r = lyb_parse_subtree(ctx, data, node, NULL, NULL, options, unres, lybs));
LYB_HAVE_READ_GOTO(r, data, error);
}
- if (children_ht) {
- lyht_free(children_ht);
- }
-
- /* end the subtree */
- lyb_read_stop_subtree(lybs);
/* make containers default if should be */
if (node->schema->nodetype == LYS_CONTAINER) {
@@ -633,12 +676,13 @@
}
}
+stop_subtree:
+ /* end the subtree */
+ lyb_read_stop_subtree(lybs);
+
return ret;
error:
- if (children_ht) {
- lyht_free(children_ht);
- }
lyd_free(node);
if (*first_sibling == node) {
*first_sibling = NULL;
@@ -647,26 +691,45 @@
}
static int
+lyb_parse_data_models(struct ly_ctx *ctx, const char *data, struct lyb_state *lybs)
+{
+ int i, r, ret = 0;
+
+ /* read model count */
+ ret += (r = lyb_read(data, (uint8_t *)&lybs->mod_count, 2, lybs));
+ LYB_HAVE_READ_RETURN(r, data, -1);
+
+ lybs->models = malloc(lybs->mod_count * sizeof *lybs->models);
+ LY_CHECK_ERR_RETURN(!lybs->models, LOGMEM(NULL), -1);
+
+ /* read modules */
+ for (i = 0; i < lybs->mod_count; ++i) {
+ ret += (r = lyb_parse_model(ctx, data, &lybs->models[i], lybs));
+ LYB_HAVE_READ_RETURN(r, data, -1);
+ }
+
+ return ret;
+}
+
+static int
lyb_parse_header(const char *data, struct lyb_state *lybs)
{
int ret = 0;
uint8_t byte = 0;
- /* TODO version, option for hash storing */
+ /* TODO version, any flags? */
ret += lyb_read(data, (uint8_t *)&byte, sizeof byte, lybs);
- /* TODO all used models */
-
return ret;
}
struct lyd_node *
-lyd_parse_lyb(struct ly_ctx *ctx, const char *data, int options, const struct lyd_node *rpc_act,
- const struct lyd_node *data_tree, const char *yang_data_name, int *parsed)
+lyd_parse_lyb(struct ly_ctx *ctx, const char *data, int options, const struct lyd_node *data_tree,
+ const char *yang_data_name, int *parsed)
{
int r, ret = 0;
- struct hash_table *top_sibling_ht = NULL;
- struct lyd_node *node = NULL;
+ struct lyd_node *node = NULL, *next, *act_notif = NULL;
+ struct unres_data *unres = NULL;
struct lyb_state lybs;
if (!ctx || !data) {
@@ -679,29 +742,70 @@
LY_CHECK_ERR_GOTO(!lybs.written || !lybs.position, LOGMEM(ctx), finish);
lybs.used = 0;
lybs.size = LYB_STATE_STEP;
+ lybs.models = NULL;
+ lybs.mod_count = 0;
+
+ unres = calloc(1, sizeof *unres);
+ LY_CHECK_ERR_GOTO(!unres, LOGMEM(ctx), finish);
/* read header */
ret += (r = lyb_parse_header(data, &lybs));
LYB_HAVE_READ_GOTO(r, data, finish);
- /* TODO read used models */
+ /* read used models */
+ ret += (r = lyb_parse_data_models(ctx, data, &lybs));
+ LYB_HAVE_READ_GOTO(r, data, finish);
/* read subtree(s) */
while (data[0]) {
- ret += (r = lyb_parse_subtree(ctx, data, NULL, &node, &top_sibling_ht, &lybs));
- LYB_HAVE_READ_GOTO(r, data, finish);
+ ret += (r = lyb_parse_subtree(ctx, data, NULL, &node, yang_data_name, options, unres, &lybs));
+ if (r < 0) {
+ lyd_free_withsiblings(node);
+ node = NULL;
+ goto finish;
+ }
+ data += r;
}
/* read the last zero, parsing finished */
++ret;
r = ret;
-finish:
- if (top_sibling_ht) {
- lyht_free(top_sibling_ht);
+ if (options & LYD_OPT_DATA_ADD_YANGLIB) {
+ if (lyd_merge(node, ly_ctx_info(ctx), LYD_OPT_DESTRUCT | LYD_OPT_EXPLICIT)) {
+ LOGERR(ctx, LY_EINT, "Adding ietf-yang-library data failed.");
+ lyd_free_withsiblings(node);
+ node = NULL;
+ goto finish;
+ }
}
+
+ /* resolve any unresolved instance-identifiers */
+ if (unres->count) {
+ if (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)) {
+ LY_TREE_DFS_BEGIN(node, next, act_notif) {
+ if (act_notif->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ break;
+ }
+ LY_TREE_DFS_END(node, next, act_notif);
+ }
+ }
+ if (lyd_defaults_add_unres(&node, options, ctx, data_tree, act_notif, unres, 0)) {
+ lyd_free_withsiblings(node);
+ node = NULL;
+ goto finish;
+ }
+ }
+
+finish:
free(lybs.written);
free(lybs.position);
+ free(lybs.models);
+ if (unres) {
+ free(unres->node);
+ free(unres->type);
+ free(unres);
+ }
if (parsed) {
*parsed = r;
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 1898985..52fdbf6 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -748,7 +748,7 @@
ly_set_free(set);
/* add default values, resolve unres and check for mandatory nodes in final tree */
- if (lyd_defaults_add_unres(&result, options, ctx, data_tree, act_notif, unres)) {
+ if (lyd_defaults_add_unres(&result, options, ctx, data_tree, act_notif, unres, 1)) {
goto error;
}
if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER))
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 3707b97..a0c8a3b 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -128,10 +128,8 @@
max_bytes = max_bits / 8 + (max_bits % 8 ? 1 : 0);
for (i = 0; i < max_bytes; ++i) {
- byte = (uint8_t)num;
+ byte = *(((uint8_t *)&num) + i);
ret += lyb_write(out, &byte, 1, lybs);
-
- num >>= 8;
}
return ret;
@@ -194,12 +192,12 @@
}
static int
-is_added_module(const struct lys_module **modules, size_t mod_count, const struct lys_module *mod)
+is_added_model(const struct lys_module **models, size_t mod_count, const struct lys_module *mod)
{
size_t i;
for (i = 0; i < mod_count; ++i) {
- if (modules[i] == mod) {
+ if (models[i] == mod) {
return 1;
}
}
@@ -208,21 +206,21 @@
}
static void
-add_module(const struct lys_module ***modules, size_t *mod_count, const struct lys_module *mod)
+add_model(const struct lys_module ***models, size_t *mod_count, const struct lys_module *mod)
{
- if (is_added_module(*modules, *mod_count, mod)) {
+ if (is_added_model(*models, *mod_count, mod)) {
return;
}
- *modules = ly_realloc(*modules, ++(*mod_count) * sizeof **modules);
- (*modules)[*mod_count - 1] = mod;
+ *models = ly_realloc(*models, ++(*mod_count) * sizeof **models);
+ (*models)[*mod_count - 1] = mod;
}
static int
lyb_print_data_models(struct lyout *out, const struct lyd_node *root, struct lyb_state *lybs)
{
int ret = 0;
- const struct lys_module **modules = NULL, *mod;
+ const struct lys_module **models = NULL, *mod;
const struct lyd_node *node;
size_t mod_count = 0;
uint32_t idx = 0, i;
@@ -230,7 +228,7 @@
/* first, collect all data node modules */
LY_TREE_FOR(root, node) {
mod = lyd_node_module(node);
- add_module(&modules, &mod_count, mod);
+ add_model(&models, &mod_count, mod);
}
/* then add all models augmenting or deviating the used models */
@@ -242,28 +240,28 @@
}
for (i = 0; i < mod->deviation_size; ++i) {
- if (mod->deviation[i].orig_node && is_added_module(modules, mod_count, lys_node_module(mod->deviation[i].orig_node))) {
- add_module(&modules, &mod_count, mod);
+ if (mod->deviation[i].orig_node && is_added_model(models, mod_count, lys_node_module(mod->deviation[i].orig_node))) {
+ add_model(&models, &mod_count, mod);
goto next_mod;
}
}
for (i = 0; i < mod->augment_size; ++i) {
- if (is_added_module(modules, mod_count, lys_node_module(mod->augment[i].target))) {
- add_module(&modules, &mod_count, mod);
+ if (is_added_model(models, mod_count, lys_node_module(mod->augment[i].target))) {
+ add_model(&models, &mod_count, mod);
goto next_mod;
}
}
}
/* now write module count on 2 bytes */
- ret += lyb_write(out, (uint8_t *)mod_count, 2, lybs);
+ ret += lyb_write(out, (uint8_t *)&mod_count, 2, lybs);
/* and all the used models */
for (i = 0; i < mod_count; ++i) {
- ret += lyb_print_model(out, modules[i], lybs);
+ ret += lyb_print_model(out, models[i], lybs);
}
- free(modules);
+ free(models);
return ret;
}
@@ -273,11 +271,9 @@
int ret = 0;
uint8_t byte = 0;
- /* TODO version, option for hash storing */
+ /* TODO version, some other flags? */
ret += ly_write(out, (char *)&byte, sizeof byte);
- /* TODO all used models */
-
return ret;
}
@@ -435,8 +431,9 @@
/* find the correct structure */
for (; !type->info.enums.count; type = &type->der->type);
- /* store the value (save bytes if possible) */
- ret += lyb_write_number(leaf->value.enm->value, type->info.enums.enm[type->info.enums.count - 1].value, out, lybs);
+ /* store the enum index (save bytes if possible) */
+ i = (leaf->value.enm - type->info.enums.enm) / sizeof *leaf->value.enm;
+ ret += lyb_write_number(i, type->info.enums.enm[type->info.enums.count - 1].value, out, lybs);
break;
case LY_TYPE_INT8:
case LY_TYPE_UINT8:
@@ -462,6 +459,31 @@
return ret;
}
+static LYB_HASH
+lyb_hash_find(struct hash_table *ht, struct lys_node *node)
+{
+ LYB_HASH hash;
+ uint32_t i;
+
+ for (i = 0; i < LYB_HASH_BITS; ++i) {
+ hash = lyb_hash(node, i);
+ if (!hash) {
+ return 0;
+ }
+
+ if (!lyht_find(ht, &node, hash, NULL)) {
+ /* success, no collision */
+ break;
+ }
+ }
+ /* cannot happen, we already calculated the hash */
+ if (i > LYB_HASH_BITS) {
+ return 0;
+ }
+
+ return hash;
+}
+
static int
lyb_print_subtree(struct lyout *out, const struct lyd_node *node, struct hash_table **sibling_ht, struct lyb_state *lybs,
int options, int top_level)
@@ -470,23 +492,16 @@
LYB_HASH hash = 0;
struct hash_table *children_ht = NULL;
- /* get the correct node hash, create whole sibling HT if needed */
-#ifdef LY_ENABLED_CACHE
- if (node->schema->hash) {
- hash = node->schema->hash;
- } else
-#endif
+ /* create whole sibling HT if not already and get our hash */
if (!*sibling_ht) {
- *sibling_ht = lyb_hash_siblings(node->schema);
+ *sibling_ht = lyb_hash_siblings(node->schema, NULL, 0);
if (!*sibling_ht) {
return -1;
}
}
+ hash = lyb_hash_find(*sibling_ht, node->schema);
if (!hash) {
- hash = lyb_hash_find(*sibling_ht, node->schema);
- if (!hash) {
- return -1;
- }
+ return -1;
}
/* register a new subtree */
@@ -515,8 +530,6 @@
/* TODO write attributes */
- /* TODO write hash if flag */
-
/* write node content */
switch (node->schema->nodetype) {
case LYS_CONTAINER:
@@ -570,7 +583,7 @@
int
lyb_print_data(struct lyout *out, const struct lyd_node *root, int options)
{
- int ret = 0;
+ int r, ret = 0;
uint8_t zero = 0;
struct hash_table *top_sibling_ht = NULL;
struct lyb_state lybs;
@@ -582,16 +595,36 @@
lybs.size = LYB_STATE_STEP;
/* LYB header */
- ret += lyb_print_header(out, options);
-
- /* all used models */
- ret += lyb_print_data_models(out, root, &lybs);
-
- LY_TREE_FOR(root, root) {
- ret += lyb_print_subtree(out, root, &top_sibling_ht, &lybs, options, 1);
+ ret += (r = lyb_print_header(out, options));
+ if (r < 0) {
+ ret = -1;
+ goto finish;
}
- ret += lyb_write(out, &zero, sizeof zero, &lybs);
+ /* all used models */
+ ret += (r = lyb_print_data_models(out, root, &lybs));
+ if (r < 0) {
+ ret = -1;
+ goto finish;
+ }
+
+ LY_TREE_FOR(root, root) {
+ ret += (r = lyb_print_subtree(out, root, &top_sibling_ht, &lybs, options, 1));
+ if (r < 0) {
+ ret = -1;
+ goto finish;
+ }
+
+ if (!(options & LYP_WITHSIBLINGS)) {
+ break;
+ }
+ }
+
+ /* ending zero byte */
+ ret += (r = lyb_write(out, &zero, sizeof zero, &lybs));
+ if (r < 0) {
+ ret = -1;
+ }
finish:
if (top_sibling_ht) {
diff --git a/src/tree_data.c b/src/tree_data.c
index ba12a72..cabfab8 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -924,7 +924,7 @@
result = lyd_parse_json(ctx, data, options, rpc_act, data_tree, yang_data_name);
break;
case LYD_LYB:
- result = lyd_parse_lyb(ctx, data, options, rpc_act, data_tree, yang_data_name, NULL);
+ result = lyd_parse_lyb(ctx, data, options, data_tree, yang_data_name, NULL);
break;
default:
/* error */
@@ -5006,7 +5006,7 @@
}
/* add default values, resolve unres and check for mandatory nodes in final tree */
- if (lyd_defaults_add_unres(node, options, ctx, data_tree, act_notif, unres)) {
+ if (lyd_defaults_add_unres(node, options, ctx, data_tree, act_notif, unres, 1)) {
goto cleanup;
}
if (act_notif) {
@@ -7017,24 +7017,9 @@
return EXIT_SUCCESS;
}
-/**
- * @brief Process (add/clean) default nodes in the data tree and resolve the unresolved items
- *
- * @param[in,out] root Pointer to the root node of the complete data tree, the root node can be NULL if the data tree
- * is empty
- * @param[in] options Parser options to know the data tree type, see @ref parseroptions.
- * @param[in] ctx Context for the case the \p root is empty (in that case \p ctx must not be NULL)
- * @param[in] data_tree Additional data tree for validating RPC/action/notification. The tree is used to satisfy
- * possible references to the datastore content.
- * @param[in] act_notif In case of nested action/notification, pointer to the subroot of the action/notification. Note
- * that in this case the \p root points to the top level data tree node which provides the context
- * for the nested action/notification
- * @param[in] unres Unresolved data list, the newly added default nodes may need to add some unresolved items
- * @return EXIT_SUCCESS or EXIT_FAILURE
- */
int
lyd_defaults_add_unres(struct lyd_node **root, int options, struct ly_ctx *ctx, const struct lyd_node *data_tree,
- struct lyd_node *act_notif, struct unres_data *unres)
+ struct lyd_node *act_notif, struct unres_data *unres, int wd)
{
struct lyd_node *msg_sibling = NULL, *msg_parent = NULL, *data_tree_sibling, *data_tree_parent;
struct lys_node *msg_op = NULL;
@@ -7080,7 +7065,7 @@
}
/* add missing default nodes */
- if (lyd_wd_add((act_notif ? &act_notif : root), ctx, unres, options)) {
+ if (wd && lyd_wd_add((act_notif ? &act_notif : root), ctx, unres, options)) {
return EXIT_FAILURE;
}
diff --git a/src/tree_data.h b/src/tree_data.h
index 97d249d..057ce95 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -530,7 +530,7 @@
* @param[in] ctx Context to connect with the data tree being built here.
* @param[in] data Serialized data in the specified format.
* @param[in] format Format of the input data to be parsed.
- * @param[in] options Parser options, see @ref parseroptions.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
* @param[in] ... Variable arguments depend on \p options. If they include:
* - #LYD_OPT_DATA:
* - #LYD_OPT_CONFIG:
@@ -568,7 +568,7 @@
* @param[in] ctx Context to connect with the data tree being built here.
* @param[in] fd The standard file descriptor of the file containing the data tree in the specified format.
* @param[in] format Format of the input data to be parsed.
- * @param[in] options Parser options, see @ref parseroptions.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
* @param[in] ... Variable arguments depend on \p options. If they include:
* - #LYD_OPT_DATA:
* - #LYD_OPT_CONFIG:
@@ -604,7 +604,7 @@
* @param[in] ctx Context to connect with the data tree being built here.
* @param[in] path Path to the file containing the data tree in the specified format.
* @param[in] format Format of the input data to be parsed.
- * @param[in] options Parser options, see @ref parseroptions.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
* @param[in] ... Variable arguments depend on \p options. If they include:
* - #LYD_OPT_DATA:
* - #LYD_OPT_CONFIG:
@@ -1240,14 +1240,11 @@
/**
* @brief Print data tree in the specified format.
*
-* Same as lyd_print(), but it allocates memory and store the data into it.
-* It is up to caller to free the returned string by free().
-*
* @param[out] strp Pointer to store the resulting dump.
* @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
* node of the data tree to print the specific subtree.
* @param[in] format Data output format.
-* @param[in] options [printer flags](@ref printerflags).
+* @param[in] options [printer flags](@ref printerflags). \p format LYD_LYB accepts only #LYP_WITHSIBLINGS option.
* @return 0 on success, 1 on failure (#ly_errno is set).
*/
int lyd_print_mem(char **strp, const struct lyd_node *root, LYD_FORMAT format, int options);
@@ -1255,13 +1252,11 @@
/**
* @brief Print data tree in the specified format.
*
- * Same as lyd_print(), but output is written into the specified file descriptor.
- *
* @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
* node of the data tree to print the specific subtree.
* @param[in] fd File descriptor where to print the data.
* @param[in] format Data output format.
- * @param[in] options [printer flags](@ref printerflags).
+ * @param[in] options [printer flags](@ref printerflags). \p format LYD_LYB accepts only #LYP_WITHSIBLINGS option.
* @return 0 on success, 1 on failure (#ly_errno is set).
*/
int lyd_print_fd(int fd, const struct lyd_node *root, LYD_FORMAT format, int options);
@@ -1269,13 +1264,11 @@
/**
* @brief Print data tree in the specified format.
*
- * To write data into a file descriptor, use lyd_print_fd().
- *
* @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
* node of the data tree to print the specific subtree.
* @param[in] f File stream where to print the data.
* @param[in] format Data output format.
- * @param[in] options [printer flags](@ref printerflags).
+ * @param[in] options [printer flags](@ref printerflags). \p format LYD_LYB accepts only #LYP_WITHSIBLINGS option.
* @return 0 on success, 1 on failure (#ly_errno is set).
*/
int lyd_print_file(FILE *f, const struct lyd_node *root, LYD_FORMAT format, int options);
@@ -1283,14 +1276,12 @@
/**
* @brief Print data tree in the specified format.
*
- * Same as lyd_print(), but output is written via provided callback.
- *
* @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
* node of the data tree to print the specific subtree.
* @param[in] writeclb Callback function to write the data (see write(1)).
* @param[in] arg Optional caller-specific argument to be passed to the \p writeclb callback.
* @param[in] format Data output format.
- * @param[in] options [printer flags](@ref printerflags).
+ * @param[in] options [printer flags](@ref printerflags). \p format LYD_LYB accepts only #LYP_WITHSIBLINGS option.
* @return 0 on success, 1 on failure (#ly_errno is set).
*/
int lyd_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg,
diff --git a/src/tree_internal.h b/src/tree_internal.h
index 063742c..931a1a4 100644
--- a/src/tree_internal.h
+++ b/src/tree_internal.h
@@ -70,6 +70,8 @@
size_t *position;
int used;
int size;
+ const struct lys_module **models;
+ int mod_count;
};
/* struct lyb_state allocation step */
@@ -104,11 +106,11 @@
/* Maximum size that will be written into LYB_SIZE_BYTES (must be large enough) */
#define LYB_SIZE_MAX 255
-LYB_HASH lyb_hash(const struct lys_node *sibling, uint8_t collision_id);
+LYB_HASH lyb_hash(struct lys_node *sibling, uint8_t collision_id);
-struct hash_table *lyb_hash_siblings(struct lys_node *sibling);
+int lyb_has_schema_model(struct lys_node *sibling, const struct lys_module **models, int mod_count);
-LYB_HASH lyb_hash_find(struct hash_table *ht, const struct lys_node *node);
+struct hash_table *lyb_hash_siblings(struct lys_node *sibling, const struct lys_module **models, int mod_count);
/**
* Macros to work with ::lyd_node#when_status
@@ -508,22 +510,23 @@
int lys_ingrouping(const struct lys_node *node);
/**
- * @brief Add default values, \p resolve unres, and finally
- * remove any redundant default values based on \p options.
+ * @brief Process (add/clean) default nodes in the data tree and resolve the unresolved items
*
- * @param[in] root Data tree root. With empty data tree, new default nodes can be created so the root pointer
- * will contain/return the newly created data tree.
- * @param[in] options Options for the inserting data to the target data tree options, see @ref parseroptions.
- * @param[in] ctx Optional parameter. If provided, default nodes from all modules in the context will be added.
- * If NULL, only the modules explicitly mentioned in data tree are taken into account.
- * @param[in] data_tree Additional data tree to be traversed when evaluating when or must expressions in \p root
- * tree.
- * @param[in] act_notif Action/notification itself in case \p root is actually an action/notification.
- * @param[in] unres Valid unres structure, on function successful exit they are all resolved.
- * @return 0 on success, nonzero on failure.
+ * @param[in,out] root Pointer to the root node of the complete data tree, the root node can be NULL if the data tree
+ * is empty
+ * @param[in] options Parser options to know the data tree type, see @ref parseroptions.
+ * @param[in] ctx Context for the case the \p root is empty (in that case \p ctx must not be NULL)
+ * @param[in] data_tree Additional data tree for validating RPC/action/notification. The tree is used to satisfy
+ * possible references to the datastore content.
+ * @param[in] act_notif In case of nested action/notification, pointer to the subroot of the action/notification. Note
+ * that in this case the \p root points to the top level data tree node which provides the context
+ * for the nested action/notification
+ * @param[in] unres Unresolved data list, the newly added default nodes may need to add some unresolved items
+ * @param[in] wd Whether to add default values.
+ * @return EXIT_SUCCESS or EXIT_FAILURE
*/
int lyd_defaults_add_unres(struct lyd_node **root, int options, struct ly_ctx *ctx, const struct lyd_node *data_tree,
- struct lyd_node *act_notif, struct unres_data *unres);
+ struct lyd_node *act_notif, struct unres_data *unres, int wd);
void lys_enable_deviations(struct lys_module *module);
diff --git a/src/tree_schema.h b/src/tree_schema.h
index e7c47fa..6f722ac 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1210,6 +1210,15 @@
* @}
*/
+#ifdef LY_ENABLED_CACHE
+
+/**
+ * @brief Maximum number of hashes stored in a schema node if cache is enabled.
+ */
+#define LYS_NODE_HASH_COUNT 4
+
+#endif
+
/**
* @brief Common structure representing single YANG data statement describing.
*
@@ -1256,7 +1265,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
} _PACKED;
@@ -1298,7 +1307,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
/* specific container's data */
@@ -1389,7 +1398,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
/* specific leaf's data */
@@ -1443,7 +1452,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
/* specific leaf-list's data */
@@ -1498,7 +1507,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
/* specific list's data */
@@ -1555,7 +1564,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
/* specific anyxml's data */
@@ -1773,7 +1782,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
/* specific rpc's data */
@@ -1819,7 +1828,7 @@
void *priv; /**< private caller's data, not used by libyang */
#ifdef LY_ENABLED_CACHE
- uint8_t hash; /**< schema hash required for LYB printer/parser */
+ uint8_t hash[LYS_NODE_HASH_COUNT]; /**< schema hash required for LYB printer/parser */
#endif
/* specific rpc's data */