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 /src | |
| parent | 9dcff75ee0d2831879939c5e9510a5a8120ea0bb (diff) | |
Strict API
Diffstat (limited to 'src')
| -rw-r--r-- | src/ecbor.c | 218 | ||||
| -rw-r--r-- | src/ecbor_decoder.c | 50 |
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 |
