lyb parser & printer CHANGE base implementation finished
All basic features should be implemented, practically
not tested at all.
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;