diff options
Diffstat (limited to 'src/ecbor.c')
| -rw-r--r-- | src/ecbor.c | 498 |
1 files changed, 302 insertions, 196 deletions
diff --git a/src/ecbor.c b/src/ecbor.c index 1e95830..59583ba 100644 --- a/src/ecbor.c +++ b/src/ecbor.c @@ -58,38 +58,42 @@ ecbor_uint64_from_big_endian (uint64_t value) #endif } -extern float +float ecbor_fp32_from_big_endian (float value) { #if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) return value; #elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - uint32_t r = ecbor_uint32_from_big_endian(*((uint32_t *) &value)); - return *((float *) &r); + /* while it looks like a lot of casts, we're doing this just so we follow + aliasing rules; the compiler will optimize */ + uint8_t *base = (uint8_t *) &value; + uint32_t r = ecbor_uint32_from_big_endian(*((uint32_t *) base)); + base = (uint8_t *) &r; + return *((float *) base); #else #error "Endianness not supported!" #endif } -extern double +double ecbor_fp64_from_big_endian (double value) { #if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) return value; #elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - uint64_t r = ecbor_uint64_from_big_endian(*((uint64_t *) &value)); - return *((double *) &r); + uint8_t *base = (uint8_t *) &value; + uint64_t r = ecbor_uint64_from_big_endian(*((uint64_t *) base)); + base = (uint8_t *) &r; + return *((double *) base); #else #error "Endianness not supported!" #endif } -extern ecbor_type_t +ecbor_type_t ecbor_get_type (ecbor_item_t *item) { - if (!item) { - return ECBOR_TYPE_NONE; - } + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); if (item->type < ECBOR_TYPE_FIRST || item->type > ECBOR_TYPE_LAST) { return ECBOR_TYPE_NONE; @@ -97,50 +101,21 @@ ecbor_get_type (ecbor_item_t *item) return item->type; } -extern ecbor_error_t -ecbor_get_value (ecbor_item_t *item, void *value) +ecbor_error_t +ecbor_get_length (ecbor_item_t *item, size_t *length) { - if (!item) { - return ECBOR_ERR_NULL_ITEM; - } - if (!value) { - return ECBOR_ERR_NULL_VALUE; - } + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); + ECBOR_INTERNAL_CHECK_VALUE_PTR (length); switch (item->type) { - case ECBOR_TYPE_NINT: - *((int64_t *)value) = item->value.integer; - break; - - case ECBOR_TYPE_UINT: - *((uint64_t *)value) = item->value.uinteger; - break; - case ECBOR_TYPE_BSTR: case ECBOR_TYPE_STR: - if (item->is_indefinite) { - return ECBOR_ERR_WONT_RETURN_INDEFINITE; - } - *((uint8_t **)value) = (uint8_t *) item->value.string.str; - break; - - case ECBOR_TYPE_TAG: - *((uint64_t *)value) = item->value.tag.tag_value; - break; - - case ECBOR_TYPE_FP16: - return ECBOR_ERR_CURRENTLY_NOT_SUPPORTED; - - case ECBOR_TYPE_FP32: - *((float *)value) = item->value.fp32; + case ECBOR_TYPE_ARRAY: + *length = item->length; break; - case ECBOR_TYPE_FP64: - *((double *)value) = item->value.fp64; - break; - - case ECBOR_TYPE_BOOL: - *((uint64_t *)value) = item->value.uinteger; + case ECBOR_TYPE_MAP: + *length = item->length / 2; break; default: @@ -150,67 +125,136 @@ ecbor_get_value (ecbor_item_t *item, void *value) return ECBOR_OK; } -extern ecbor_error_t -ecbor_get_length (ecbor_item_t *item, uint64_t *length) +ecbor_error_t +ecbor_get_array_item (ecbor_item_t *array, size_t index, + ecbor_item_t *item) { - if (!item) { - return ECBOR_ERR_NULL_ITEM; - } - if (!length) { - return ECBOR_ERR_NULL_VALUE; - } - - switch (item->type) { - case ECBOR_TYPE_BSTR: - case ECBOR_TYPE_STR: - case ECBOR_TYPE_ARRAY: - *length = item->length; - break; + ecbor_error_t rc; - case ECBOR_TYPE_MAP: - *length = item->length / 2; - break; + if (!array) { + return ECBOR_ERR_NULL_ARRAY; + } + ECBOR_INTERNAL_CHECK_TYPE (array->type, ECBOR_TYPE_ARRAY); + ECBOR_INTERNAL_CHECK_BOUNDS (index, array->length); + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); - default: - return ECBOR_ERR_INVALID_TYPE; + if (array->child) { + /* parsed in tree mode */ + ecbor_item_t *item_ptr; + rc = ecbor_get_array_item_ptr (array, index, &item_ptr); + if (rc != ECBOR_OK) { + return rc; + } + + /* copy contents */ + (*item) = (*item_ptr); + } else { + /* parsed in normal mode, we must re-parse it */ + ecbor_decode_context_t context; + size_t i; + + 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_array_item (ecbor_item_t *array, uint64_t index, - ecbor_item_t *item) +ecbor_error_t +ecbor_get_array_item_ptr (ecbor_item_t *array, size_t index, + ecbor_item_t **item) { - ecbor_decode_context_t context; - ecbor_error_t rc; - uint64_t i; + + size_t i; if (!array) { return ECBOR_ERR_NULL_ARRAY; } - if (array->type != ECBOR_TYPE_ARRAY) { - return ECBOR_ERR_INVALID_TYPE; - } - if (array->length <= index) { - return ECBOR_ERR_INDEX_OUT_OF_BOUNDS; + ECBOR_INTERNAL_CHECK_TYPE (array->type, ECBOR_TYPE_ARRAY); + ECBOR_INTERNAL_CHECK_BOUNDS (index, array->length); + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); + if (!array->child) { + return ECBOR_ERR_WRONG_MODE; } - if (!item) { - return ECBOR_ERR_NULL_ITEM; + + (*item) = array->child; + for (i = 0; i < index; i ++) { + (*item) = (*item)->next; + if (!(*item)) { + /* internal error, this should not have happened */ + return ECBOR_ERR_UNKNOWN; + } } - rc = ecbor_initialize_decode (&context, array->value.items, array->size); - if (rc != ECBOR_OK) { - return rc; + return ECBOR_OK; +} + +ecbor_error_t +ecbor_get_map_item (ecbor_item_t *map, size_t index, ecbor_item_t *key, + ecbor_item_t *value) +{ + ecbor_error_t rc; + + if (!map) { + return ECBOR_ERR_NULL_MAP; } - - for (i = 0; i <= index; i ++) { - rc = ecbor_decode (&context, item); + + ECBOR_INTERNAL_CHECK_TYPE (map->type, ECBOR_TYPE_MAP); + ECBOR_INTERNAL_CHECK_BOUNDS ((index * 2), map->length); + ECBOR_INTERNAL_CHECK_ITEM_PTR (key); + ECBOR_INTERNAL_CHECK_ITEM_PTR (value); + + if (map->child) { + /* parsed in tree mode */ + ecbor_item_t *k, *v; + rc = ecbor_get_map_item_ptr (map, index, &k, &v); if (rc != ECBOR_OK) { - if (rc == ECBOR_END_OF_BUFFER) { - return ECBOR_ERR_INVALID_END_OF_BUFFER; - } else { - return rc; + return rc; + } + + /* copy contents */ + (*key) = (*k); + (*value) = (*v); + } else { + /* parsed in normal mode */ + ecbor_decode_context_t context; + size_t i; + + 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; + } } } } @@ -218,43 +262,63 @@ ecbor_get_array_item (ecbor_item_t *array, uint64_t index, 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_error_t +ecbor_get_map_item_ptr (ecbor_item_t *map, size_t index, ecbor_item_t **key, + ecbor_item_t **value) { - ecbor_decode_context_t context; - ecbor_error_t rc; - uint64_t i; + size_t i; if (!map) { return ECBOR_ERR_NULL_MAP; } - if (map->type != ECBOR_TYPE_MAP) { - return ECBOR_ERR_INVALID_TYPE; - } - if (map->length <= (index * 2)) { - return ECBOR_ERR_INDEX_OUT_OF_BOUNDS; + + ECBOR_INTERNAL_CHECK_TYPE (map->type, ECBOR_TYPE_MAP); + ECBOR_INTERNAL_CHECK_BOUNDS ((index * 2), map->length); + ECBOR_INTERNAL_CHECK_ITEM_PTR (key); + ECBOR_INTERNAL_CHECK_ITEM_PTR (value); + if (!map->child) { + return ECBOR_ERR_WRONG_MODE; } - if (!key || !value) { - return ECBOR_ERR_NULL_ITEM; + + (*key) = map->child; + for (i = 0; i < index * 2; i ++) { + (*key) = (*key)->next; + if (!(*key)) { + /* internal error, this should not have happened */ + return ECBOR_ERR_UNKNOWN; + } } - rc = ecbor_initialize_decode (&context, map->value.items, map->size); - if (rc != ECBOR_OK) { - return rc; + (*value) = (*key)->next; + if (!(*value)) { + /* internal error, this should not have happened */ + return ECBOR_ERR_UNKNOWN; } - - for (i = 0; i <= index; i ++) { - rc = ecbor_decode (&context, key); + + return ECBOR_OK; +} + +ecbor_error_t +ecbor_get_tag_item (ecbor_item_t *tag, ecbor_item_t *item) +{ + ECBOR_INTERNAL_CHECK_ITEM_PTR (tag); + ECBOR_INTERNAL_CHECK_VALUE_PTR (item); + ECBOR_INTERNAL_CHECK_TYPE (tag->type, ECBOR_TYPE_TAG); + + if (tag->child) { + /* parsed in tree mode; copy contents */ + (*item) = (*tag->child); + } else { + /* parsed in normal mode */ + ecbor_decode_context_t context; + ecbor_error_t rc; + + rc = ecbor_initialize_decode (&context, tag->value.tag.child, tag->size); if (rc != ECBOR_OK) { - if (rc == ECBOR_END_OF_BUFFER) { - return ECBOR_ERR_INVALID_END_OF_BUFFER; - } else { - return rc; - } + return rc; } - - rc = ecbor_decode (&context, value); + + rc = ecbor_decode (&context, item); if (rc != ECBOR_OK) { if (rc == ECBOR_END_OF_BUFFER) { return ECBOR_ERR_INVALID_END_OF_BUFFER; @@ -267,51 +331,75 @@ ecbor_get_map_item (ecbor_item_t *map, uint64_t index, ecbor_item_t *key, return ECBOR_OK; } -extern ecbor_error_t -ecbor_get_tag_item (ecbor_item_t *tag, ecbor_item_t *item) +ecbor_error_t +ecbor_get_tag_item_ptr (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->type != ECBOR_TYPE_TAG) { - return ECBOR_ERR_INVALID_TYPE; - } - if (!item) { - return ECBOR_ERR_NULL_VALUE; - } - - rc = ecbor_initialize_decode (&context, tag->value.tag.child, 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; - } + ECBOR_INTERNAL_CHECK_ITEM_PTR (tag); + ECBOR_INTERNAL_CHECK_VALUE_PTR (item); + ECBOR_INTERNAL_CHECK_TYPE (tag->type, ECBOR_TYPE_TAG); + if (!tag->child) { + return ECBOR_ERR_WRONG_MODE; } + (*item) = tag->child; return ECBOR_OK; } -static inline ecbor_error_t -ecbor_get_string_internal (ecbor_item_t *str, uint8_t **value, ecbor_type_t type) + +#define ECBOR_GET_INTEGER_INTERNAL(item, value, etype, btype) \ +{ \ + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); \ + ECBOR_INTERNAL_CHECK_VALUE_PTR (value); \ + ECBOR_INTERNAL_CHECK_TYPE ((item)->type, (etype)); \ + (*value) = (btype) item->value.uinteger; \ + return (item->size - 1 <= sizeof(btype) \ + ? ECBOR_OK \ + : ECBOR_ERR_VALUE_OVERFLOW); \ +} + +ecbor_error_t +ecbor_get_uint8 (ecbor_item_t *item, uint8_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_UINT, uint8_t) + +ecbor_error_t +ecbor_get_uint16 (ecbor_item_t *item, uint16_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_UINT, uint16_t) + +ecbor_error_t +ecbor_get_uint32 (ecbor_item_t *item, uint32_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_UINT, uint32_t) + +ecbor_error_t +ecbor_get_uint64 (ecbor_item_t *item, uint64_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_UINT, uint64_t) + +ecbor_error_t +ecbor_get_int8 (ecbor_item_t *item, int8_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_NINT, int8_t) + +ecbor_error_t +ecbor_get_int16 (ecbor_item_t *item, int16_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_NINT, int16_t) + +ecbor_error_t +ecbor_get_int32 (ecbor_item_t *item, int32_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_NINT, int32_t) + +ecbor_error_t +ecbor_get_int64 (ecbor_item_t *item, int64_t *value) +ECBOR_GET_INTEGER_INTERNAL (item, value, ECBOR_TYPE_NINT, int64_t) + +#undef ECBOR_GET_INTEGER_INTERNAL + + +static __attribute__((noinline)) ecbor_error_t +ecbor_get_string_internal (ecbor_item_t *str, uint8_t **value, + ecbor_type_t type) { - if (!str) { - return ECBOR_ERR_NULL_ITEM; - } - if (!value) { - return ECBOR_ERR_NULL_VALUE; - } - if (str->type != type) { - return ECBOR_ERR_INVALID_TYPE; - } + ECBOR_INTERNAL_CHECK_ITEM_PTR (str); + ECBOR_INTERNAL_CHECK_VALUE_PTR (value); + ECBOR_INTERNAL_CHECK_TYPE (str->type, type); + if (str->is_indefinite) { return ECBOR_ERR_WONT_RETURN_INDEFINITE; } @@ -321,19 +409,14 @@ ecbor_get_string_internal (ecbor_item_t *str, uint8_t **value, ecbor_type_t type return ECBOR_OK; } -static inline ecbor_error_t -ecbor_get_string_chunk_count_internal (ecbor_item_t *str, uint64_t *count, +static __attribute__((noinline)) ecbor_error_t +ecbor_get_string_chunk_count_internal (ecbor_item_t *str, size_t *count, ecbor_type_t type) { - if (!str) { - return ECBOR_ERR_NULL_ITEM; - } - if (!count) { - return ECBOR_ERR_NULL_VALUE; - } - if (str->type != type) { - return ECBOR_ERR_INVALID_TYPE; - } + ECBOR_INTERNAL_CHECK_ITEM_PTR (str); + ECBOR_INTERNAL_CHECK_VALUE_PTR (count); + ECBOR_INTERNAL_CHECK_TYPE (str->type, type); + if (!str->is_indefinite) { return ECBOR_ERR_WONT_RETURN_DEFINITE; } @@ -343,30 +426,23 @@ ecbor_get_string_chunk_count_internal (ecbor_item_t *str, uint64_t *count, return ECBOR_OK; } -static inline ecbor_error_t -ecbor_get_string_chunk_internal (ecbor_item_t *str, uint64_t index, +static __attribute__((noinline)) ecbor_error_t +ecbor_get_string_chunk_internal (ecbor_item_t *str, size_t index, ecbor_item_t *chunk, ecbor_type_t type) { ecbor_decode_context_t context; ecbor_error_t rc; - uint64_t i; + size_t i; + + ECBOR_INTERNAL_CHECK_ITEM_PTR (str); + ECBOR_INTERNAL_CHECK_VALUE_PTR (chunk); + ECBOR_INTERNAL_CHECK_TYPE (str->type, type); - if (!str) { - return ECBOR_ERR_NULL_ITEM; - } - if (!chunk) { - return ECBOR_ERR_NULL_VALUE; - } - if (str->type != type) { - return ECBOR_ERR_INVALID_TYPE; - } if (!str->is_indefinite) { return ECBOR_ERR_WONT_RETURN_DEFINITE; } - if (index >= str->value.string.n_chunks) { - return ECBOR_ERR_INDEX_OUT_OF_BOUNDS; - } - + ECBOR_INTERNAL_CHECK_BOUNDS (index, str->value.string.n_chunks) + /* locate chunk */ rc = ecbor_initialize_decode (&context, str->value.string.str, str->size); if (rc != ECBOR_OK) { @@ -402,13 +478,13 @@ ecbor_get_str (ecbor_item_t *str, char **value) } ecbor_error_t -ecbor_get_str_chunk_count (ecbor_item_t *str, uint64_t *count) +ecbor_get_str_chunk_count (ecbor_item_t *str, size_t *count) { return ecbor_get_string_chunk_count_internal (str, count, ECBOR_TYPE_STR); } ecbor_error_t -ecbor_get_str_chunk (ecbor_item_t *str, uint64_t index, ecbor_item_t *chunk) +ecbor_get_str_chunk (ecbor_item_t *str, size_t index, ecbor_item_t *chunk) { return ecbor_get_string_chunk_internal (str, index, chunk, ECBOR_TYPE_STR); } @@ -420,30 +496,60 @@ ecbor_get_bstr (ecbor_item_t *str, uint8_t **value) } ecbor_error_t -ecbor_get_bstr_chunk_count (ecbor_item_t *str, uint64_t *count) +ecbor_get_bstr_chunk_count (ecbor_item_t *str, size_t *count) { return ecbor_get_string_chunk_count_internal (str, count, ECBOR_TYPE_BSTR); } ecbor_error_t -ecbor_get_bstr_chunk (ecbor_item_t *str, uint64_t index, ecbor_item_t *chunk) +ecbor_get_bstr_chunk (ecbor_item_t *str, size_t index, ecbor_item_t *chunk) { return ecbor_get_string_chunk_internal (str, index, chunk, ECBOR_TYPE_BSTR); } + ecbor_error_t -ecbor_get_root (ecbor_decode_context_t *context, ecbor_node_t **root) +ecbor_get_tag_value (ecbor_item_t *tag, uint64_t *tag_value) { - 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; - } + ECBOR_INTERNAL_CHECK_ITEM_PTR (tag); + ECBOR_INTERNAL_CHECK_VALUE_PTR (tag_value); + ECBOR_INTERNAL_CHECK_TYPE (tag->type, ECBOR_TYPE_TAG); + + (*tag_value) = tag->value.tag.tag_value; + return ECBOR_OK; +} + + +ecbor_error_t +ecbor_get_fp32 (ecbor_item_t *item, float *value) +{ + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); + ECBOR_INTERNAL_CHECK_VALUE_PTR (value); + ECBOR_INTERNAL_CHECK_TYPE (item->type, ECBOR_TYPE_FP32); + + (*value) = item->value.fp32; + return ECBOR_OK; +} + +ecbor_error_t +ecbor_get_fp64 (ecbor_item_t *item, double *value) +{ + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); + ECBOR_INTERNAL_CHECK_VALUE_PTR (value); + ECBOR_INTERNAL_CHECK_TYPE (item->type, ECBOR_TYPE_FP64); + + (*value) = item->value.fp64; + return ECBOR_OK; +} + + +ecbor_error_t +ecbor_get_bool (ecbor_item_t *item, uint8_t *value) +{ + ECBOR_INTERNAL_CHECK_ITEM_PTR (item); + ECBOR_INTERNAL_CHECK_VALUE_PTR (value); + ECBOR_INTERNAL_CHECK_TYPE (item->type, ECBOR_TYPE_BOOL); - *root = &context->nodes[0]; + (*value) = (uint8_t) item->value.uinteger; return ECBOR_OK; }
\ No newline at end of file |
