summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrimio <vasi.vilvoiu@gmail.com>2018-02-27 01:12:57 +0200
committerrimio <vasi.vilvoiu@gmail.com>2018-02-27 01:12:57 +0200
commit9dcff75ee0d2831879939c5e9510a5a8120ea0bb (patch)
tree10cfcef5dc462c2cd0d9ce06d2d3158f71a00960
parent5c5694dc87e2a752809ee40bac6604fd3a8a275e (diff)
Partial decoder
-rw-r--r--include/ecbor.h6
-rw-r--r--src/ecbor_decoder.c103
2 files changed, 83 insertions, 26 deletions
diff --git a/include/ecbor.h b/include/ecbor.h
index a4aed39..3c875ee 100644
--- a/include/ecbor.h
+++ b/include/ecbor.h
@@ -75,6 +75,10 @@ typedef struct {
union {
uint64_t uinteger;
int64_t integer;
+ struct {
+ uint64_t tag_value;
+ const uint8_t *child;
+ } tag;
const uint8_t *string;
const uint8_t *items;
} value;
@@ -96,7 +100,9 @@ typedef struct ecbor_node ecbor_node_t;
struct ecbor_node {
ecbor_item_t item;
ecbor_node_t *parent;
+ ecbor_node_t *child; /* first child */
ecbor_node_t *next; /* next in array or map */
+ ecbor_node_t *prev; /* ditto */
uint64_t index; /* index in array or map */
};
diff --git a/src/ecbor_decoder.c b/src/ecbor_decoder.c
index ccc8196..3330598 100644
--- a/src/ecbor_decoder.c
+++ b/src/ecbor_decoder.c
@@ -371,7 +371,28 @@ ecbor_decode_next_internal (ecbor_decode_context_t *context,
break;
case ECBOR_MT_TAG:
- return ECBOR_ERR_CURRENTLY_NOT_SUPPORTED;
+ {
+ ecbor_error_t rc;
+
+ /* decode tag */
+ rc = ecbor_decode_uint (context, &item->value.tag.tag_value,
+ &item->size, additional);
+ if (rc != ECBOR_OK) {
+ return rc;
+ }
+
+ /* keep child pointer */
+ item->value.tag.child = context->in_position;
+ item->n_chunks = 1;
+
+ if (context->mode != ECBOR_MODE_DECODE_STREAMED) {
+ ecbor_item_t child;
+
+ /* not in streamed mode; compute size so we can advance */
+ return ecbor_decode_next_internal (context, &child, false,
+ ECBOR_MT_UNDEFINED);
+ }
+ }
break;
case ECBOR_MT_SPECIAL:
@@ -394,7 +415,7 @@ ecbor_error_t
ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
{
ecbor_error_t rc = ECBOR_OK;
- ecbor_node_t *curr_prev = NULL, *curr_parent = NULL, *curr_node = NULL;
+ ecbor_node_t *curr_node = NULL, *prev_node = NULL, *par_node = NULL;
if (!context) {
return ECBOR_ERR_NULL_CONTEXT;
@@ -426,16 +447,12 @@ ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
goto end;
}
- curr_prev = curr_node;
curr_node = &context->nodes[context->n_nodes];
+ curr_node->next = NULL;
+ curr_node->prev = NULL;
+ curr_node->parent = NULL;
+ curr_node->child = NULL;
context->n_nodes ++;
-
- if (curr_prev) {
- curr_prev->next = curr_node;
- curr_node->index = curr_prev->index + 1;
- } else {
- curr_node->index = 0;
- }
/* consume next item */
rc = ecbor_decode_next_internal (context, &curr_node->item, false,
@@ -443,36 +460,35 @@ ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
/* handle end of indefinite */
if (rc == ECBOR_END_OF_INDEFINITE) {
- if ((!curr_parent)
- || (curr_parent->item.major_type != ECBOR_MT_MAP
- && curr_parent->item.major_type != ECBOR_MT_ARRAY)
- || (!curr_parent->item.is_indefinite)) {
+ if ((!par_node)
+ || (par_node->item.major_type != ECBOR_MT_MAP
+ && par_node->item.major_type != ECBOR_MT_ARRAY)
+ || (!par_node->item.is_indefinite)) {
/* we are not in an indefinite map or array */
rc = ECBOR_ERR_INVALID_STOP_CODE;
goto end;
}
+
+ if (par_node && par_node->item.major_type == ECBOR_MT_MAP
+ && prev_node && (prev_node->index % 2 == 0)) {
+ /* map must have even number of children */
+ rc = ECBOR_ERR_INVALID_KEY_VALUE_PAIR;
+ goto end;
+ }
/* jump up one level */
- curr_node = curr_parent;
- curr_parent = curr_parent->parent;
+ curr_node = par_node;
+ par_node = curr_node->parent;
+ prev_node = curr_node->prev;
/* ignore this item, reuse it later */
context->n_nodes --;
continue;
}
- /* handle new children */
- if (curr_node->item.major_type == ECBOR_MT_MAP
- || curr_node->item.major_type == ECBOR_MT_ARRAY) {
- /* TODO */
- }
-
- /* handle end of definite maps and arrays */
- /* TODO */
-
/* check return code */
if (rc == ECBOR_END_OF_BUFFER) {
- if (!curr_parent) {
+ if (par_node) {
/* we are not allowed to reach the end unless the item is top-level */
rc = ECBOR_ERR_INVALID_END_OF_BUFFER;
goto end;
@@ -480,6 +496,41 @@ ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
} else if (rc != ECBOR_OK) {
goto end;
}
+
+ /* link in tree */
+ if (prev_node) {
+ prev_node->next = curr_node;
+ curr_node->prev = prev_node;
+ }
+ if (par_node) {
+ curr_node->parent = par_node;
+ if (!prev_node) {
+ par_node->child = curr_node;
+ }
+ }
+
+ /* handle new children */
+ if (curr_node->item.major_type == ECBOR_MT_MAP
+ || curr_node->item.major_type == ECBOR_MT_ARRAY
+ || curr_node->item.major_type == ECBOR_MT_TAG) {
+ /* jump a level down */
+ par_node = curr_node;
+ prev_node = NULL;
+ continue;
+ }
+
+ /* handle end of definite maps and arrays, and tags */
+ while (par_node
+ && (par_node->item.major_type == ECBOR_MT_MAP
+ || par_node->item.major_type == ECBOR_MT_ARRAY
+ || par_node->item.major_type == ECBOR_MT_TAG)
+ && !par_node->item.is_indefinite
+ && par_node->item.n_chunks == (curr_node->index + 1)) {
+ /* parent has filled all items, jump a level up */
+ curr_node = par_node;
+ par_node = curr_node->parent;
+ prev_node = curr_node->prev;
+ }
}
end: