summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrimio <vasi.vilvoiu@gmail.com>2018-02-27 20:05:58 +0200
committerrimio <vasi.vilvoiu@gmail.com>2018-02-27 20:05:58 +0200
commitda204f2f2d1262a4e88590cb1e4e4f0ed62bc371 (patch)
treea71773e5fc083cc189c1c82f6702fa206b315d3a /src
parent9dcff75ee0d2831879939c5e9510a5a8120ea0bb (diff)
Strict API
Diffstat (limited to 'src')
-rw-r--r--src/ecbor.c218
-rw-r--r--src/ecbor_decoder.c50
2 files changed, 253 insertions, 15 deletions
diff --git a/src/ecbor.c b/src/ecbor.c
index 11984a6..882f729 100644
--- a/src/ecbor.c
+++ b/src/ecbor.c
@@ -6,3 +6,221 @@
*/
#include "ecbor.h"
+
+extern ecbor_major_type_t
+ecbor_get_type (ecbor_item_t *item)
+{
+ if (!item) {
+ return ECBOR_MT_UNDEFINED;
+ }
+ if (item->major_type < ECBOR_MT_UINT
+ || item->major_type > ECBOR_MT_SPECIAL) {
+ return ECBOR_MT_UNDEFINED;
+ }
+ return item->major_type;
+}
+
+extern ecbor_error_t
+ecbor_get_value (ecbor_item_t *item, void *value)
+{
+ if (!item) {
+ return ECBOR_ERR_NULL_ITEM;
+ }
+ if (!value) {
+ return ECBOR_ERR_NULL_VALUE;
+ }
+
+ switch (item->major_type) {
+ case ECBOR_MT_NINT:
+ *((int64_t *)value) = item->value.integer;
+ break;
+
+ case ECBOR_MT_UINT:
+ *((uint64_t *)value) = item->value.uinteger;
+ break;
+
+ case ECBOR_MT_BSTR:
+ case ECBOR_MT_STR:
+ *((uint8_t **)value) = (uint8_t *) item->value.string;
+ break;
+
+ case ECBOR_MT_TAG:
+ *((uint64_t *)value) = item->value.tag.tag_value;
+ break;
+
+ default:
+ return ECBOR_ERR_INVALID_TYPE;
+ }
+
+ return ECBOR_OK;
+}
+
+extern ecbor_error_t
+ecbor_get_length (ecbor_item_t *item, uint64_t *length)
+{
+ if (!item) {
+ return ECBOR_ERR_NULL_ITEM;
+ }
+ if (!length) {
+ return ECBOR_ERR_NULL_VALUE;
+ }
+
+ switch (item->major_type) {
+ case ECBOR_MT_BSTR:
+ case ECBOR_MT_STR:
+ *length = item->size;
+ break;
+
+ case ECBOR_MT_ARRAY:
+ *length = item->n_chunks;
+ break;
+
+ case ECBOR_MT_MAP:
+ *length = item->n_chunks / 2;
+ break;
+
+ default:
+ return ECBOR_ERR_INVALID_TYPE;
+ }
+
+ return ECBOR_OK;
+}
+
+extern ecbor_error_t
+ecbor_get_array_item (ecbor_item_t *array, uint64_t index,
+ ecbor_item_t *item)
+{
+ ecbor_decode_context_t context;
+ ecbor_error_t rc;
+ uint64_t i;
+
+ if (!array) {
+ return ECBOR_ERR_NULL_ARRAY;
+ }
+ if (array->major_type != ECBOR_MT_ARRAY) {
+ return ECBOR_ERR_INVALID_TYPE;
+ }
+ if (array->n_chunks <= index) {
+ return ECBOR_ERR_INDEX_OUT_OF_BOUNDS;
+ }
+ if (!item) {
+ return ECBOR_ERR_NULL_ITEM;
+ }
+
+ rc = ecbor_initialize_decode (&context, array->value.items, array->size);
+ if (rc != ECBOR_OK) {
+ return rc;
+ }
+
+ for (i = 0; i < index; i ++) {
+ rc = ecbor_decode (&context, item);
+ if (rc != ECBOR_OK) {
+ if (rc == ECBOR_END_OF_BUFFER) {
+ return ECBOR_ERR_INVALID_END_OF_BUFFER;
+ } else {
+ return rc;
+ }
+ }
+ }
+
+ return ECBOR_OK;
+}
+
+extern ecbor_error_t
+ecbor_get_map_item (ecbor_item_t *map, uint64_t index, ecbor_item_t *key,
+ ecbor_item_t *value)
+{
+ ecbor_decode_context_t context;
+ ecbor_error_t rc;
+ uint64_t i;
+
+ if (!map) {
+ return ECBOR_ERR_NULL_MAP;
+ }
+ if (map->major_type != ECBOR_MT_ARRAY) {
+ return ECBOR_ERR_INVALID_TYPE;
+ }
+ if (map->n_chunks <= (index * 2)) {
+ return ECBOR_ERR_INDEX_OUT_OF_BOUNDS;
+ }
+ if (!key || !value) {
+ return ECBOR_ERR_NULL_ITEM;
+ }
+
+ rc = ecbor_initialize_decode (&context, map->value.items, map->size);
+ if (rc != ECBOR_OK) {
+ return rc;
+ }
+
+ for (i = 0; i < index; i ++) {
+ rc = ecbor_decode (&context, key);
+ if (rc != ECBOR_OK) {
+ if (rc == ECBOR_END_OF_BUFFER) {
+ return ECBOR_ERR_INVALID_END_OF_BUFFER;
+ } else {
+ return rc;
+ }
+ }
+
+ rc = ecbor_decode (&context, value);
+ if (rc != ECBOR_OK) {
+ if (rc == ECBOR_END_OF_BUFFER) {
+ return ECBOR_ERR_INVALID_END_OF_BUFFER;
+ } else {
+ return rc;
+ }
+ }
+ }
+
+ return ECBOR_OK;
+}
+
+extern ecbor_error_t
+ecbor_get_tag_item (ecbor_item_t *tag, ecbor_item_t *item)
+{
+ ecbor_decode_context_t context;
+ ecbor_error_t rc;
+
+ if (!tag) {
+ return ECBOR_ERR_NULL_ITEM;
+ }
+ if (tag->major_type != ECBOR_MT_ARRAY) {
+ return ECBOR_ERR_INVALID_TYPE;
+ }
+ if (!item) {
+ return ECBOR_ERR_NULL_VALUE;
+ }
+
+ rc = ecbor_initialize_decode (&context, tag->value.items, tag->size);
+ if (rc != ECBOR_OK) {
+ return rc;
+ }
+
+ rc = ecbor_decode (&context, item);
+ if (rc != ECBOR_OK) {
+ if (rc == ECBOR_END_OF_BUFFER) {
+ return ECBOR_ERR_INVALID_END_OF_BUFFER;
+ } else {
+ return rc;
+ }
+ }
+
+ return ECBOR_OK;
+}
+
+extern ecbor_error_t
+ecbor_get_root (ecbor_decode_context_t *context, ecbor_node_t **root)
+{
+ if (!context) {
+ return ECBOR_ERR_NULL_CONTEXT;
+ }
+ if (!root) {
+ return ECBOR_ERR_NULL_NODE;
+ }
+ if (context->n_nodes <= 0) {
+ return ECBOR_ERR_EMPTY_NODE_BUFFER;
+ }
+
+ *root = &context->nodes[0];
+ return ECBOR_OK;
+} \ No newline at end of file
diff --git a/src/ecbor_decoder.c b/src/ecbor_decoder.c
index 3330598..c53dc2f 100644
--- a/src/ecbor_decoder.c
+++ b/src/ecbor_decoder.c
@@ -81,7 +81,7 @@ ecbor_initialize_decode_tree (ecbor_decode_context_t *context,
}
if (!node_buffer) {
- return ECBOR_ERR_NULL_ITEM_BUFFER;
+ return ECBOR_ERR_NULL_NODE_BUFFER;
}
context->mode = ECBOR_MODE_DECODE_TREE;
@@ -405,6 +405,9 @@ ecbor_decode_next_internal (ecbor_decode_context_t *context,
break;
default:
+ /* while this would theoretically be a case for invalid type, any 3 bit
+ value should be a valid type, so this branch is an internal error and
+ should never happen */
return ECBOR_ERR_UNKNOWN;
}
@@ -413,10 +416,7 @@ ecbor_decode_next_internal (ecbor_decode_context_t *context,
ecbor_error_t
ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
-{
- ecbor_error_t rc = ECBOR_OK;
- ecbor_node_t *curr_node = NULL, *prev_node = NULL, *par_node = NULL;
-
+{
if (!context) {
return ECBOR_ERR_NULL_CONTEXT;
}
@@ -424,22 +424,34 @@ ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
return ECBOR_ERR_NULL_ITEM;
}
- if (context->mode == ECBOR_MODE_DECODE
- || context->mode == ECBOR_MODE_DECODE_STREAMED) {
- /* we just get the next item */
- return ecbor_decode_next_internal (context, item, false, ECBOR_MT_UNDEFINED);
+ if (context->mode != ECBOR_MODE_DECODE
+ && context->mode != ECBOR_MODE_DECODE_STREAMED) {
+ /* context is for wrong mode */
+ return ECBOR_ERR_WRONG_MODE;
+ }
+
+ /* we just get the next item */
+ return ecbor_decode_next_internal (context, item, false, ECBOR_MT_UNDEFINED);
+}
+
+extern ecbor_error_t
+ecbor_decode_tree (ecbor_decode_context_t *context)
+{
+ ecbor_error_t rc = ECBOR_OK;
+ ecbor_node_t *curr_node = NULL, *prev_node = NULL, *par_node = NULL;
+
+ if (!context) {
+ return ECBOR_ERR_NULL_CONTEXT;
}
- /*
- * decode whole tree
- */
+ /* initialization */
context->n_nodes = 0;
/* step into streamed mode; some of the semantic checks will be done here */
context->mode = ECBOR_MODE_DECODE_STREAMED;
- /* consume until something happens */
- while (true) {
+ /* consume until end of buffer or error */
+ while (rc != ECBOR_OK) {
/* allocate new node */
if (context->n_nodes >= context->node_capacity) {
@@ -453,7 +465,7 @@ ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
curr_node->parent = NULL;
curr_node->child = NULL;
context->n_nodes ++;
-
+
/* consume next item */
rc = ecbor_decode_next_internal (context, &curr_node->item, false,
ECBOR_MT_UNDEFINED);
@@ -481,6 +493,9 @@ ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
par_node = curr_node->parent;
prev_node = curr_node->prev;
+ /* continue parsing */
+ rc = ECBOR_OK;
+
/* ignore this item, reuse it later */
context->n_nodes --;
continue;
@@ -536,5 +551,10 @@ ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item)
end:
/* return to tree mode and return error code */
context->mode = ECBOR_MODE_DECODE_TREE;
+ rc = (rc == ECBOR_END_OF_BUFFER ? ECBOR_OK : rc);
+ if (rc != ECBOR_OK) {
+ /* make sure we don't expose garbage to user */
+ context->n_nodes = 0;
+ }
return rc;
} \ No newline at end of file