diff options
| author | rimio <vasi.vilvoiu@gmail.com> | 2018-02-27 20:05:58 +0200 |
|---|---|---|
| committer | rimio <vasi.vilvoiu@gmail.com> | 2018-02-27 20:05:58 +0200 |
| commit | da204f2f2d1262a4e88590cb1e4e4f0ed62bc371 (patch) | |
| tree | a71773e5fc083cc189c1c82f6702fa206b315d3a | |
| parent | 9dcff75ee0d2831879939c5e9510a5a8120ea0bb (diff) | |
Strict API
| -rw-r--r-- | include/ecbor.h | 83 | ||||
| -rw-r--r-- | src/ecbor.c | 218 | ||||
| -rw-r--r-- | src/ecbor_decoder.c | 50 |
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 |
