summaryrefslogtreecommitdiff
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
parent9dcff75ee0d2831879939c5e9510a5a8120ea0bb (diff)
Strict API
-rw-r--r--include/ecbor.h83
-rw-r--r--src/ecbor.c218
-rw-r--r--src/ecbor_decoder.c50
3 files changed, 332 insertions, 19 deletions
diff --git a/include/ecbor.h b/include/ecbor.h
index 3c875ee..1712537 100644
--- a/include/ecbor.h
+++ b/include/ecbor.h
@@ -22,23 +22,30 @@ typedef enum {
ECBOR_ERR_NULL_CONTEXT = 10,
ECBOR_ERR_NULL_INPUT_BUFFER = 11,
ECBOR_ERR_NULL_OUTPUT_BUFFER = 12,
- ECBOR_ERR_NULL_ITEM_BUFFER = 13,
+ ECBOR_ERR_NULL_NODE_BUFFER = 13,
+ ECBOR_ERR_NULL_VALUE = 14,
+ ECBOR_ERR_NULL_ARRAY = 15,
+ ECBOR_ERR_NULL_MAP = 16,
ECBOR_ERR_NULL_ITEM = 20,
+ ECBOR_ERR_NULL_NODE = 21,
ECBOR_ERR_WRONG_MODE = 30,
-
+
/* bounds errors */
ECBOR_ERR_INVALID_END_OF_BUFFER = 50,
ECBOR_ERR_END_OF_NODE_BUFFER = 51,
+ ECBOR_ERR_EMPTY_NODE_BUFFER = 52,
+ ECBOR_ERR_INDEX_OUT_OF_BOUNDS = 53,
- /* syntax errors */
+ /* semantic errors */
ECBOR_ERR_CURRENTLY_NOT_SUPPORTED = 100,
ECBOR_ERR_INVALID_ADDITIONAL = 101,
ECBOR_ERR_INVALID_CHUNK_MAJOR_TYPE = 102,
ECBOR_ERR_NESTET_INDEFINITE_STRING = 103,
ECBOR_ERR_INVALID_KEY_VALUE_PAIR = 104,
ECBOR_ERR_INVALID_STOP_CODE = 105,
+ ECBOR_ERR_INVALID_TYPE = 106,
/* control codes */
ECBOR_END_OF_BUFFER = 200,
@@ -173,13 +180,81 @@ ecbor_initialize_decode_tree (ecbor_decode_context_t *context,
/*
+ * Encoding routines
+ */
+
+
+/*
* Decoding routines
*/
extern ecbor_error_t
ecbor_decode (ecbor_decode_context_t *context, ecbor_item_t *item);
+extern ecbor_error_t
+ecbor_decode_tree (ecbor_decode_context_t *context);
+
/*
- * Encoding routines
+ * Tree API
+ */
+extern ecbor_error_t
+ecbor_get_root (ecbor_decode_context_t *context, ecbor_node_t **root);
+
+/*
+ * Strict API
+ */
+extern ecbor_major_type_t
+ecbor_get_type (ecbor_item_t *item);
+
+extern ecbor_error_t
+ecbor_get_value (ecbor_item_t *item, void *value);
+
+extern ecbor_error_t
+ecbor_get_length (ecbor_item_t *item, uint64_t *length);
+
+extern ecbor_error_t
+ecbor_get_array_item (ecbor_item_t *array, uint64_t index,
+ ecbor_item_t *arr_item);
+
+extern ecbor_error_t
+ecbor_get_map_item (ecbor_item_t *map, uint64_t index, ecbor_item_t *key,
+ ecbor_item_t *value);
+
+extern ecbor_error_t
+ecbor_get_tag_item (ecbor_item_t *tag, ecbor_item_t *arr_item);
+
+
+/*
+ * Inline API
*/
+#define ECBOR_GET_TYPE(i) \
+ ((i).major_type)
+
+#define ECBOR_IS_NINT(i) \
+ ((i).major_type == ECBOR_MT_NINT)
+#define ECBOR_IS_UINT(i) \
+ ((i).major_type == ECBOR_MT_UINT)
+#define ECBOR_IS_INTEGER(i) \
+ (ECBOR_IS_NINT(i) || ECBOR_IS_UINT(i))
+#define ECBOR_IS_BSTR(i) \
+ ((i).major_type == ECBOR_MT_BSTR)
+#define ECBOR_IS_STR(i) \
+ ((i).major_type == ECBOR_MT_STR)
+#define ECBOR_IS_ARRAY(i) \
+ ((i).major_type == ECBOR_MT_ARRAY)
+#define ECBOR_IS_MAP(i) \
+ ((i).major_type == ECBOR_MT_MAP)
+#define ECBOR_IS_TAG(i) \
+ ((i).major_type == ECBOR_MT_TAG)
+
+#define ECBOR_GET_INT(i) \
+ ((i).value.integer)
+#define ECBOR_GET_UINT(i) \
+ ((i).value.uinteger)
+#define ECBOR_GET_BSTR(i) \
+ ((i).value.string)
+#define ECBOR_GET_STR(i) \
+ ((i).value.string)
+#define ECBOR_GET_TAG(i) \
+ ((i).value.tag.tag_value)
#endif \ No newline at end of file
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