diff --git a/CMakeLists.txt b/CMakeLists.txt index c025e95e5f..5d98cf34e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -911,6 +911,11 @@ if(BUILD_TESTING AND(UNIX OR MINGW)) list(APPEND TEST_LINK_LIBS Threads::Threads) endif() + try_compile(HAVE_FLOAT16 ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tools/test_float16.c) + if(HAVE_FLOAT16) + list(APPEND TEST_COMPILE_DEFINITIONS "HAVE_FLOAT16") + endif() + # Disable clang-tidy for gtest oc_disable_clang_tidy() @@ -980,7 +985,7 @@ if(BUILD_TESTING AND(UNIX OR MINGW)) file(GLOB COMMONTEST_SRC tests/gtest/*.cpp tests/gtest/tls/*.cpp) # Unit tests - file(GLOB APITEST_SRC api/unittest/*.cpp api/client/unittest/*.cpp) + file(GLOB APITEST_SRC api/unittest/*.cpp api/unittest/encoder/*.cpp api/client/unittest/*.cpp) set(apitest_files) if (OC_INTROSPECTION_ENABLED AND OC_IDD_API_ENABLED) set(apitest_files ${PROJECT_SOURCE_DIR}/api/unittest/introspectiontest_IDD.cbor) diff --git a/api/cloud/unittest/cloud_manager_test.cpp b/api/cloud/unittest/cloud_manager_test.cpp index a608826af5..b6a27f18e3 100644 --- a/api/cloud/unittest/cloud_manager_test.cpp +++ b/api/cloud/unittest/cloud_manager_test.cpp @@ -20,6 +20,7 @@ #include "api/cloud/oc_cloud_internal.h" #include "api/cloud/oc_cloud_manager_internal.h" #include "api/cloud/oc_cloud_store_internal.h" +#include "api/oc_rep_internal.h" #include "oc_api.h" #include "oc_rep.h" #include "port/oc_log_internal.h" diff --git a/api/oc_client_api.c b/api/oc_client_api.c index 9a5a681c95..18faa9d334 100644 --- a/api/oc_client_api.c +++ b/api/oc_client_api.c @@ -31,6 +31,7 @@ #include "oc_api.h" #include "oc_message_internal.h" #include "oc_ri_internal.h" +#include "util/oc_secure_string_internal.h" #ifdef OC_TCP #include "messaging/coap/coap_signal.h" @@ -52,94 +53,117 @@ typedef struct oc_dispatch_context_t // a global variable static oc_dispatch_context_t g_dispatch = { NULL, NULL }; -static coap_packet_t g_request[1]; +typedef struct oc_dispatch_request_t +{ + coap_packet_t packet; #ifdef OC_BLOCK_WISE -static oc_blockwise_state_t *g_request_buffer = NULL; + oc_blockwise_state_t *buffer; #endif /* OC_BLOCK_WISE */ +} oc_dispatch_request_t; + +static oc_dispatch_request_t g_request; #ifdef OC_OSCORE static oc_message_t *g_multicast_update = NULL; #endif /* OC_OSCORE */ static bool -dispatch_coap_request(void) +dispatch_coap_request_set_payload(oc_dispatch_request_t *request, + const oc_dispatch_context_t *dispatch) { int payload_size = oc_rep_get_encoded_payload_size(); - if ((g_dispatch.client_cb->method == OC_PUT || - g_dispatch.client_cb->method == OC_POST) && + if ((dispatch->client_cb->method == OC_PUT || + dispatch->client_cb->method == OC_POST) && payload_size > 0) { #ifdef OC_BLOCK_WISE - g_request_buffer->payload_size = (uint32_t)payload_size; + request->buffer->payload_size = (uint32_t)payload_size; uint32_t block_size; + if ( #ifdef OC_TCP - if ((g_dispatch.transaction->message->endpoint.flags & TCP) == 0 && - payload_size > OC_BLOCK_SIZE) { -#else /* OC_TCP */ - if ((long)payload_size > OC_BLOCK_SIZE) { -#endif /* !OC_TCP */ + (dispatch->transaction->message->endpoint.flags & TCP) == 0 && +#endif /* OC_TCP */ + (long)payload_size > OC_BLOCK_SIZE) { void *payload = oc_blockwise_dispatch_block( - g_request_buffer, 0, (uint32_t)OC_BLOCK_SIZE, &block_size); + request->buffer, 0, (uint32_t)OC_BLOCK_SIZE, &block_size); if (payload) { - coap_set_payload(g_request, payload, block_size); - coap_options_set_block1(g_request, 0, 1, (uint16_t)block_size, 0); - coap_options_set_size1(g_request, (uint32_t)payload_size); - g_request->type = COAP_TYPE_CON; - g_dispatch.client_cb->qos = HIGH_QOS; + coap_set_payload(&request->packet, payload, block_size); + coap_options_set_block1(&request->packet, 0, 1, (uint16_t)block_size, + 0); + coap_options_set_size1(&request->packet, (uint32_t)payload_size); + request->packet.type = COAP_TYPE_CON; + dispatch->client_cb->qos = HIGH_QOS; } } else { - coap_set_payload(g_request, g_request_buffer->buffer, + coap_set_payload(&request->packet, request->buffer->buffer, (uint32_t)payload_size); - g_request_buffer->ref_count = 0; + request->buffer->ref_count = 0; } #else /* OC_BLOCK_WISE */ - coap_set_payload( - g_request, g_dispatch.transaction->message->data + COAP_MAX_HEADER_SIZE, - (uint32_t)payload_size); + coap_set_payload(&request->packet, + dispatch->transaction->message->data + + COAP_MAX_HEADER_SIZE, + (uint32_t)payload_size); #endif /* !OC_BLOCK_WISE */ } if (payload_size > 0) { + oc_content_format_t cf; + if (!oc_rep_encoder_get_content_format(&cf)) { + return false; + } #ifdef OC_SPEC_VER_OIC - if (g_dispatch.client_cb->endpoint.version == OIC_VER_1_1_0) { - coap_options_set_content_format(g_request, APPLICATION_CBOR); - } else -#endif /* OC_SPEC_VER_OIC */ - { - coap_options_set_content_format(g_request, - oc_rep_encoder_get_content_format()); + if (dispatch->client_cb->endpoint.version == OIC_VER_1_1_0 && + cf == APPLICATION_VND_OCF_CBOR) { + cf = APPLICATION_CBOR; } +#endif /* OC_SPEC_VER_OIC */ + + coap_options_set_content_format(&request->packet, cf); } + return true; +} +static bool +dispatch_coap_request(void) +{ bool success = false; - g_dispatch.transaction->message->length = coap_serialize_message( - g_request, g_dispatch.transaction->message->data, oc_message_buffer_size()); - if (g_dispatch.transaction->message->length > 0) { - coap_send_transaction(g_dispatch.transaction); - - if (g_dispatch.client_cb->observe_seq == OC_COAP_OPTION_OBSERVE_NOT_SET) { - if (g_dispatch.client_cb->qos == LOW_QOS) { - oc_set_delayed_callback(g_dispatch.client_cb, - &oc_client_cb_remove_async, OC_NON_LIFETIME); - } else { - oc_set_delayed_callback(g_dispatch.client_cb, - &oc_client_cb_remove_async, - OC_EXCHANGE_LIFETIME); - } - } + if (!dispatch_coap_request_set_payload(&g_request, &g_dispatch)) { + coap_clear_transaction(g_dispatch.transaction); + oc_client_cb_free(g_dispatch.client_cb); + goto dispatch_coap_request_exit; + } - success = true; - } else { + g_dispatch.transaction->message->length = coap_serialize_message( + &g_request.packet, g_dispatch.transaction->message->data, + oc_message_buffer_size()); + if (g_dispatch.transaction->message->length == 0) { coap_clear_transaction(g_dispatch.transaction); oc_client_cb_free(g_dispatch.client_cb); + goto dispatch_coap_request_exit; + } + + coap_send_transaction(g_dispatch.transaction); + + if (g_dispatch.client_cb->observe_seq == OC_COAP_OPTION_OBSERVE_NOT_SET) { + if (g_dispatch.client_cb->qos == LOW_QOS) { + oc_set_delayed_callback(g_dispatch.client_cb, &oc_client_cb_remove_async, + OC_NON_LIFETIME); + } else { + oc_set_delayed_callback(g_dispatch.client_cb, &oc_client_cb_remove_async, + OC_EXCHANGE_LIFETIME); + } } + success = true; + +dispatch_coap_request_exit: #ifdef OC_BLOCK_WISE - if (g_request_buffer && g_request_buffer->ref_count == 0) { - oc_blockwise_free_request_buffer(g_request_buffer); + if (g_request.buffer != NULL && g_request.buffer->ref_count == 0) { + oc_blockwise_free_request_buffer(g_request.buffer); } - g_request_buffer = NULL; + g_request.buffer = NULL; #endif /* OC_BLOCK_WISE */ g_dispatch.transaction = NULL; @@ -171,66 +195,70 @@ prepare_coap_request(oc_client_cb_t *cb, coap_configure_request_fn_t configure, #ifdef OC_BLOCK_WISE if (cb->method == OC_PUT || cb->method == OC_POST) { - g_request_buffer = oc_blockwise_alloc_request_buffer( + g_request.buffer = oc_blockwise_alloc_request_buffer( oc_string(cb->uri) + 1, oc_string_len(cb->uri) - 1, &cb->endpoint, cb->method, OC_BLOCKWISE_CLIENT, (uint32_t)OC_MIN_APP_DATA_SIZE); - if (!g_request_buffer) { + if (!g_request.buffer) { OC_ERR("global request_buffer is NULL"); return false; } #ifdef OC_DYNAMIC_ALLOCATION #ifdef OC_APP_DATA_BUFFER_POOL - if (g_request_buffer->block) { - oc_rep_new_v1(g_request_buffer->buffer, g_request_buffer->buffer_size); + if (g_request.buffer->block) { + oc_rep_new_v1(g_request.buffer->buffer, g_request.buffer->buffer_size); } else #endif { - oc_rep_new_realloc_v1(&g_request_buffer->buffer, - g_request_buffer->buffer_size, + oc_rep_new_realloc_v1(&g_request.buffer->buffer, + g_request.buffer->buffer_size, OC_MAX_APP_DATA_SIZE); } #else /* OC_DYNAMIC_ALLOCATION */ - oc_rep_new_v1(g_request_buffer->buffer, OC_MIN_APP_DATA_SIZE); + oc_rep_new_v1(g_request.buffer->buffer, OC_MIN_APP_DATA_SIZE); #endif /* !OC_DYNAMIC_ALLOCATION */ - g_request_buffer->mid = cb->mid; - g_request_buffer->client_cb = cb; + g_request.buffer->mid = cb->mid; + g_request.buffer->client_cb = cb; } #endif /* OC_BLOCK_WISE */ #ifdef OC_TCP if (cb->endpoint.flags & TCP) { - coap_tcp_init_message(g_request, (uint8_t)cb->method); + coap_tcp_init_message(&g_request.packet, (uint8_t)cb->method); } else #endif /* OC_TCP */ { - coap_udp_init_message(g_request, type, (uint8_t)cb->method, cb->mid); + coap_udp_init_message(&g_request.packet, type, (uint8_t)cb->method, + cb->mid); } + oc_content_format_t cf; + if (!oc_rep_encoder_get_content_format(&cf)) { + return false; + } #ifdef OC_SPEC_VER_OIC - if (cb->endpoint.version == OIC_VER_1_1_0) { - coap_options_set_accept(g_request, APPLICATION_CBOR); - } else -#endif /* OC_SPEC_VER_OIC */ - { - coap_options_set_accept(g_request, oc_rep_encoder_get_content_format()); + if (cb->endpoint.version == OIC_VER_1_1_0 && cf == APPLICATION_VND_OCF_CBOR) { + cf = APPLICATION_CBOR; } +#endif /* OC_SPEC_VER_OIC */ + + coap_options_set_accept(&g_request.packet, cf); - coap_set_token(g_request, cb->token, cb->token_len); + coap_set_token(&g_request.packet, cb->token, cb->token_len); - coap_options_set_uri_path(g_request, oc_string(cb->uri), + coap_options_set_uri_path(&g_request.packet, oc_string(cb->uri), oc_string_len(cb->uri)); if (cb->observe_seq != OC_COAP_OPTION_OBSERVE_NOT_SET) { - coap_options_set_observe(g_request, cb->observe_seq); + coap_options_set_observe(&g_request.packet, cb->observe_seq); } if (oc_string_len(cb->query) > 0) { - coap_options_set_uri_query(g_request, oc_string(cb->query), + coap_options_set_uri_query(&g_request.packet, oc_string(cb->query), oc_string_len(cb->query)); } if (configure != NULL) { - configure(g_request, configure_data); + configure(&g_request.packet, configure_data); } g_dispatch.client_cb = cb; @@ -268,16 +296,18 @@ oc_do_multicast_update(void) if (payload_size <= 0) { goto do_multicast_update_error; } - coap_set_payload(g_request, g_multicast_update->data + COAP_MAX_HEADER_SIZE, + coap_set_payload(&g_request.packet, + g_multicast_update->data + COAP_MAX_HEADER_SIZE, (uint32_t)payload_size); - if (payload_size > 0) { - coap_options_set_content_format(g_request, - oc_rep_encoder_get_content_format()); + oc_content_format_t cf; + if (!oc_rep_encoder_get_content_format(&cf)) { + goto do_multicast_update_error; } + coap_options_set_content_format(&g_request.packet, cf); g_multicast_update->length = coap_serialize_message( - g_request, g_multicast_update->data, oc_message_buffer_size()); + &g_request.packet, g_multicast_update->data, oc_message_buffer_size()); if (g_multicast_update->length <= 0) { goto do_multicast_update_error; } @@ -316,17 +346,19 @@ oc_init_multicast_update(const char *uri, const char *query) oc_rep_new_v1(g_multicast_update->data + COAP_MAX_HEADER_SIZE, OC_BLOCK_SIZE); - coap_udp_init_message(g_request, type, OC_POST, coap_get_mid()); + coap_udp_init_message(&g_request.packet, type, OC_POST, coap_get_mid()); - coap_options_set_accept(g_request, APPLICATION_VND_OCF_CBOR); + coap_options_set_accept(&g_request.packet, APPLICATION_VND_OCF_CBOR); - g_request->token_len = sizeof(g_request->token); - oc_random_buffer(g_request->token, g_request->token_len); + g_request.packet.token_len = sizeof(g_request.packet.token); + oc_random_buffer(g_request.packet.token, g_request.packet.token_len); - coap_options_set_uri_path(g_request, uri, strlen(uri)); + coap_options_set_uri_path(&g_request.packet, uri, + oc_strnlen(uri, OC_MAX_STRING_LENGTH)); if (query) { - coap_options_set_uri_query(g_request, query, strlen(query)); + coap_options_set_uri_query(&g_request.packet, query, + oc_strnlen(query, OC_MAX_STRING_LENGTH)); } return true; diff --git a/api/oc_rep.c b/api/oc_rep.c index a2fc9af3e0..e866b80d74 100644 --- a/api/oc_rep.c +++ b/api/oc_rep.c @@ -31,10 +31,10 @@ #include -static struct oc_memb *g_rep_objects; +static struct oc_memb *g_rep_objects = NULL; CborEncoder root_map; CborEncoder links_array; -int g_err; +int g_err = CborNoError; void oc_rep_set_pool(struct oc_memb *rep_objects_pool) @@ -46,7 +46,7 @@ void oc_rep_new_v1(uint8_t *payload, size_t size) { g_err = CborNoError; - oc_rep_buffer_init(payload, size); + oc_rep_encoder_buffer_init(oc_rep_global_encoder(), payload, size); } void @@ -62,7 +62,8 @@ void oc_rep_new_realloc_v1(uint8_t **payload, size_t size, size_t max_size) { g_err = CborNoError; - oc_rep_buffer_realloc_init(payload, size, max_size); + oc_rep_encoder_buffer_realloc_init(oc_rep_global_encoder(), payload, size, + max_size); } void diff --git a/api/oc_rep_decode.c b/api/oc_rep_decode.c index cc675a6332..fd8b5a7221 100644 --- a/api/oc_rep_decode.c +++ b/api/oc_rep_decode.c @@ -24,16 +24,6 @@ #include "api/oc_rep_decode_json_internal.h" #endif /* OC_JSON_ENCODER */ -typedef CborError (*oc_rep_parse_payload_t)(const uint8_t *payload, - size_t payload_size, - oc_rep_t **out_rep); - -typedef struct -{ - oc_rep_decoder_type_t type; - oc_rep_parse_payload_t parse; -} oc_rep_decoder_t; - static int oc_rep_parse_cbor(const uint8_t *payload, size_t payload_size, oc_rep_t **out_rep); @@ -515,20 +505,28 @@ oc_rep_parse_cbor(const uint8_t *payload, size_t payload_size, return CborNoError; } -void -oc_rep_decoder_set_type(oc_rep_decoder_type_t decoder_type) +oc_rep_decoder_t +oc_rep_decoder(oc_rep_decoder_type_t type) { - g_rep_decoder.type = decoder_type; - if (g_rep_decoder.type == OC_REP_CBOR_DECODER) { - g_rep_decoder.parse = &oc_rep_parse_cbor; - return; - } + oc_rep_decoder_t decoder = { + .type = OC_REP_CBOR_DECODER, + .parse = &oc_rep_parse_cbor, + }; #ifdef OC_JSON_ENCODER - if (g_rep_decoder.type == OC_REP_JSON_DECODER) { - g_rep_decoder.parse = &oc_rep_parse_json; - return; + if (type == OC_REP_JSON_DECODER) { + decoder.type = OC_REP_JSON_DECODER; + decoder.parse = &oc_rep_parse_json; } +#else /* !OC_JSON_ENCODER */ + (void)type; #endif /* OC_JSON_ENCODER */ + return decoder; +} + +void +oc_rep_decoder_set_type(oc_rep_decoder_type_t type) +{ + g_rep_decoder = oc_rep_decoder(type); } oc_rep_decoder_type_t @@ -538,7 +536,7 @@ oc_rep_decoder_get_type(void) } bool -oc_rep_decoder_set_type_by_content_format(oc_content_format_t content_format) +oc_rep_decoder_set_by_content_format(oc_content_format_t content_format) { if (content_format == APPLICATION_CBOR || content_format == APPLICATION_VND_OCF_CBOR || diff --git a/api/oc_rep_decode_internal.h b/api/oc_rep_decode_internal.h index 8f8c7f2e93..432c471dcf 100644 --- a/api/oc_rep_decode_internal.h +++ b/api/oc_rep_decode_internal.h @@ -34,12 +34,26 @@ typedef enum oc_rep_decoder_type_t { #endif /* OC_JSON_ENCODER */ } oc_rep_decoder_type_t; +/** Parse payload to oc_rep_t */ +typedef CborError (*oc_rep_parse_payload_t)(const uint8_t *payload, + size_t payload_size, + oc_rep_t **out_rep); + +typedef struct +{ + oc_rep_decoder_type_t type; + oc_rep_parse_payload_t parse; +} oc_rep_decoder_t; + +/** Get decoder. */ +oc_rep_decoder_t oc_rep_decoder(oc_rep_decoder_type_t type); + /** - * @brief Set the decoder type to decode the request payload to oc_rep_t. + * @brief Set the global decoder used to decode the request payload to oc_rep_t. * - * @param decoder_type decoder + * @param type decoder type */ -void oc_rep_decoder_set_type(oc_rep_decoder_type_t decoder_type); +void oc_rep_decoder_set_type(oc_rep_decoder_type_t type); /** * @brief Get the decoder type to decode the request payload to oc_rep_t. @@ -56,8 +70,7 @@ oc_rep_decoder_type_t oc_rep_decoder_get_type(void); * @return true if the decoder type was set * @return false otherwise */ -bool oc_rep_decoder_set_type_by_content_format( - oc_content_format_t content_format); +bool oc_rep_decoder_set_by_content_format(oc_content_format_t content_format); #ifdef __cplusplus } diff --git a/api/oc_rep_encode.c b/api/oc_rep_encode.c index 580af53249..9c168ccc2d 100644 --- a/api/oc_rep_encode.c +++ b/api/oc_rep_encode.c @@ -16,146 +16,182 @@ * ****************************************************************************/ +#include "api/oc_rep_encode_cbor_internal.h" +#include "api/oc_rep_encode_internal.h" #include "oc_rep.h" -#include "oc_rep_encode_internal.h" #include "port/oc_log_internal.h" +#include "util/oc_features.h" #ifdef OC_JSON_ENCODER -#include "oc_rep_encode_json_internal.h" +#include "api/oc_rep_encode_json_internal.h" #endif /* OC_JSON_ENCODER */ +#ifdef OC_HAS_FEATURE_CRC_ENCODER +#include "api/oc_rep_encode_crc_internal.h" +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ + #include #include #include #include -typedef struct -{ - uint8_t *buffer; - +static oc_rep_encoder_t g_rep_encoder = { .type = OC_REP_CBOR_ENCODER, + .impl = OC_REP_CBOR_ENCODER_INIT, + .buffer = { + .ptr = NULL, + .size = 0, #ifdef OC_DYNAMIC_ALLOCATION - size_t buffer_size; - size_t buffer_max_size; - uint8_t **buffer_ptr; - bool enable_realloc; + .max_size = 0, + .pptr = NULL, + .enable_realloc = false, #endif /* OC_DYNAMIC_ALLOCATION */ -} oc_rep_buffer_t; + }, }; -CborEncoder g_encoder; - -static oc_rep_buffer_t g_rep_buffer = { - .buffer = NULL, -#ifdef OC_DYNAMIC_ALLOCATION - .buffer_size = 0, - .buffer_max_size = 0, - .buffer_ptr = NULL, - .enable_realloc = false, -#endif /* OC_DYNAMIC_ALLOCATION */ -}; +oc_rep_encoder_t * +oc_rep_global_encoder(void) +{ + return &g_rep_encoder; +} -#define OC_REP_CBOR_ENCODER_INIT \ - { \ - .type = OC_REP_CBOR_ENCODER, \ - \ - .encode_null = &cbor_encode_null, .encode_boolean = &cbor_encode_boolean, \ - .encode_int = &cbor_encode_int, .encode_uint = &cbor_encode_uint, \ - .encode_floating_point = &cbor_encode_floating_point, \ - .encode_double = &cbor_encode_double, \ - .encode_text_string = &cbor_encode_text_string, \ - .encode_byte_string = &cbor_encode_byte_string, \ - .create_array = &cbor_encoder_create_array, \ - .create_map = &cbor_encoder_create_map, \ - .close_container = &cbor_encoder_close_container, \ +void +oc_rep_encoder_convert_ptr_to_offset(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder) +{ + if (encoder->buffer.ptr == NULL || subEncoder->data.ptr == NULL || + subEncoder->end == NULL) { + return; } + subEncoder->data.ptr = + (uint8_t *)(subEncoder->data.ptr - encoder->buffer.ptr); + subEncoder->end = (uint8_t *)(subEncoder->end - encoder->buffer.ptr); +} -static oc_rep_encoder_t g_rep_encoder = OC_REP_CBOR_ENCODER_INIT; - -oc_rep_encoder_t -oc_rep_cbor_encoder(void) +void +oc_rep_encoder_convert_offset_to_ptr(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder) { - return (oc_rep_encoder_t)OC_REP_CBOR_ENCODER_INIT; + if (encoder->buffer.ptr == NULL || + // don't convert in bytes needed state + (subEncoder->data.ptr != NULL && subEncoder->end == NULL)) { + return; + } + subEncoder->data.ptr = encoder->buffer.ptr + (intptr_t)subEncoder->data.ptr; + subEncoder->end = encoder->buffer.ptr + (intptr_t)encoder->buffer.size; } -#undef OC_REP_CBOR_ENCODER_INIT +static void +rep_cbor_context_init(oc_rep_encoder_t *encoder, size_t size) +{ + cbor_encoder_init(&encoder->ctx, encoder->buffer.ptr, size, 0); + oc_rep_encoder_convert_ptr_to_offset(encoder, &encoder->ctx); +} -CborEncoder * -oc_rep_encoder_convert_offset_to_ptr(CborEncoder *encoder) +void +oc_rep_encoder_buffer_init(oc_rep_encoder_t *encoder, uint8_t *buffer, + size_t size) { - if (!encoder || (encoder->data.ptr && !encoder->end)) { - return encoder; - } - encoder->data.ptr = g_rep_buffer.buffer + (intptr_t)encoder->data.ptr; + encoder->buffer.ptr = buffer; + encoder->buffer.size = size; #ifdef OC_DYNAMIC_ALLOCATION - encoder->end = - g_rep_buffer.buffer ? g_rep_buffer.buffer + g_rep_buffer.buffer_size : NULL; -#else /* OC_DYNAMIC_ALLOCATION */ - encoder->end = g_rep_buffer.buffer + (intptr_t)encoder->end; -#endif /* !OC_DYNAMIC_ALLOCATION */ - return encoder; + encoder->buffer.enable_realloc = false; + encoder->buffer.pptr = NULL; + encoder->buffer.max_size = size; +#endif /* OC_DYNAMIC_ALLOCATION */ + rep_cbor_context_init(encoder, size); } -CborEncoder * -oc_rep_encoder_convert_ptr_to_offset(CborEncoder *encoder) +#ifdef OC_DYNAMIC_ALLOCATION + +void +oc_rep_encoder_buffer_realloc_init(oc_rep_encoder_t *encoder, uint8_t **buffer, + size_t size, size_t max_size) { - if (!encoder || (encoder->data.ptr && !encoder->end)) { - return encoder; - } - encoder->data.ptr = (uint8_t *)(encoder->data.ptr - g_rep_buffer.buffer); - encoder->end = (uint8_t *)(encoder->end - g_rep_buffer.buffer); - return encoder; + encoder->buffer.size = size; + encoder->buffer.max_size = max_size; + encoder->buffer.pptr = buffer; + encoder->buffer.ptr = *buffer; + encoder->buffer.enable_realloc = true; + rep_cbor_context_init(encoder, size); } +#endif /* OC_DYNAMIC_ALLOCATION */ + #ifdef OC_DYNAMIC_ALLOCATION static size_t -oc_rep_encoder_get_extra_bytes_needed(CborEncoder *encoder) +rep_encoder_get_extra_bytes_needed(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - size_t size = cbor_encoder_get_extra_bytes_needed(encoder); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + size_t size = encoder->impl.get_extra_bytes_needed(subEncoder); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return size; } static CborError -realloc_buffer(size_t needed) +rep_buffer_realloc(oc_rep_encoder_t *encoder, size_t needed) { - if (!g_rep_buffer.enable_realloc || - g_rep_buffer.buffer_size + needed > g_rep_buffer.buffer_max_size) { + if (!encoder->buffer.enable_realloc) { return CborErrorOutOfMemory; } + if (encoder->buffer.size + needed > encoder->buffer.max_size) { + OC_WRN("Insufficient memory: Increase OC_MAX_APP_DATA_SIZE to accomodate a " + "larger payload(+%d)", + (int)needed); + return CborErrorOutOfMemory; + } + // preallocate buffer to avoid reallocation - if (2 * (g_rep_buffer.buffer_size + needed) < - (g_rep_buffer.buffer_max_size / 4)) { - needed += g_rep_buffer.buffer_size + needed; + if (2 * (encoder->buffer.size + needed) < (encoder->buffer.max_size / 4)) { + needed += encoder->buffer.size + needed; } else { - needed = g_rep_buffer.buffer_max_size - g_rep_buffer.buffer_size; + needed = encoder->buffer.max_size - encoder->buffer.size; } - uint8_t *tmp = (uint8_t *)realloc(*g_rep_buffer.buffer_ptr, - g_rep_buffer.buffer_size + needed); + size_t new_size = encoder->buffer.size + needed; + uint8_t *tmp = (uint8_t *)realloc(*encoder->buffer.pptr, new_size); if (tmp == NULL) { + OC_ERR("Memory reallocation failed"); return CborErrorOutOfMemory; } - *g_rep_buffer.buffer_ptr = tmp; - g_rep_buffer.buffer = tmp; - g_rep_buffer.buffer_size = g_rep_buffer.buffer_size + needed; + *encoder->buffer.pptr = tmp; + encoder->buffer.ptr = tmp; + encoder->buffer.size = new_size; return CborNoError; } #endif /* OC_DYNAMIC_ALLOCATION */ -void -oc_rep_encoder_set_type(oc_rep_encoder_type_t encoder_type) +oc_rep_encoder_t +oc_rep_encoder(oc_rep_encoder_type_t type, oc_rep_encoder_buffer_t buffer) { - if (encoder_type == OC_REP_CBOR_ENCODER) { - g_rep_encoder = oc_rep_cbor_encoder(); - return; - } + oc_rep_encoder_t encoder = { + .type = OC_REP_CBOR_ENCODER, + .impl = oc_rep_cbor_encoder(), + }; #ifdef OC_JSON_ENCODER - if (encoder_type == OC_REP_JSON_ENCODER) { - g_rep_encoder = oc_rep_json_encoder(); - return; + if (type == OC_REP_JSON_ENCODER) { + encoder.type = OC_REP_JSON_ENCODER; + encoder.impl = oc_rep_json_encoder(); } #endif /* OC_JSON_ENCODER */ + +#ifdef OC_HAS_FEATURE_CRC_ENCODER + if (type == OC_REP_CRC_ENCODER) { + encoder.type = OC_REP_CRC_ENCODER; + encoder.impl = oc_rep_crc_encoder(); + } +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ + + (void)type; + encoder.buffer = buffer; + rep_cbor_context_init(&encoder, encoder.buffer.size); + return encoder; +} + +void +oc_rep_encoder_set_type(oc_rep_encoder_type_t type) +{ + g_rep_encoder = oc_rep_encoder(type, g_rep_encoder.buffer); } oc_rep_encoder_type_t @@ -181,100 +217,119 @@ oc_rep_encoder_set_type_by_accept(oc_content_format_t accept) return false; } -oc_content_format_t -oc_rep_encoder_get_content_format(void) +bool +oc_rep_encoder_get_content_format(oc_content_format_t *format) { #ifdef OC_JSON_ENCODER if (g_rep_encoder.type == OC_REP_JSON_ENCODER) { - return APPLICATION_JSON; + *format = APPLICATION_JSON; + return true; } #endif /* OC_JSON_ENCODER */ - return APPLICATION_VND_OCF_CBOR; -} +#ifdef OC_HAS_FEATURE_CRC_ENCODER + if (g_rep_encoder.type == OC_REP_CRC_ENCODER) { + // encoding of message payloads with crc is not supported + return false; + } +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ -void -oc_rep_buffer_init(uint8_t *buffer, size_t size) -{ - g_rep_buffer.buffer = buffer; -#ifdef OC_DYNAMIC_ALLOCATION - g_rep_buffer.enable_realloc = false; - g_rep_buffer.buffer_size = size; - g_rep_buffer.buffer_ptr = NULL; - g_rep_buffer.buffer_max_size = size; -#endif /* OC_DYNAMIC_ALLOCATION */ - cbor_encoder_init(&g_encoder, g_rep_buffer.buffer, size, 0); - oc_rep_encoder_convert_ptr_to_offset(&g_encoder); + *format = APPLICATION_VND_OCF_CBOR; + return true; } -#ifdef OC_DYNAMIC_ALLOCATION -void -oc_rep_buffer_realloc_init(uint8_t **buffer, size_t size, size_t max_size) +oc_rep_encoder_reset_t +oc_rep_global_encoder_reset(const oc_rep_encoder_reset_t *reset) { - assert(buffer != NULL); - g_rep_buffer.buffer_size = size; - g_rep_buffer.buffer_max_size = max_size; - g_rep_buffer.buffer_ptr = buffer; - g_rep_buffer.buffer = *buffer; - g_rep_buffer.enable_realloc = true; - cbor_encoder_init(&g_encoder, g_rep_buffer.buffer, size, 0); - oc_rep_encoder_convert_ptr_to_offset(&g_encoder); + oc_rep_encoder_reset_t prev = { + .encoder = g_rep_encoder, + }; + prev.root_map_ctx = root_map; + prev.links_array_ctx = links_array; + + if (reset != NULL) { + g_rep_encoder = reset->encoder; + root_map = reset->root_map_ctx; + links_array = reset->links_array_ctx; + g_err = CborNoError; + } + + return prev; } -#endif /* OC_DYNAMIC_ALLOCATION */ CborEncoder * oc_rep_get_encoder(void) { - return &g_encoder; + return &g_rep_encoder.ctx; } const uint8_t * oc_rep_get_encoder_buf(void) { - return g_rep_buffer.buffer; + return g_rep_encoder.buffer.ptr; } #ifdef OC_DYNAMIC_ALLOCATION int oc_rep_get_encoder_buffer_size(void) { - return (int)g_rep_buffer.buffer_size; + return (int)g_rep_encoder.buffer.size; } #endif /* OC_DYNAMIC_ALLOCATION */ +#ifdef OC_DYNAMIC_ALLOCATION + +bool +oc_rep_encoder_shrink_buffer(oc_rep_encoder_t *encoder) +{ + if (!encoder->buffer.enable_realloc || encoder->buffer.pptr == NULL) { + return false; + } + int size = oc_rep_encoder_payload_size(encoder); + if (size <= 0 || size == (int)encoder->buffer.size) { + // if the size is 0, then it means that the encoder was not used at all + // if the size is already the same as the buffer size, then there is no + // need to shrink + return false; + } + uint8_t *tmp = (uint8_t *)realloc(encoder->buffer.ptr, size); + if (tmp == NULL) { + OC_ERR("Memory reallocation failed"); + return false; + } + OC_DBG("encoder buffer was shrinked from %d to %d", (int)encoder->buffer.size, + size); + encoder->buffer.size = (size_t)size; + *encoder->buffer.pptr = tmp; + encoder->buffer.ptr = tmp; + return true; +} + +#endif /* OC_DYNAMIC_ALLOCATION */ + uint8_t * oc_rep_shrink_encoder_buf(uint8_t *buf) { -#ifndef OC_DYNAMIC_ALLOCATION - return buf; -#else /* !OC_DYNAMIC_ALLOCATION */ - if (!g_rep_buffer.enable_realloc || !buf || !g_rep_buffer.buffer_ptr || - buf != g_rep_buffer.buffer) - return buf; - int size = oc_rep_get_encoded_payload_size(); - if (size <= 0) { - // if the size is 0, then it means that the encoder was not used at all +#ifdef OC_DYNAMIC_ALLOCATION + if (buf == NULL || buf != g_rep_encoder.buffer.ptr) { return buf; } - uint8_t *tmp = (uint8_t *)realloc(buf, size); - if (tmp == NULL && size > 0) { + if (!oc_rep_encoder_shrink_buffer(&g_rep_encoder)) { return buf; } - OC_DBG("cbor encoder buffer was shrinked from %d to %d", - (int)g_rep_buffer.buffer_size, size); - g_rep_buffer.buffer_size = (size_t)size; - *g_rep_buffer.buffer_ptr = tmp; - g_rep_buffer.buffer = tmp; - return tmp; + return g_rep_encoder.buffer.ptr; +#else /* !OC_DYNAMIC_ALLOCATION */ + return buf; #endif /* OC_DYNAMIC_ALLOCATION */ } int -oc_rep_get_encoded_payload_size(void) +oc_rep_encoder_payload_size(oc_rep_encoder_t *encoder) { - oc_rep_encoder_convert_offset_to_ptr(&g_encoder); - size_t size = cbor_encoder_get_buffer_size(&g_encoder, g_rep_buffer.buffer); - size_t needed = cbor_encoder_get_extra_bytes_needed(&g_encoder); - oc_rep_encoder_convert_ptr_to_offset(&g_encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, &encoder->ctx); + size_t size = + encoder->impl.get_buffer_size(&encoder->ctx, encoder->buffer.ptr); + size_t needed = encoder->impl.get_extra_bytes_needed(&encoder->ctx); + oc_rep_encoder_convert_ptr_to_offset(encoder, &encoder->ctx); if (g_err == CborErrorOutOfMemory) { OC_WRN("Insufficient memory: Increase OC_MAX_APP_DATA_SIZE to " "accomodate a larger payload(+%d)", @@ -287,409 +342,539 @@ oc_rep_get_encoded_payload_size(void) return (int)size; } -void -oc_rep_encode_raw(const uint8_t *data, size_t len) +int +oc_rep_get_encoded_payload_size(void) { - if (g_encoder.end == NULL) { + return oc_rep_encoder_payload_size(&g_rep_encoder); +} + +CborError +oc_rep_encoder_write_raw(oc_rep_encoder_t *encoder, const uint8_t *data, + size_t len) +{ + if (encoder->ctx.end == NULL) { OC_WRN("encoder has not set end pointer."); - g_err = CborErrorInternalError; - return; + return CborErrorInternalError; } #ifdef OC_DYNAMIC_ALLOCATION - size_t remaining = g_rep_buffer.buffer_size - (size_t)g_encoder.data.ptr; + size_t remaining = encoder->buffer.size - (size_t)encoder->ctx.data.ptr; if (remaining < len) { size_t needed = len - remaining; - if (!g_rep_buffer.enable_realloc) { - OC_WRN("Insufficient memory: Increase OC_MAX_APP_DATA_SIZE to " - "accomodate a larger payload(+%d)", - (int)needed); - g_err = CborErrorOutOfMemory; - return; + if (!encoder->buffer.enable_realloc) { + OC_WRN( + "Insufficient memory: Reallocation of the encoder buffer disabled"); + return CborErrorOutOfMemory; } CborEncoder prevEncoder; - memcpy(&prevEncoder, &g_encoder, sizeof(prevEncoder)); - CborError err = realloc_buffer(needed); + memcpy(&prevEncoder, &encoder->ctx, sizeof(prevEncoder)); + CborError err = rep_buffer_realloc(encoder, needed); if (err != CborNoError) { - g_err = err; - return; + return err; } - memcpy(&g_encoder, &prevEncoder, sizeof(prevEncoder)); + memcpy(&encoder->ctx, &prevEncoder, sizeof(prevEncoder)); } #else /* OC_DYNAMIC_ALLOCATION */ - intptr_t needed = (intptr_t)g_encoder.end - (intptr_t)g_encoder.data.ptr; + intptr_t needed = + (intptr_t)encoder->ctx.end - (intptr_t)encoder->ctx.data.ptr; if (needed < (intptr_t)len) { OC_WRN("Insufficient memory: Increase OC_MAX_APP_DATA_SIZE to " "accomodate a larger payload(+%d)", (int)needed); - g_err = CborErrorOutOfMemory; - return; + return CborErrorOutOfMemory; } #endif /* !OC_DYNAMIC_ALLOCATION */ - oc_rep_encoder_convert_offset_to_ptr(&g_encoder); - memcpy(g_encoder.data.ptr, data, len); - g_encoder.data.ptr = g_encoder.data.ptr + len; - g_err = CborNoError; - oc_rep_encoder_convert_ptr_to_offset(&g_encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, &encoder->ctx); + memcpy(encoder->ctx.data.ptr, data, len); + encoder->ctx.data.ptr = encoder->ctx.data.ptr + len; + oc_rep_encoder_convert_ptr_to_offset(encoder, &encoder->ctx); + return CborNoError; +} + +void +oc_rep_encode_raw(const uint8_t *data, size_t len) +{ + g_err = oc_rep_encoder_write_raw(&g_rep_encoder, data, len); } static CborError -oc_rep_encode_null_internal(CborEncoder *encoder) +rep_encode_null_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_null(encoder); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = encoder->impl.encode_null(subEncoder); + oc_rep_encoder_convert_ptr_to_offset(oc_rep_global_encoder(), subEncoder); return err; } CborError -oc_rep_encode_null(CborEncoder *encoder) +oc_rep_encoder_write_null(oc_rep_encoder_t *encoder, CborEncoder *subEncoder) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_null_internal(encoder); + return rep_encode_null_internal(encoder, subEncoder); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_null_internal(encoder); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = rep_encode_null_internal(encoder, subEncoder); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_null_internal(encoder); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_null_internal(encoder, subEncoder); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_null(CborEncoder *encoder) +{ + return oc_rep_encoder_write_null(&g_rep_encoder, encoder); +} + static CborError -oc_rep_encode_boolean_internal(CborEncoder *encoder, bool value) +rep_encode_boolean_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, bool value) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_boolean(encoder, value); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = encoder->impl.encode_boolean(subEncoder, value); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return err; } CborError -oc_rep_encode_boolean(CborEncoder *encoder, bool value) +oc_rep_encoder_write_boolean(oc_rep_encoder_t *encoder, CborEncoder *subEncoder, + bool value) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_boolean_internal(encoder, value); + return rep_encode_boolean_internal(encoder, subEncoder, value); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_boolean_internal(encoder, value); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = rep_encode_boolean_internal(encoder, subEncoder, value); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_boolean_internal(encoder, value); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_boolean_internal(encoder, subEncoder, value); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_boolean(CborEncoder *encoder, bool value) +{ + return oc_rep_encoder_write_boolean(&g_rep_encoder, encoder, value); +} + static CborError -oc_rep_encode_int_internal(CborEncoder *encoder, int64_t value) +rep_encode_int_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, int64_t value) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_int(encoder, value); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = encoder->impl.encode_int(subEncoder, value); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return err; } CborError -oc_rep_encode_int(CborEncoder *encoder, int64_t value) +oc_rep_encoder_write_int(oc_rep_encoder_t *encoder, CborEncoder *subEncoder, + int64_t value) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_int_internal(encoder, value); + return rep_encode_int_internal(encoder, subEncoder, value); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_int_internal(encoder, value); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = rep_encode_int_internal(encoder, subEncoder, value); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_int_internal(encoder, value); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_int_internal(encoder, subEncoder, value); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_int(CborEncoder *subEncoder, int64_t value) +{ + return oc_rep_encoder_write_int(&g_rep_encoder, subEncoder, value); +} + static CborError -oc_rep_encode_uint_internal(CborEncoder *encoder, uint64_t value) +rep_encode_uint_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, uint64_t value) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_uint(encoder, value); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = encoder->impl.encode_uint(subEncoder, value); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return err; } CborError -oc_rep_encode_uint(CborEncoder *encoder, uint64_t value) +oc_rep_encoder_write_uint(oc_rep_encoder_t *encoder, CborEncoder *subEncoder, + uint64_t value) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_uint_internal(encoder, value); + return rep_encode_uint_internal(encoder, subEncoder, value); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_uint_internal(encoder, value); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = rep_encode_uint_internal(encoder, subEncoder, value); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_uint_internal(encoder, value); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_uint_internal(encoder, subEncoder, value); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_uint(CborEncoder *subEncoder, uint64_t value) +{ + return oc_rep_encoder_write_uint(&g_rep_encoder, subEncoder, value); +} + static CborError -oc_rep_encode_floating_point_internal(CborEncoder *encoder, CborType fpType, - const void *value) +rep_encode_floating_point_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, CborType fpType, + const void *value) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_floating_point(encoder, fpType, value); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = + encoder->impl.encode_floating_point(subEncoder, fpType, value); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return err; } CborError -oc_rep_encode_floating_point(CborEncoder *encoder, CborType fpType, - const void *value) +oc_rep_encoder_write_floating_point(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, CborType fpType, + const void *value) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_floating_point_internal(encoder, fpType, value); + return rep_encode_floating_point_internal(encoder, subEncoder, fpType, value); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_floating_point_internal(encoder, fpType, value); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = + rep_encode_floating_point_internal(encoder, subEncoder, fpType, value); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_floating_point_internal(encoder, fpType, value); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_floating_point_internal(encoder, subEncoder, fpType, + value); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_floating_point(CborEncoder *subEncoder, CborType fpType, + const void *value) +{ + return oc_rep_encoder_write_floating_point(&g_rep_encoder, subEncoder, fpType, + value); +} + static CborError -oc_rep_encode_double_internal(CborEncoder *encoder, double value) +rep_encode_double_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, double value) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_double(encoder, value); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = encoder->impl.encode_double(subEncoder, value); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return err; } CborError -oc_rep_encode_double(CborEncoder *encoder, double value) +oc_rep_encoder_write_double(oc_rep_encoder_t *encoder, CborEncoder *subEncoder, + double value) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_double_internal(encoder, value); + return rep_encode_double_internal(encoder, subEncoder, value); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_double_internal(encoder, value); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = rep_encode_double_internal(encoder, subEncoder, value); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_double_internal(encoder, value); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_double_internal(encoder, subEncoder, value); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_double(CborEncoder *subEncoder, double value) +{ + return oc_rep_encoder_write_double(&g_rep_encoder, subEncoder, value); +} + static CborError -oc_rep_encode_text_string_internal(CborEncoder *encoder, const char *string, - size_t length) +rep_encode_text_string_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, const char *string, + size_t length) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_text_string(encoder, string, length); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = encoder->impl.encode_text_string(subEncoder, string, length); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return err; } CborError -oc_rep_encode_text_string(CborEncoder *encoder, const char *string, - size_t length) +oc_rep_encoder_write_text_string(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, const char *string, + size_t length) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_text_string_internal(encoder, string, length); + return rep_encode_text_string_internal(encoder, subEncoder, string, length); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_text_string_internal(encoder, string, length); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = + rep_encode_text_string_internal(encoder, subEncoder, string, length); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_text_string_internal(encoder, string, length); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_text_string_internal(encoder, subEncoder, string, length); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_text_string(CborEncoder *subEncoder, const char *string, + size_t length) +{ + return oc_rep_encoder_write_text_string(&g_rep_encoder, subEncoder, string, + length); +} + static CborError -oc_rep_encode_byte_string_internal(CborEncoder *encoder, const uint8_t *string, - size_t length) +rep_encode_byte_string_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, const uint8_t *string, + size_t length) { - oc_rep_encoder_convert_offset_to_ptr(encoder); - CborError err = g_rep_encoder.encode_byte_string(encoder, string, length); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + CborError err = encoder->impl.encode_byte_string(subEncoder, string, length); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); return err; } CborError -oc_rep_encode_byte_string(CborEncoder *encoder, const uint8_t *string, - size_t length) +oc_rep_encoder_write_byte_string(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, const uint8_t *string, + size_t length) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encode_byte_string_internal(encoder, string, length); + return rep_encode_byte_string_internal(encoder, subEncoder, string, length); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); - CborError err = oc_rep_encode_byte_string_internal(encoder, string, length); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); + CborError err = + rep_encode_byte_string_internal(encoder, subEncoder, string, length); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encode_byte_string_internal(encoder, string, length); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encode_byte_string_internal(encoder, subEncoder, string, length); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encode_byte_string(CborEncoder *encoder, const uint8_t *string, + size_t length) +{ + return oc_rep_encoder_write_byte_string(&g_rep_encoder, encoder, string, + length); +} + static CborError -oc_rep_encoder_create_array_internal(CborEncoder *encoder, - CborEncoder *arrayEncoder, size_t length) -{ - oc_rep_encoder_convert_offset_to_ptr(encoder); - oc_rep_encoder_convert_offset_to_ptr(arrayEncoder); - CborError err = g_rep_encoder.create_array(encoder, arrayEncoder, length); - oc_rep_encoder_convert_ptr_to_offset(encoder); - oc_rep_encoder_convert_ptr_to_offset(arrayEncoder); +rep_encoder_create_array_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *arrayEncoder, size_t length) +{ + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, arrayEncoder); + CborError err = encoder->impl.create_array(subEncoder, arrayEncoder, length); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); + oc_rep_encoder_convert_ptr_to_offset(encoder, arrayEncoder); return err; } CborError -oc_rep_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, - size_t length) +oc_rep_encoder_write_array_open(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *arrayEncoder, size_t length) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encoder_create_array_internal(encoder, arrayEncoder, length); + return rep_encoder_create_array_internal(encoder, subEncoder, arrayEncoder, + length); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); CborEncoder prevArrayEncoder; memcpy(&prevArrayEncoder, arrayEncoder, sizeof(prevArrayEncoder)); - CborError err = - oc_rep_encoder_create_array_internal(encoder, arrayEncoder, length); + CborError err = rep_encoder_create_array_internal(encoder, subEncoder, + arrayEncoder, length); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(arrayEncoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, arrayEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); memcpy(arrayEncoder, &prevArrayEncoder, sizeof(prevArrayEncoder)); - return oc_rep_encoder_create_array_internal(encoder, arrayEncoder, length); + return rep_encoder_create_array_internal(encoder, subEncoder, arrayEncoder, + length); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encoder_create_array(CborEncoder *subEncoder, CborEncoder *arrayEncoder, + size_t length) +{ + return oc_rep_encoder_write_array_open(&g_rep_encoder, subEncoder, + arrayEncoder, length); +} + static CborError -oc_rep_encoder_create_map_internal(CborEncoder *encoder, - CborEncoder *mapEncoder, size_t length) -{ - oc_rep_encoder_convert_offset_to_ptr(encoder); - oc_rep_encoder_convert_offset_to_ptr(mapEncoder); - CborError err = g_rep_encoder.create_map(encoder, mapEncoder, length); - oc_rep_encoder_convert_ptr_to_offset(encoder); - oc_rep_encoder_convert_ptr_to_offset(mapEncoder); +rep_encoder_create_map_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *mapEncoder, size_t length) +{ + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, mapEncoder); + CborError err = encoder->impl.create_map(subEncoder, mapEncoder, length); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); + oc_rep_encoder_convert_ptr_to_offset(encoder, mapEncoder); return err; } CborError -oc_rep_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, - size_t length) +oc_rep_encoder_write_map_open(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, CborEncoder *mapEncoder, + size_t length) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encoder_create_map_internal(encoder, mapEncoder, length); + return rep_encoder_create_map_internal(encoder, subEncoder, mapEncoder, + length); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevMapEncoder; memcpy(&prevMapEncoder, mapEncoder, sizeof(prevMapEncoder)); CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); CborError err = - oc_rep_encoder_create_map_internal(encoder, mapEncoder, length); + rep_encoder_create_map_internal(encoder, subEncoder, mapEncoder, length); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(mapEncoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, mapEncoder)); if (err != CborNoError) { return err; } memcpy(mapEncoder, &prevMapEncoder, sizeof(prevMapEncoder)); - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); - return oc_rep_encoder_create_map_internal(encoder, mapEncoder, length); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); + return rep_encoder_create_map_internal(encoder, subEncoder, mapEncoder, + length); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } +CborError +oc_rep_encoder_create_map(CborEncoder *subEncoder, CborEncoder *mapEncoder, + size_t length) +{ + return oc_rep_encoder_write_map_open(&g_rep_encoder, subEncoder, mapEncoder, + length); +} + static CborError -oc_rep_encoder_close_container_internal(CborEncoder *encoder, - CborEncoder *containerEncoder) -{ - oc_rep_encoder_convert_offset_to_ptr(encoder); - oc_rep_encoder_convert_offset_to_ptr(containerEncoder); - CborError err = g_rep_encoder.close_container(encoder, containerEncoder); - oc_rep_encoder_convert_ptr_to_offset(encoder); - oc_rep_encoder_convert_ptr_to_offset(containerEncoder); +rep_encoder_close_container_internal(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *containerEncoder) +{ + oc_rep_encoder_convert_offset_to_ptr(encoder, subEncoder); + oc_rep_encoder_convert_offset_to_ptr(encoder, containerEncoder); + CborError err = encoder->impl.close_container(subEncoder, containerEncoder); + oc_rep_encoder_convert_ptr_to_offset(encoder, subEncoder); + oc_rep_encoder_convert_ptr_to_offset(encoder, containerEncoder); return err; } CborError -oc_rep_encoder_close_container(CborEncoder *encoder, - CborEncoder *containerEncoder) +oc_rep_encoder_write_container_close(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *containerEncoder) { #ifndef OC_DYNAMIC_ALLOCATION - return oc_rep_encoder_close_container_internal(encoder, containerEncoder); + return rep_encoder_close_container_internal(encoder, subEncoder, + containerEncoder); #else /* !OC_DYNAMIC_ALLOCATION */ CborEncoder prevContainerEncoder; memcpy(&prevContainerEncoder, containerEncoder, sizeof(prevContainerEncoder)); CborEncoder prevEncoder; - memcpy(&prevEncoder, encoder, sizeof(prevEncoder)); + memcpy(&prevEncoder, subEncoder, sizeof(prevEncoder)); CborError err = - oc_rep_encoder_close_container_internal(encoder, containerEncoder); + rep_encoder_close_container_internal(encoder, subEncoder, containerEncoder); if (err == CborErrorOutOfMemory) { - err = realloc_buffer(oc_rep_encoder_get_extra_bytes_needed(encoder)); + err = rep_buffer_realloc( + encoder, rep_encoder_get_extra_bytes_needed(encoder, subEncoder)); if (err != CborNoError) { return err; } - memcpy(encoder, &prevEncoder, sizeof(prevEncoder)); + memcpy(subEncoder, &prevEncoder, sizeof(prevEncoder)); memcpy(containerEncoder, &prevContainerEncoder, sizeof(prevContainerEncoder)); - return oc_rep_encoder_close_container_internal(encoder, containerEncoder); + return rep_encoder_close_container_internal(encoder, subEncoder, + containerEncoder); } return err; #endif /* OC_DYNAMIC_ALLOCATION */ } + +CborError +oc_rep_encoder_close_container(CborEncoder *subEncoder, + CborEncoder *containerEncoder) +{ + return oc_rep_encoder_write_container_close(&g_rep_encoder, subEncoder, + containerEncoder); +} diff --git a/api/oc_rep_encode_cbor.c b/api/oc_rep_encode_cbor.c new file mode 100644 index 0000000000..e4da65914b --- /dev/null +++ b/api/oc_rep_encode_cbor.c @@ -0,0 +1,27 @@ +/**************************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#include "api/oc_rep_encode_cbor_internal.h" + +#include + +oc_rep_encoder_implementation_t +oc_rep_cbor_encoder(void) +{ + return (oc_rep_encoder_implementation_t)OC_REP_CBOR_ENCODER_INIT; +} diff --git a/api/oc_rep_encode_cbor_internal.h b/api/oc_rep_encode_cbor_internal.h new file mode 100644 index 0000000000..d32e373cba --- /dev/null +++ b/api/oc_rep_encode_cbor_internal.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#ifndef OC_REP_ENCODE_CBOR_INTERNAL_H +#define OC_REP_ENCODE_CBOR_INTERNAL_H + +#include "api/oc_rep_encode_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define OC_REP_CBOR_ENCODER_INIT \ + { \ + .get_buffer_size = &cbor_encoder_get_buffer_size, \ + .get_extra_bytes_needed = &cbor_encoder_get_extra_bytes_needed, \ + \ + .encode_null = &cbor_encode_null, .encode_boolean = &cbor_encode_boolean, \ + .encode_int = &cbor_encode_int, .encode_uint = &cbor_encode_uint, \ + .encode_floating_point = &cbor_encode_floating_point, \ + .encode_double = &cbor_encode_double, \ + .encode_text_string = &cbor_encode_text_string, \ + .encode_byte_string = &cbor_encode_byte_string, \ + .create_array = &cbor_encoder_create_array, \ + .create_map = &cbor_encoder_create_map, \ + .close_container = &cbor_encoder_close_container, \ + } + +/** Return CBOR encoder implementation. */ +oc_rep_encoder_implementation_t oc_rep_cbor_encoder(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OC_REP_ENCODE_JSON_INTERNAL_H */ diff --git a/api/oc_rep_encode_crc.c b/api/oc_rep_encode_crc.c new file mode 100644 index 0000000000..583198401a --- /dev/null +++ b/api/oc_rep_encode_crc.c @@ -0,0 +1,216 @@ +/**************************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#include "util/oc_features.h" + +#ifdef OC_HAS_FEATURE_CRC_ENCODER + +#include "oc_rep_encode_crc_internal.h" +#include "util/oc_crc_internal.h" +#include "util/oc_macros_internal.h" + +typedef enum crc_flag_t { + CrcFlagBytesNeeded = 1 << 0, + CrcFlagHasPayload = 1 << 1, + + CrcFlagIsMap = 1 << 2, +} crc_flag_t; + +static size_t +rep_crc_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer) +{ + (void)buffer; + if ((encoder->flags & CrcFlagHasPayload) != 0) { + return sizeof(uint64_t); + } + return 0; +} + +static size_t +rep_crc_get_extra_bytes_needed(const CborEncoder *encoder) +{ + if ((encoder->flags & CrcFlagBytesNeeded) != 0) { + return encoder->data.bytes_needed; + } + return 0; +} + +static CborError +rep_crc_append_to_buffer(CborEncoder *encoder, CborType data_type, + const void *data, size_t len) +{ + size_t size = 0; + if (encoder->data.ptr != NULL) { + size = encoder->end - encoder->data.ptr; + } + + uint64_t crc = 0; + if (size < sizeof(crc)) { + encoder->flags |= CrcFlagBytesNeeded; + encoder->data.bytes_needed = (ptrdiff_t)(sizeof(crc) - size); + return CborErrorOutOfMemory; + } + + encoder->flags &= ~CrcFlagBytesNeeded; + if ((encoder->flags & CrcFlagHasPayload) != 0) { + memcpy(&crc, encoder->data.ptr, sizeof(crc)); + } + + uint8_t type[] = { (uint8_t)data_type }; + crc = oc_crc64(crc, type, OC_ARRAY_SIZE(type)); + if (len > 0) { + crc = oc_crc64(crc, data, len); + } + memcpy(encoder->data.ptr, &crc, sizeof(crc)); + encoder->flags |= CrcFlagHasPayload; + return CborNoError; +} + +static CborError +rep_crc_encode_null(CborEncoder *encoder) +{ + return rep_crc_append_to_buffer(encoder, CborNullType, NULL, 0); +} + +static CborError +rep_crc_encode_bool(CborEncoder *encoder, bool value) +{ + uint8_t crc_bool = { value ? OC_CRC_REP_TRUE : OC_CRC_REP_FALSE }; + return rep_crc_append_to_buffer(encoder, CborBooleanType, &crc_bool, 1); +} + +static CborError +rep_crc_encode_int(CborEncoder *encoder, int64_t value) +{ + return rep_crc_append_to_buffer(encoder, CborIntegerType, &value, + sizeof(value)); +} + +static CborError +rep_crc_encode_floating_point(CborEncoder *encoder, CborType fpType, + const void *value) +{ + uint8_t size = 0; + if (fpType == CborDoubleType) { + size = sizeof(double); + } else if (fpType == CborFloatType) { + size = sizeof(float); + } else if (fpType == CborHalfFloatType) { + size = sizeof(uint16_t); + } + if (size == 0) { + return CborErrorIllegalType; + } + return rep_crc_append_to_buffer(encoder, fpType, value, size); +} + +static CborError +rep_crc_encode_double(CborEncoder *encoder, double value) +{ + return rep_crc_append_to_buffer(encoder, CborDoubleType, &value, + sizeof(value)); +} + +static CborError +rep_crc_encode_uint(CborEncoder *encoder, uint64_t value) +{ + return rep_crc_append_to_buffer(encoder, CborIntegerType, &value, + sizeof(value)); +} + +static CborError +rep_crc_encode_byte_string(CborEncoder *encoder, const uint8_t *string, + size_t length) +{ + return rep_crc_append_to_buffer(encoder, CborByteStringType, string, length); +} + +static CborError +rep_crc_encode_text_string(CborEncoder *encoder, const char *string, + size_t length) +{ + return rep_crc_append_to_buffer(encoder, CborTextStringType, string, length); +} + +static CborError +rep_crc_encoder_create_container(CborEncoder *encoder, CborEncoder *container, + size_t length, bool isMap) +{ + (void)length; + uint8_t open_byte = OC_CRC_OPEN_CONTAINER; + int err = rep_crc_append_to_buffer( + encoder, isMap ? CborMapType : CborArrayType, &open_byte, 1); + if (err == CborNoError) { + memcpy(container, encoder, sizeof(CborEncoder)); + container->flags = + isMap ? encoder->flags | CrcFlagIsMap : encoder->flags & ~CrcFlagIsMap; + } else if (err == CborErrorOutOfMemory) { + memcpy(container, encoder, sizeof(CborEncoder)); + } + return err; +} + +static CborError +rep_crc_encoder_create_array(CborEncoder *encoder, CborEncoder *container, + size_t length) +{ + return rep_crc_encoder_create_container(encoder, container, length, false); +} + +static CborError +rep_crc_encoder_create_map(CborEncoder *encoder, CborEncoder *container, + size_t length) +{ + return rep_crc_encoder_create_container(encoder, container, length, true); +} + +static CborError +rep_crc_encoder_close_container(CborEncoder *encoder, + const CborEncoder *container) +{ + // synchronise buffer state with that of the container + encoder->end = container->end; + encoder->data = container->data; + CborType type = + (container->flags & CrcFlagIsMap) != 0 ? CborMapType : CborArrayType; + uint8_t close_byte = OC_CRC_CLOSE_CONTAINER; + return rep_crc_append_to_buffer(encoder, type, &close_byte, 1); +} + +oc_rep_encoder_implementation_t +oc_rep_crc_encoder(void) +{ + return (oc_rep_encoder_implementation_t){ + .get_buffer_size = &rep_crc_get_buffer_size, + .get_extra_bytes_needed = &rep_crc_get_extra_bytes_needed, + + .encode_null = &rep_crc_encode_null, + .encode_boolean = &rep_crc_encode_bool, + .encode_int = &rep_crc_encode_int, + .encode_uint = &rep_crc_encode_uint, + .encode_floating_point = &rep_crc_encode_floating_point, + .encode_double = &rep_crc_encode_double, + .encode_byte_string = &rep_crc_encode_byte_string, + .encode_text_string = &rep_crc_encode_text_string, + .create_array = &rep_crc_encoder_create_array, + .create_map = &rep_crc_encoder_create_map, + .close_container = &rep_crc_encoder_close_container, + }; +} + +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ diff --git a/api/oc_rep_encode_crc_internal.h b/api/oc_rep_encode_crc_internal.h new file mode 100644 index 0000000000..443c2aca43 --- /dev/null +++ b/api/oc_rep_encode_crc_internal.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#ifndef OC_REP_ENCODE_CRC_INTERNAL_H +#define OC_REP_ENCODE_CRC_INTERNAL_H + +#include "util/oc_features.h" + +#ifdef OC_HAS_FEATURE_CRC_ENCODER + +#ifdef __cplusplus +extern "C" { +#endif + +#include "api/oc_rep_encode_internal.h" + +#define OC_CRC_REP_FALSE (0x0) +#define OC_CRC_REP_TRUE (0x1) + +#define OC_CRC_OPEN_CONTAINER (0x0) +#define OC_CRC_CLOSE_CONTAINER (0x1) + +/** Return an initialized CRC encoder. */ +oc_rep_encoder_implementation_t oc_rep_crc_encoder(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ + +#endif /* OC_REP_ENCODE_CRC_INTERNAL_H */ diff --git a/api/oc_rep_encode_internal.h b/api/oc_rep_encode_internal.h index 8e1b5a4968..22ad52ebcf 100644 --- a/api/oc_rep_encode_internal.h +++ b/api/oc_rep_encode_internal.h @@ -32,7 +32,25 @@ extern "C" { #endif -/** Encoding interface */ +typedef struct +{ + uint8_t *ptr; + size_t size; + +#ifdef OC_DYNAMIC_ALLOCATION + size_t max_size; + uint8_t **pptr; + bool enable_realloc; +#endif /* OC_DYNAMIC_ALLOCATION */ +} oc_rep_encoder_buffer_t; + +/** Rep encoder interface */ +typedef size_t (*oc_get_buffer_size_t)(const CborEncoder *encoder, + const uint8_t *buffer) OC_NONNULL(); + +typedef size_t (*oc_get_extra_bytes_needed_t)(const CborEncoder *encoder) + OC_NONNULL(); + typedef CborError (*oc_rep_encode_null_t)(CborEncoder *encoder) OC_NONNULL(); typedef CborError (*oc_rep_encode_boolean_t)(CborEncoder *encoder, bool value) @@ -70,9 +88,10 @@ typedef CborError (*oc_rep_encoder_create_map_t)(CborEncoder *encoder, typedef CborError (*oc_rep_encoder_close_container_t)( CborEncoder *encoder, const CborEncoder *containerEncoder) OC_NONNULL(); -typedef struct oc_rep_encoder_t +typedef struct oc_rep_encoder_implementation_t { - oc_rep_encoder_type_t type; + oc_get_buffer_size_t get_buffer_size; + oc_get_extra_bytes_needed_t get_extra_bytes_needed; oc_rep_encode_null_t encode_null; oc_rep_encode_boolean_t encode_boolean; @@ -85,10 +104,33 @@ typedef struct oc_rep_encoder_t oc_rep_encoder_create_array_t create_array; oc_rep_encoder_create_map_t create_map; oc_rep_encoder_close_container_t close_container; +} oc_rep_encoder_implementation_t; + +typedef struct oc_rep_encoder_t +{ + oc_rep_encoder_type_t type; + oc_rep_encoder_implementation_t impl; + oc_rep_encoder_buffer_t buffer; + CborEncoder ctx; } oc_rep_encoder_t; -/** Return an initialized CBOR encoder. */ -oc_rep_encoder_t oc_rep_cbor_encoder(void); +/** Return pointer to the global encoder */ +oc_rep_encoder_t *oc_rep_global_encoder(void) OC_RETURNS_NONNULL; + +typedef struct oc_rep_encoder_reset_t +{ + oc_rep_encoder_t encoder; + CborEncoder root_map_ctx; + CborEncoder links_array_ctx; +} oc_rep_encoder_reset_t; + +/** Set global encoder and return the previous */ +oc_rep_encoder_reset_t oc_rep_global_encoder_reset( + const oc_rep_encoder_reset_t *reset); + +/** Get encoder. */ +oc_rep_encoder_t oc_rep_encoder(oc_rep_encoder_type_t type, + oc_rep_encoder_buffer_t buffer); /** * @brief Initialize global encoder buffer. @@ -96,13 +138,17 @@ oc_rep_encoder_t oc_rep_cbor_encoder(void); * @note the pointer to the buffer directly isn't stored directly, instead * an offset is stored to allow reallocation. * - * @param buffer buffer used by the global encoder (cannot be NULL) + * @param encoder encoder (cannot be NULL) + * @param buffer buffer used by the global encoder * @param size size of the buffer */ -void oc_rep_buffer_init(uint8_t *buffer, size_t size); +void oc_rep_encoder_buffer_init(oc_rep_encoder_t *encoder, uint8_t *buffer, + size_t size) OC_NONNULL(1); + +#ifdef OC_DYNAMIC_ALLOCATION /** - * @brief Initialize global encoder buffer and enable buffer reallocation. + * @brief Initialize encoder buffer and enable buffer reallocation. * * If the buffer is too small then the buffer will be enlarged using the realloc * syscall. The size of the buffer cannot exceed the maximal allowed size. @@ -110,23 +156,38 @@ void oc_rep_buffer_init(uint8_t *buffer, size_t size); * @note the pointer to the buffer directly isn't stored directly, instead * an offset is stored to allow reallocation. * - * @param buffer pointer buffer used by the global encoder (cannot be NULL) + * @param encoder encoder (cannot be NULL) + * @param buffer pointer buffer used by the global encoder * @param size size of the buffer * @param max_size maximal allowed size of the buffer */ -void oc_rep_buffer_realloc_init(uint8_t **buffer, size_t size, size_t max_size); +void oc_rep_encoder_buffer_realloc_init(oc_rep_encoder_t *encoder, + uint8_t **buffer, size_t size, + size_t max_size) OC_NONNULL(1); + +#endif /* OC_DYNAMIC_ALLOCATION */ + +/** @brief Get the size of the encoded data. */ +int oc_rep_encoder_payload_size(oc_rep_encoder_t *encoder) OC_NONNULL(); + +#ifdef OC_DYNAMIC_ALLOCATION +/** @brief Shrink encoder buffer to the payload size */ +bool oc_rep_encoder_shrink_buffer(oc_rep_encoder_t *encoder) OC_NONNULL(); +#endif /* OC_DYNAMIC_ALLOCATION */ /** * @brief Recalcute the pointer to the buffer and the pointer to the end of the * buffer to be offsets from the global buffer. */ -CborEncoder *oc_rep_encoder_convert_ptr_to_offset(CborEncoder *encoder); +void oc_rep_encoder_convert_ptr_to_offset(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder) OC_NONNULL(); /** * @brief Recalcute from relative offsets to pointer to buffer usable by cbor * library. */ -CborEncoder *oc_rep_encoder_convert_offset_to_ptr(CborEncoder *encoder); +void oc_rep_encoder_convert_offset_to_ptr(const oc_rep_encoder_t *encoder, + CborEncoder *subEncoder) OC_NONNULL(); /** * @brief Set the encoder type to encode the response payload according to the @@ -137,8 +198,73 @@ CborEncoder *oc_rep_encoder_convert_offset_to_ptr(CborEncoder *encoder); */ bool oc_rep_encoder_set_type_by_accept(oc_content_format_t accept); -/** Get content format of the global encoder */ -oc_content_format_t oc_rep_encoder_get_content_format(void); +/** @brief Get content format of the global encoder */ +bool oc_rep_encoder_get_content_format(oc_content_format_t *format) + OC_NONNULL(); + +/** @brief Write raw data to encoder */ +int oc_rep_encoder_write_raw(oc_rep_encoder_t *encoder, const uint8_t *data, + size_t len) OC_NONNULL(1); + +/** @brief Write null representation to encoder */ +CborError oc_rep_encoder_write_null(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder) OC_NONNULL(); + +/** @brief Write boolean representation to encoder */ +CborError oc_rep_encoder_write_boolean(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, bool value) + OC_NONNULL(); + +/** @brief Write integer representation to encoder */ +CborError oc_rep_encoder_write_int(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, int64_t value) + OC_NONNULL(); + +/** @brief Write unsigned integer representation to encoder */ +CborError oc_rep_encoder_write_uint(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, uint64_t value) + OC_NONNULL(); + +/** @brief Write double representation to encoder */ +CborError oc_rep_encoder_write_floating_point(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborType fpType, + const void *value) OC_NONNULL(); + +/** @brief Write double representation to encoder */ +CborError oc_rep_encoder_write_double(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, double value) + OC_NONNULL(); + +/** @brief Write byte string representation to encoder */ +CborError oc_rep_encoder_write_text_string(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + const char *string, size_t length) + OC_NONNULL(1, 2); + +/** @brief Write byte string representation to encoder */ +CborError oc_rep_encoder_write_byte_string(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + const uint8_t *string, size_t length) + OC_NONNULL(1, 2); + +/** @brief Write representation of opening an array to encoder */ +CborError oc_rep_encoder_write_array_open(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *arrayEncoder, + size_t length) OC_NONNULL(); + +/** @brief Write representation of opening a map to encoder */ +CborError oc_rep_encoder_write_map_open(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *mapEncoder, size_t length) + OC_NONNULL(); + +/** @brief Write representation of closing a container to encoder */ +CborError oc_rep_encoder_write_container_close(oc_rep_encoder_t *encoder, + CborEncoder *subEncoder, + CborEncoder *containerEncoder) + OC_NONNULL(); #ifdef __cplusplus } diff --git a/api/oc_rep_encode_json.c b/api/oc_rep_encode_json.c index 7078399452..56964afe5e 100644 --- a/api/oc_rep_encode_json.c +++ b/api/oc_rep_encode_json.c @@ -34,6 +34,18 @@ typedef enum json_types_t { MapType = 1 << 3, } json_types_t; +static size_t +rep_json_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer) +{ + return (size_t)(encoder->data.ptr - buffer); +} + +static size_t +rep_json_get_extra_bytes_needed(const CborEncoder *encoder) +{ + return encoder->end != NULL ? 0 : (size_t)encoder->data.bytes_needed; +} + static bool rep_json_would_overflow(CborEncoder *encoder, size_t len) { @@ -44,16 +56,6 @@ rep_json_would_overflow(CborEncoder *encoder, size_t len) return remaining < 0; } -static void -rep_json_advance_ptr(CborEncoder *encoder, size_t n) -{ - if (encoder->end != NULL) { - encoder->data.ptr += n; - } else { - encoder->data.bytes_needed += (ptrdiff_t)n; - } -} - static CborError rep_json_append_to_buffer(CborEncoder *encoder, const void *data, size_t len) { @@ -64,7 +66,7 @@ rep_json_append_to_buffer(CborEncoder *encoder, const void *data, size_t len) encoder->data.bytes_needed = 0; } - rep_json_advance_ptr(encoder, len); + encoder->data.bytes_needed += (ptrdiff_t)len; return CborErrorOutOfMemory; } @@ -316,11 +318,12 @@ rep_json_encoder_close_container(CborEncoder *encoder, return rep_json_append_to_buffer(encoder, break_byte, 1); } -oc_rep_encoder_t +oc_rep_encoder_implementation_t oc_rep_json_encoder(void) { - return (oc_rep_encoder_t){ - .type = OC_REP_JSON_ENCODER, + return (oc_rep_encoder_implementation_t){ + .get_buffer_size = &rep_json_get_buffer_size, + .get_extra_bytes_needed = &rep_json_get_extra_bytes_needed, .encode_null = &rep_json_encode_null, .encode_boolean = &rep_json_encode_boolean, diff --git a/api/oc_rep_encode_json_internal.h b/api/oc_rep_encode_json_internal.h index 0efe74066f..6c433d48f2 100644 --- a/api/oc_rep_encode_json_internal.h +++ b/api/oc_rep_encode_json_internal.h @@ -33,8 +33,8 @@ extern "C" { #define OC_REP_JSON_INT_MIN ~(1LL << 52) #define OC_REP_JSON_UINT_MAX (1ULL << 53) -/** Return an initialized JSON encoder. */ -oc_rep_encoder_t oc_rep_json_encoder(void); +/** Return JSON encoder implementation. */ +oc_rep_encoder_implementation_t oc_rep_json_encoder(void); #ifdef __cplusplus } diff --git a/api/oc_ri.c b/api/oc_ri.c index 230da0274a..97a26a5c06 100644 --- a/api/oc_ri.c +++ b/api/oc_ri.c @@ -1333,7 +1333,7 @@ oc_ri_invoke_coap_entity_handler(coap_make_response_ctx_t *ctx, bool bad_request = false; bool entity_too_large = false; - if (payload_len > 0 && oc_rep_decoder_set_type_by_content_format(cf)) { + if (payload_len > 0 && oc_rep_decoder_set_by_content_format(cf)) { /* Attempt to parse request payload using tinyCBOR via oc_rep helper * functions. The result of this parse is a tree of oc_rep_t structures * which will reflect the schema of the payload. diff --git a/api/oc_runtime.c b/api/oc_runtime.c index 2bac5363d7..4ff59267ef 100644 --- a/api/oc_runtime.c +++ b/api/oc_runtime.c @@ -16,6 +16,7 @@ * ****************************************************************************/ +#include "api/oc_rep_internal.h" #include "oc_runtime_internal.h" #include "port/oc_random.h" #include "port/oc_clock.h" diff --git a/api/unittest/encoder/TestEncoderBuffer.cpp b/api/unittest/encoder/TestEncoderBuffer.cpp new file mode 100644 index 0000000000..83a3e5e8a5 --- /dev/null +++ b/api/unittest/encoder/TestEncoderBuffer.cpp @@ -0,0 +1,133 @@ +/****************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#include "TestEncoderBuffer.h" + +#include "oc_rep.h" +#include "port/oc_log_internal.h" + +#include + +oc_rep_encoder_type_t TestEncoderBuffer::default_encoder = + oc_rep_encoder_get_type(); +oc_rep_decoder_type_t TestEncoderBuffer::default_decoder = + oc_rep_decoder_get_type(); + +TestEncoderBuffer::TestEncoderBuffer(oc_rep_encoder_type_t encoder_type) + : encoder_type_(encoder_type) +{ + oc_rep_encoder_set_type(encoder_type); + + if (encoder_type_ == OC_REP_CBOR_ENCODER) { + oc_rep_decoder_set_type(OC_REP_CBOR_DECODER); + } +#ifdef OC_JSON_ENCODER + else if (encoder_type_ == OC_REP_JSON_ENCODER) { + oc_rep_decoder_set_type(OC_REP_JSON_DECODER); + } +#endif /* OC_JSON_ENCODER */ +} + +TestEncoderBuffer::~TestEncoderBuffer() +{ +#ifdef OC_DYNAMIC_ALLOCATION + free(buffer_); +#endif /* OC_DYNAMIC_ALLOCATION */ +} + +std::optional +TestEncoderBuffer::GetDecoderType() const +{ + if (encoder_type_ == OC_REP_CBOR_ENCODER) { + return OC_REP_CBOR_DECODER; + } + +#ifdef OC_JSON_ENCODER + if (encoder_type_ == OC_REP_JSON_ENCODER) { + return OC_REP_JSON_DECODER; + } +#endif /* OC_JSON_ENCODER */ + + return {}; +} + +bool +TestEncoderBuffer::HasDecoder() const +{ + return GetDecoderType().has_value(); +} + +void +TestEncoderBuffer::RestoreDefaults() +{ + oc_rep_encoder_set_type(default_encoder); + oc_rep_decoder_set_type(default_decoder); +} + +void +TestEncoderBuffer::StoreDefaults() +{ + TestEncoderBuffer::default_encoder = oc_rep_encoder_get_type(); + TestEncoderBuffer::default_decoder = oc_rep_decoder_get_type(); +} + +void +TestEncoderBuffer::SetRepBuffer(size_t size, size_t max_size) +{ +#ifdef OC_DYNAMIC_ALLOCATION + free(buffer_); + buffer_ = nullptr; + if (size > 0) { + buffer_ = static_cast(malloc(size)); + memset(buffer_, 0, size); + } + oc_rep_new_realloc_v1(&buffer_, size, max_size); +#else /* OC_DYNAMIC_ALLOCATION */ + (void)size; + buffer_.resize(max_size); + oc_rep_new_v1(buffer_.data(), buffer_.size()); + memset(&rep_objects_alloc_[0], 0, OC_MAX_NUM_REP_OBJECTS * sizeof(char)); + memset(&rep_objects_pool_[0], 0, OC_MAX_NUM_REP_OBJECTS * sizeof(oc_rep_t)); +#endif /* OC_DYNAMIC_ALLOCATION */ +} + +void +TestEncoderBuffer::Shrink() +{ +#ifdef OC_DYNAMIC_ALLOCATION + buffer_ = oc_rep_shrink_encoder_buf(buffer_); +#endif /* OC_DYNAMIC_ALLOCATION */ +} + +oc::oc_rep_unique_ptr +TestEncoderBuffer::ParsePayload() +{ + auto dt = GetDecoderType(); + if (!dt.has_value()) { + return oc::oc_rep_unique_ptr(nullptr, &oc_free_rep); + } + + const uint8_t *payload = oc_rep_get_encoder_buf(); + int payload_len = oc_rep_get_encoded_payload_size(); + EXPECT_NE(payload_len, -1); + oc_rep_set_pool(&rep_objects_); + oc_rep_t *rep = nullptr; + oc_rep_decoder_t decoder = oc_rep_decoder(*dt); + EXPECT_EQ(CborNoError, decoder.parse(payload, payload_len, &rep)); + return oc::oc_rep_unique_ptr(rep, &oc_free_rep); +} diff --git a/api/unittest/encoder/TestEncoderBuffer.h b/api/unittest/encoder/TestEncoderBuffer.h new file mode 100644 index 0000000000..e7126c6bab --- /dev/null +++ b/api/unittest/encoder/TestEncoderBuffer.h @@ -0,0 +1,72 @@ +/****************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#pragma once + +#include "api/oc_rep_decode_internal.h" +#include "api/oc_rep_encode_internal.h" +#include "oc_config.h" +#include "oc_rep.h" +#include "tests/gtest/RepPool.h" + +#include +#include +#include +#include + +class TestEncoderBuffer { +public: + explicit TestEncoderBuffer(oc_rep_encoder_type_t encoder_type); + ~TestEncoderBuffer(); + + TestEncoderBuffer(TestEncoderBuffer &other) = delete; + TestEncoderBuffer &operator=(TestEncoderBuffer &other) = delete; + TestEncoderBuffer(TestEncoderBuffer &&other) = delete; + TestEncoderBuffer &operator=(TestEncoderBuffer &&other) = delete; + + static void RestoreDefaults(); + static void StoreDefaults(); + + std::optional GetDecoderType() const; + bool HasDecoder() const; + + /* buffer for oc_rep_t */ + void SetRepBuffer(size_t size = 1024, size_t max_size = 1024); + + void Shrink(); + + oc::oc_rep_unique_ptr ParsePayload(); + +private: + static oc_rep_encoder_type_t default_encoder; + static oc_rep_decoder_type_t default_decoder; + + oc_rep_encoder_type_t encoder_type_; + +#ifdef OC_DYNAMIC_ALLOCATION + uint8_t *buffer_{ nullptr }; + oc_memb rep_objects_{ sizeof(oc_rep_t), 0, nullptr, nullptr, nullptr }; +#else /* !OC_DYNAMIC_ALLOCATION */ + std::vector buffer_{}; + std::array rep_objects_alloc_{}; + std::array rep_objects_pool_{}; + oc_memb rep_objects_{ sizeof(oc_rep_t), OC_MAX_NUM_REP_OBJECTS, + rep_objects_alloc_.data(), rep_objects_pool_.data(), + nullptr }; +#endif /* OC_DYNAMIC_ALLOCATION */ +}; diff --git a/api/unittest/repdecodetest.cpp b/api/unittest/repdecodetest.cpp index 24c3ea8792..ee93a025e2 100644 --- a/api/unittest/repdecodetest.cpp +++ b/api/unittest/repdecodetest.cpp @@ -35,7 +35,7 @@ TEST_F(TestRepDecode, SetTypeByContentFormat) for (int i = 0; i < APPLICATION_NOT_DEFINED; ++i) { auto cf = static_cast(i); if (is_accepted_format(cf)) { - EXPECT_TRUE(oc_rep_decoder_set_type_by_content_format(cf)); + EXPECT_TRUE(oc_rep_decoder_set_by_content_format(cf)); oc_rep_decoder_type_t exp_type = OC_REP_CBOR_DECODER; #ifdef OC_JSON_ENCODER if (cf == APPLICATION_JSON || cf == APPLICATION_TD_JSON) { @@ -45,12 +45,11 @@ TEST_F(TestRepDecode, SetTypeByContentFormat) EXPECT_EQ(exp_type, oc_rep_decoder_get_type()); continue; } - EXPECT_FALSE(oc_rep_decoder_set_type_by_content_format(cf)) + EXPECT_FALSE(oc_rep_decoder_set_by_content_format(cf)) << "unexpected valid decoder for cf: " << cf; } - EXPECT_TRUE( - oc_rep_decoder_set_type_by_content_format(APPLICATION_NOT_DEFINED)); + EXPECT_TRUE(oc_rep_decoder_set_by_content_format(APPLICATION_NOT_DEFINED)); EXPECT_EQ(OC_REP_CBOR_DECODER, oc_rep_decoder_get_type()); } diff --git a/api/unittest/repencodecbortest.cpp b/api/unittest/repencodecbortest.cpp new file mode 100644 index 0000000000..2f26090410 --- /dev/null +++ b/api/unittest/repencodecbortest.cpp @@ -0,0 +1,330 @@ +/****************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#include "encoder/TestEncoderBuffer.h" + +#include "api/oc_rep_encode_internal.h" +#include "api/oc_rep_decode_internal.h" +#include "oc_rep.h" +#include "port/oc_log_internal.h" +#include "tests/gtest/RepPool.h" + +#include +#include +#include +#include +#include +#include + +class TestCborRepEncodeWithRealloc : public testing::Test { +public: + static void SetUpTestCase() + { + TestEncoderBuffer::StoreDefaults(); + TestCborRepEncodeWithRealloc::encoder = + std::make_unique(OC_REP_CBOR_ENCODER); + ASSERT_EQ(OC_REP_CBOR_ENCODER, oc_rep_encoder_get_type()); + } + + static void TearDownTestCase() + { + TestCborRepEncodeWithRealloc::encoder.reset(); + TestEncoderBuffer::RestoreDefaults(); + } + + static void SetRepBuffer(size_t size = 1024, size_t max_size = 1024) + { + TestCborRepEncodeWithRealloc::encoder->SetRepBuffer(size, max_size); + } + + static oc::oc_rep_unique_ptr ParsePayload() + { + return TestCborRepEncodeWithRealloc::encoder->ParsePayload(); + } + + static void Shrink() { TestCborRepEncodeWithRealloc::encoder->Shrink(); } + + static std::unique_ptr encoder; +}; + +std::unique_ptr TestCborRepEncodeWithRealloc::encoder{ + nullptr +}; + +TEST_F(TestCborRepEncodeWithRealloc, EncodeRaw) +{ + std::vector in{ '\0' }; + SetRepBuffer(0, 0); + oc_rep_encode_raw(in.data(), in.size()); + EXPECT_EQ(CborErrorInternalError, oc_rep_get_cbor_errno()); + + SetRepBuffer(1, 1); + oc_rep_encode_raw(in.data(), in.size()); + EXPECT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_encode_raw(in.data(), in.size()); + EXPECT_EQ(CborErrorOutOfMemory, oc_rep_get_cbor_errno()); + + SetRepBuffer(1, 8); + for (size_t i = 0; i < 8; ++i) { + oc_rep_encode_raw(in.data(), in.size()); + EXPECT_EQ(CborNoError, oc_rep_get_cbor_errno()); + } + EXPECT_EQ(8, oc_rep_get_encoded_payload_size()); + + oc_rep_encode_raw(in.data(), in.size()); + EXPECT_EQ(CborErrorOutOfMemory, oc_rep_get_cbor_errno()); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeNull) +{ + SetRepBuffer(1, 1); + ASSERT_EQ(CborNoError, oc_rep_encode_null(oc_rep_get_encoder())); + EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_null(oc_rep_get_encoder())); + + SetRepBuffer(1, 8); + for (size_t i = 0; i < 8; ++i) { + ASSERT_EQ(CborNoError, oc_rep_encode_null(oc_rep_get_encoder())); + } + EXPECT_EQ(8, oc_rep_get_encoded_payload_size()); + EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_null(oc_rep_get_encoder())); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeBool) +{ + SetRepBuffer(1, 1); + ASSERT_EQ(CborNoError, oc_rep_encode_boolean(oc_rep_get_encoder(), false)); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_boolean(oc_rep_get_encoder(), true)); + + // 4 * true + 4 * false + SetRepBuffer(1, 8); + for (size_t i = 0; i < 8; ++i) { + ASSERT_EQ(CborNoError, + oc_rep_encode_boolean(oc_rep_get_encoder(), i % 2 == 0)); + } + ASSERT_EQ(8, oc_rep_get_encoded_payload_size()); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_boolean(oc_rep_get_encoder(), false)); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeInt) +{ + SetRepBuffer(1, 1); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_int(oc_rep_get_encoder(), INT64_MAX)); + + SetRepBuffer(1, 9); + ASSERT_EQ(CborNoError, oc_rep_encode_int(oc_rep_get_encoder(), INT64_MAX)); + ASSERT_EQ(9, oc_rep_get_encoded_payload_size()); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_int(oc_rep_get_encoder(), INT64_MAX)); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeUint) +{ + SetRepBuffer(1, 1); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_uint(oc_rep_get_encoder(), UINT64_MAX)); + + SetRepBuffer(1, 9); + ASSERT_EQ(CborNoError, oc_rep_encode_uint(oc_rep_get_encoder(), UINT64_MAX)); + ASSERT_EQ(9, oc_rep_get_encoded_payload_size()); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_uint(oc_rep_get_encoder(), UINT64_MAX)); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeFloat) +{ + float val = 0; + SetRepBuffer(1, 1); + EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_floating_point( + oc_rep_get_encoder(), CborFloatType, &val)); + + SetRepBuffer(1, 5); + val = std::numeric_limits::max(); + ASSERT_EQ(CborNoError, oc_rep_encode_floating_point(oc_rep_get_encoder(), + CborFloatType, &val)); + ASSERT_EQ(5, oc_rep_get_encoded_payload_size()); + EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_floating_point( + oc_rep_get_encoder(), CborFloatType, &val)); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeDouble) +{ + SetRepBuffer(1, 1); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_double(oc_rep_get_encoder(), + std::numeric_limits::max())); + + SetRepBuffer(1, 9); + ASSERT_EQ(CborNoError, + oc_rep_encode_double(oc_rep_get_encoder(), + std::numeric_limits::max())); + ASSERT_EQ(9, oc_rep_get_encoded_payload_size()); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_double(oc_rep_get_encoder(), + std::numeric_limits::max())); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeTextString) +{ + SetRepBuffer(1, 1); + std::string str = "test"; + EXPECT_EQ( + CborErrorOutOfMemory, + oc_rep_encode_text_string(oc_rep_get_encoder(), str.c_str(), str.length())); + + SetRepBuffer(1, 17); + str = "this is 16 chars"; + ASSERT_EQ(CborNoError, oc_rep_encode_text_string(oc_rep_get_encoder(), + str.c_str(), str.length())); + ASSERT_EQ(17, oc_rep_get_encoded_payload_size()); + + str = "c"; + EXPECT_EQ( + CborErrorOutOfMemory, + oc_rep_encode_text_string(oc_rep_get_encoder(), str.c_str(), str.length())); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeByteString) +{ + SetRepBuffer(1, 1); + std::vector bstr = { 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, + 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, 0x0 }; + EXPECT_EQ( + CborErrorOutOfMemory, + oc_rep_encode_byte_string(oc_rep_get_encoder(), bstr.data(), bstr.size())); + + SetRepBuffer(1, 20); + EXPECT_EQ(CborNoError, oc_rep_encode_byte_string(oc_rep_get_encoder(), + bstr.data(), bstr.size())); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeArray) +{ + SetRepBuffer(1, 1); + CborEncoder array{}; + CborEncoder inner_array{}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( + oc_rep_get_encoder(), &array, CborIndefiniteLength)); + EXPECT_EQ( + CborErrorOutOfMemory, + oc_rep_encoder_create_array(&array, &inner_array, CborIndefiniteLength)); + + SetRepBuffer(1, 1); + array = {}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( + oc_rep_get_encoder(), &array, CborIndefiniteLength)); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encoder_close_container(oc_rep_get_encoder(), &array)); + + SetRepBuffer(1, 3); + array = {}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( + oc_rep_get_encoder(), &array, CborIndefiniteLength)); + ASSERT_EQ(CborNoError, oc_rep_encode_boolean(&array, true)); + ASSERT_EQ(CborNoError, + oc_rep_encoder_close_container(oc_rep_get_encoder(), &array)); + ASSERT_EQ(3, oc_rep_get_encoded_payload_size()); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodeMap) +{ + SetRepBuffer(1, 1); + CborEncoder map{}; + CborEncoder inner_map{}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, + CborIndefiniteLength)); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encoder_create_map(&map, &inner_map, CborIndefiniteLength)); + + SetRepBuffer(1, 1); + map = {}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, + CborIndefiniteLength)); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encoder_close_container(oc_rep_get_encoder(), &map)); + + std::string key = "key"; + SetRepBuffer(1, 7); + map = {}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, + CborIndefiniteLength)); + ASSERT_EQ(CborNoError, + oc_rep_encode_text_string(&map, key.c_str(), key.length())); + ASSERT_EQ(CborNoError, oc_rep_encode_boolean(&map, true)); + ASSERT_EQ(CborNoError, + oc_rep_encoder_close_container(oc_rep_get_encoder(), &map)); + ASSERT_EQ(7, oc_rep_get_encoded_payload_size()); + + auto rep = ParsePayload(); + ASSERT_NE(nullptr, rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(rep.get(), true).data()); +} + +TEST_F(TestCborRepEncodeWithRealloc, EncodedPayloadRealloc) +{ + SetRepBuffer(1, 1024); + + oc_rep_start_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_text_string(root, hello, "world"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_double(root, double, 3.14); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_boolean(root, bool, true); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_int(root, int, -1); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_uint(root, uint, -1); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + std::vector byte_string = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + oc_rep_set_byte_string(root, byte_string_key, byte_string.data(), + byte_string.size()); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + std::vector fib = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 }; + oc_rep_set_key(oc_rep_object(root), "fibonacci"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_begin_array(oc_rep_object(root), fibonacci); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + for (const auto &val : fib) { + oc_rep_add_int(fibonacci, val); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + } + oc_rep_end_array(oc_rep_object(root), fibonacci); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + std::vector math_constants = { 3.14159, 2.71828, 1.414121, 1.61803 }; + oc_rep_set_double_array(root, math_constants, math_constants.data(), + math_constants.size()); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + + auto rep = ParsePayload(); + ASSERT_NE(nullptr, rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(rep.get(), true).data()); + size_t payload_size = oc_rep_get_encoded_payload_size(); + EXPECT_EQ(156, payload_size); +#ifdef OC_DYNAMIC_ALLOCATION + EXPECT_GT(oc_rep_get_encoder_buffer_size(), payload_size); +#endif /* OC_DYNAMIC_ALLOCATION */ + Shrink(); +#ifdef OC_DYNAMIC_ALLOCATION + EXPECT_EQ(oc_rep_get_encoder_buffer_size(), payload_size); +#endif /* OC_DYNAMIC_ALLOCATION */ +} diff --git a/api/unittest/repencodecrctest.cpp b/api/unittest/repencodecrctest.cpp new file mode 100644 index 0000000000..e96ceade28 --- /dev/null +++ b/api/unittest/repencodecrctest.cpp @@ -0,0 +1,439 @@ +/****************************************************************** + * + * Copyright (c) 2023 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#include "util/oc_features.h" + +#ifdef OC_HAS_FEATURE_CRC_ENCODER + +#include "encoder/TestEncoderBuffer.h" + +#include "api/oc_rep_encode_crc_internal.h" +#include "oc_rep.h" +#include "tests/gtest/Utility.h" +#include "util/oc_crc_internal.h" + +#include +#include +#include +#include +#include +#include + +class TestCrcRepEncodeWithRealloc : public testing::Test { +public: + static void SetUpTestCase() + { + TestEncoderBuffer::StoreDefaults(); + TestCrcRepEncodeWithRealloc::encoder = + std::make_unique(OC_REP_CRC_ENCODER); + ASSERT_EQ(OC_REP_CRC_ENCODER, oc_rep_encoder_get_type()); + } + + static void TearDownTestCase() + { + TestCrcRepEncodeWithRealloc::encoder.reset(); + TestEncoderBuffer::RestoreDefaults(); + } + + static void SetRepBuffer(size_t size = 1024, size_t max_size = 1024) + { + TestCrcRepEncodeWithRealloc::encoder->SetRepBuffer(size, max_size); + } + + static void Shrink() { TestCrcRepEncodeWithRealloc::encoder->Shrink(); } + + static std::optional geyPayloadCRC() + { + const uint8_t *payload = oc_rep_get_encoder_buf(); + int payload_len = oc_rep_get_encoded_payload_size(); + uint64_t crc; + if (payload_len != sizeof(crc)) { + return {}; + } + memcpy(&crc, payload, sizeof(crc)); + return crc; + } + + static std::unique_ptr encoder; +}; + +std::unique_ptr TestCrcRepEncodeWithRealloc::encoder{ + nullptr +}; + +static uint64_t +calculateCrc(uint64_t crc, CborType type, const uint8_t *buffer, size_t size) +{ + if (CborInvalidType != type) { + auto dt = static_cast(type); + crc = oc_crc64(crc, &dt, 1); + } + return oc_crc64(crc, buffer, size); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeNull) +{ + SetRepBuffer(1, 0); + EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_null(oc_rep_get_encoder())); + + SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, oc_rep_encode_null(oc_rep_get_encoder())); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + uint64_t expCrc = calculateCrc(0, CborNullType, nullptr, 0); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeBool) +{ + SetRepBuffer(1, 1); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_boolean(oc_rep_get_encoder(), true)); + + SetRepBuffer(1, 8); + std::vector crcData{}; + uint64_t expCrc = 0; + for (size_t i = 0; i < 8; ++i) { + bool value = i % 2 == 0; + ASSERT_EQ(CborNoError, oc_rep_encode_boolean(oc_rep_get_encoder(), value)); + crcData.push_back(value ? OC_CRC_REP_TRUE : OC_CRC_REP_FALSE); + expCrc = calculateCrc(expCrc, CborBooleanType, &crcData[i], 1); + } + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeInt) +{ + SetRepBuffer(1, 2); + int64_t value = INT64_MAX; + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_int(oc_rep_get_encoder(), value)); + + SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, oc_rep_encode_int(oc_rep_get_encoder(), value)); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + std::array crcData{}; + memcpy(&crcData[0], &value, sizeof(value)); + uint64_t expCrc = + calculateCrc(0, CborIntegerType, crcData.data(), crcData.size()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeUint) +{ + SetRepBuffer(1, 3); + uint64_t value = UINT64_MAX; + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_uint(oc_rep_get_encoder(), value)); + + SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, oc_rep_encode_uint(oc_rep_get_encoder(), value)); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + std::array crcData{}; + memcpy(&crcData[0], &value, sizeof(value)); + uint64_t expCrc = + calculateCrc(0, CborIntegerType, crcData.data(), crcData.size()); + EXPECT_EQ(expCrc, *crc); +} + +template +static void +encodeFloat() +{ + TestCrcRepEncodeWithRealloc::SetRepBuffer(1, 4); + FloatType value = std::numeric_limits::max(); + + CborType fp = CborInvalidType; + if (sizeof(FloatType) == sizeof(uint16_t)) { + fp = CborHalfFloatType; + } else if (sizeof(FloatType) == sizeof(float)) { + fp = CborFloatType; + } else if (sizeof(FloatType) == sizeof(double)) { + fp = CborDoubleType; + } + if (fp == CborInvalidType) { + return; + } + + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_floating_point(oc_rep_get_encoder(), fp, &value)); + TestCrcRepEncodeWithRealloc::SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, + oc_rep_encode_floating_point(oc_rep_get_encoder(), fp, &value)); + + auto crc = TestCrcRepEncodeWithRealloc::geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + std::array crcData{}; + memcpy(&crcData[0], &value, sizeof(value)); + uint64_t expCrc = calculateCrc(0, fp, crcData.data(), crcData.size()); + EXPECT_EQ(expCrc, *crc); +} + +#ifdef HAVE_FLOAT16 + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeFloat16) +{ + encodeFloat<_Float16>(); +} + +#endif /* HAVE_FLOAT16 */ + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeFloat) +{ + encodeFloat(); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeDoubleFloat) +{ + encodeFloat(); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeFloat_Fail) +{ + SetRepBuffer(1, 8); + bool value = true; + EXPECT_NE(CborNoError, oc_rep_encode_floating_point(oc_rep_get_encoder(), + CborBooleanType, &value)); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeDouble) +{ + SetRepBuffer(1, 5); + double value = std::numeric_limits::max(); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encode_double(oc_rep_get_encoder(), value)); + SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, oc_rep_encode_double(oc_rep_get_encoder(), value)); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + std::array crcData{}; + memcpy(&crcData[0], &value, sizeof(value)); + uint64_t expCrc = + calculateCrc(0, CborDoubleType, crcData.data(), crcData.size()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeByteString) +{ + SetRepBuffer(1, 6); + std::vector bstr = { 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, + 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, 0x0 }; + EXPECT_EQ( + CborErrorOutOfMemory, + oc_rep_encode_byte_string(oc_rep_get_encoder(), bstr.data(), bstr.size())); + + SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, oc_rep_encode_byte_string(oc_rep_get_encoder(), + bstr.data(), bstr.size())); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + uint64_t expCrc = + calculateCrc(0, CborByteStringType, bstr.data(), bstr.size()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeTextString) +{ + SetRepBuffer(1, 7); + std::string str = "test"; + EXPECT_EQ( + CborErrorOutOfMemory, + oc_rep_encode_text_string(oc_rep_get_encoder(), str.c_str(), str.length())); + + SetRepBuffer(1, 8); + str = "this is 16 chars"; + ASSERT_EQ(CborNoError, oc_rep_encode_text_string(oc_rep_get_encoder(), + str.c_str(), str.length())); + ASSERT_EQ(8, oc_rep_get_encoded_payload_size()); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + auto data = oc::GetVector(str); + uint64_t expCrc = + calculateCrc(0, CborTextStringType, data.data(), data.size()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeArray) +{ + SetRepBuffer(1, 1); + CborEncoder array{}; + ASSERT_EQ(CborErrorOutOfMemory, + oc_rep_encoder_create_array(oc_rep_get_encoder(), &array, + CborIndefiniteLength)); + + SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( + oc_rep_get_encoder(), &array, CborIndefiniteLength)); + uint8_t openByte = OC_CRC_OPEN_CONTAINER; + uint8_t closeByte = OC_CRC_CLOSE_CONTAINER; + uint64_t expCrc = calculateCrc(0, CborArrayType, &openByte, 1); + + ASSERT_EQ(CborNoError, + oc_rep_encoder_close_container(oc_rep_get_encoder(), &array)); + expCrc = calculateCrc(expCrc, CborArrayType, &closeByte, 1); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeArrayOfArrays) +{ + SetRepBuffer(1, 8); + + CborEncoder array{}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( + oc_rep_get_encoder(), &array, CborIndefiniteLength)); + const uint8_t openByte = OC_CRC_OPEN_CONTAINER; + const uint8_t closeByte = OC_CRC_CLOSE_CONTAINER; + uint64_t expCrc = calculateCrc(0, CborArrayType, &openByte, 1); + + // bool array + CborEncoder boolArray{}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_array(&array, &boolArray, + CborIndefiniteLength)); + expCrc = calculateCrc(expCrc, CborArrayType, &openByte, 1); + + uint8_t boolValue = OC_CRC_REP_TRUE; + ASSERT_EQ(CborNoError, oc_rep_encode_boolean(&boolArray, true)); + expCrc = calculateCrc(expCrc, CborBooleanType, &boolValue, 1); + + boolValue = OC_CRC_REP_FALSE; + ASSERT_EQ(CborNoError, oc_rep_encode_boolean(&boolArray, false)); + expCrc = calculateCrc(expCrc, CborBooleanType, &boolValue, 1); + + ASSERT_EQ(CborNoError, oc_rep_encoder_close_container(&array, &boolArray)); + expCrc = calculateCrc(expCrc, CborArrayType, &closeByte, 1); + + // integer Array + CborEncoder intArray{}; + ASSERT_EQ(CborNoError, oc_rep_encoder_create_array(&array, &intArray, + CborIndefiniteLength)); + expCrc = calculateCrc(expCrc, CborArrayType, &openByte, 1); + + int64_t intValue = 0; + ASSERT_EQ(CborNoError, oc_rep_encode_int(&intArray, intValue)); + std::array crcData{}; + memcpy(&crcData[0], &intValue, sizeof(intValue)); + expCrc = + calculateCrc(expCrc, CborIntegerType, crcData.data(), crcData.size()); + + intValue = 42; + ASSERT_EQ(CborNoError, oc_rep_encode_int(&intArray, intValue)); + memcpy(&crcData[0], &intValue, sizeof(intValue)); + expCrc = + calculateCrc(expCrc, CborIntegerType, crcData.data(), crcData.size()); + + ASSERT_EQ(CborNoError, oc_rep_encoder_close_container(&array, &intArray)); + expCrc = calculateCrc(expCrc, CborArrayType, &closeByte, 1); + + ASSERT_EQ(CborNoError, + oc_rep_encoder_close_container(oc_rep_get_encoder(), &array)); + expCrc = calculateCrc(expCrc, CborArrayType, &closeByte, 1); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodeMap) +{ + SetRepBuffer(1, 1); + CborEncoder map{}; + ASSERT_EQ(CborErrorOutOfMemory, + oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, + CborIndefiniteLength)); + + SetRepBuffer(1, 8); + ASSERT_EQ(CborNoError, oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, + CborIndefiniteLength)); + const uint8_t openByte = OC_CRC_OPEN_CONTAINER; + const uint8_t closeByte = OC_CRC_CLOSE_CONTAINER; + uint64_t expCrc = calculateCrc(0, CborMapType, &openByte, 1); + + ASSERT_EQ(CborNoError, + oc_rep_encoder_close_container(oc_rep_get_encoder(), &map)); + expCrc = calculateCrc(expCrc, CborMapType, &closeByte, 1); + + auto crc = geyPayloadCRC(); + ASSERT_TRUE(crc.has_value()); + EXPECT_EQ(expCrc, *crc); +} + +TEST_F(TestCrcRepEncodeWithRealloc, EncodedPayloadRealloc) +{ + SetRepBuffer(1, 1024); + + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_start_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_text_string(root, hello, "world"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_double(root, double, 3.14); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_boolean(root, bool, true); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_int(root, int, -1); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_uint(root, uint, -1); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + std::vector byte_string = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + oc_rep_set_byte_string(root, byte_string_key, byte_string.data(), + byte_string.size()); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + std::vector fib = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 }; + oc_rep_set_key(oc_rep_object(root), "fibonacci"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_begin_array(oc_rep_object(root), fibonacci); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + for (const auto &val : fib) { + oc_rep_add_int(fibonacci, val); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + } + oc_rep_end_array(oc_rep_object(root), fibonacci); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + std::vector math_constants = { 3.14159, 2.71828, 1.414121, 1.61803 }; + oc_rep_set_double_array(root, math_constants, math_constants.data(), + math_constants.size()); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + + size_t payload_size = oc_rep_get_encoded_payload_size(); + EXPECT_EQ(8, payload_size); +#ifdef OC_DYNAMIC_ALLOCATION + EXPECT_GT(oc_rep_get_encoder_buffer_size(), payload_size); +#endif /* OC_DYNAMIC_ALLOCATION */ + Shrink(); +#ifdef OC_DYNAMIC_ALLOCATION + EXPECT_EQ(oc_rep_get_encoder_buffer_size(), payload_size); +#endif /* OC_DYNAMIC_ALLOCATION */ +} + +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ diff --git a/api/unittest/repencodejsontest.cpp b/api/unittest/repencodejsontest.cpp index ad194e3060..bc5462bbf2 100644 --- a/api/unittest/repencodejsontest.cpp +++ b/api/unittest/repencodejsontest.cpp @@ -20,6 +20,8 @@ #ifdef OC_JSON_ENCODER +#include "encoder/TestEncoderBuffer.h" + #include "api/oc_rep_encode_internal.h" #include "api/oc_rep_encode_json_internal.h" #include "api/oc_rep_decode_internal.h" @@ -29,143 +31,47 @@ #include #include +#include #include #include #include -static const oc_rep_encoder_type_t g_rep_default_encoder = - oc_rep_encoder_get_type(); -static const oc_rep_decoder_type_t g_rep_default_decoder = - oc_rep_decoder_get_type(); - class TestJsonRepEncodeWithRealloc : public testing::Test { public: static void SetUpTestCase() { - oc_rep_encoder_set_type(OC_REP_JSON_ENCODER); - oc_rep_decoder_set_type(OC_REP_JSON_DECODER); + TestEncoderBuffer::StoreDefaults(); + TestJsonRepEncodeWithRealloc::encoder = + std::make_unique(OC_REP_JSON_ENCODER); + ASSERT_EQ(OC_REP_JSON_ENCODER, oc_rep_encoder_get_type()); } static void TearDownTestCase() { - oc_rep_encoder_set_type(g_rep_default_encoder); - oc_rep_decoder_set_type(g_rep_default_decoder); - } - - void TearDown() override - { -#ifdef OC_DYNAMIC_ALLOCATION - free(buffer_); -#endif /* OC_DYNAMIC_ALLOCATION */ + TestJsonRepEncodeWithRealloc::encoder.reset(); + TestEncoderBuffer::RestoreDefaults(); } - /* buffer for oc_rep_t */ - void SetRepBuffer(size_t size = 1024, size_t max_size = 1024) + static void SetRepBuffer(size_t size = 1024, size_t max_size = 1024) { -#ifdef OC_DYNAMIC_ALLOCATION - if (buffer_ != nullptr) { - free(buffer_); - } - buffer_ = nullptr; - if (size > 0) { - buffer_ = static_cast(malloc(size)); - } - oc_rep_new_realloc_v1(&buffer_, size, max_size); -#else /* OC_DYNAMIC_ALLOCATION */ - (void)size; - buffer_.resize(max_size); - oc_rep_new_v1(buffer_.data(), buffer_.size()); - memset(rep_objects_alloc_, 0, OC_MAX_NUM_REP_OBJECTS * sizeof(char)); - memset(rep_objects_pool_, 0, OC_MAX_NUM_REP_OBJECTS * sizeof(oc_rep_t)); -#endif /* OC_DYNAMIC_ALLOCATION */ + TestJsonRepEncodeWithRealloc::encoder->SetRepBuffer(size, max_size); } - void Shrink() + static oc::oc_rep_unique_ptr ParsePayload() { -#ifdef OC_DYNAMIC_ALLOCATION - buffer_ = oc_rep_shrink_encoder_buf(buffer_); -#endif /* OC_DYNAMIC_ALLOCATION */ + return TestJsonRepEncodeWithRealloc::encoder->ParsePayload(); } - oc::oc_rep_unique_ptr ParsePayload() - { - const uint8_t *payload = oc_rep_get_encoder_buf(); - int payload_len = oc_rep_get_encoded_payload_size(); - EXPECT_NE(payload_len, -1); - oc_rep_set_pool(&rep_objects_); - oc_rep_t *rep = nullptr; - EXPECT_EQ(CborNoError, oc_parse_rep(payload, payload_len, &rep)); - return oc::oc_rep_unique_ptr(rep, &oc_free_rep); - } + static void Shrink() { TestJsonRepEncodeWithRealloc::encoder->Shrink(); } -#ifdef OC_DYNAMIC_ALLOCATION - uint8_t *buffer_{ nullptr }; - oc_memb rep_objects_{ sizeof(oc_rep_t), 0, nullptr, nullptr, nullptr }; -#else /* !OC_DYNAMIC_ALLOCATION */ - std::vector buffer_{}; - char rep_objects_alloc_[OC_MAX_NUM_REP_OBJECTS]; - oc_rep_t rep_objects_pool_[OC_MAX_NUM_REP_OBJECTS]; - oc_memb rep_objects_{ sizeof(oc_rep_t), OC_MAX_NUM_REP_OBJECTS, - rep_objects_alloc_, (void *)rep_objects_pool_, - nullptr }; -#endif /* OC_DYNAMIC_ALLOCATION */ + static std::unique_ptr encoder; }; -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodedPayloadRealloc) -{ - SetRepBuffer(1, 1024); - - oc_rep_start_root_object(); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_text_string(root, hello, "world"); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_double(root, double, 3.14); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_boolean(root, bool, true); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_int(root, int, -1); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_uint(root, uint, OC_REP_JSON_UINT_MAX); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); -#if 0 - std::vector byte_string = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; - oc_rep_set_byte_string(root, byte_string_key, byte_string.data(), - byte_string.size()); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); -#endif - std::vector fib = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 }; - oc_rep_set_key(oc_rep_object(root), "fibonacci"); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_begin_array(oc_rep_object(root), fibonacci); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - for (const auto &val : fib) { - oc_rep_add_int(fibonacci, val); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - } - oc_rep_end_array(oc_rep_object(root), fibonacci); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - std::vector math_constants = { 3.14159, 2.71828, 1.414121, 1.61803 }; - oc_rep_set_double_array(root, math_constants, math_constants.data(), - math_constants.size()); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_end_root_object(); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - - auto rep = ParsePayload(); - ASSERT_NE(nullptr, rep.get()); - OC_DBG("payload: %s", oc::RepPool::GetJson(rep.get(), true).data()); - size_t payload_size = oc_rep_get_encoded_payload_size(); - EXPECT_EQ(176, payload_size); -#ifdef OC_DYNAMIC_ALLOCATION - EXPECT_GT(oc_rep_get_encoder_buffer_size(), payload_size); -#endif /* OC_DYNAMIC_ALLOCATION */ - Shrink(); -#ifdef OC_DYNAMIC_ALLOCATION - EXPECT_EQ(oc_rep_get_encoder_buffer_size(), payload_size); -#endif /* OC_DYNAMIC_ALLOCATION */ -} +std::unique_ptr TestJsonRepEncodeWithRealloc::encoder{ + nullptr +}; -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeRaw) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeRaw) { std::vector in{ '\0' }; SetRepBuffer(0, 0); @@ -189,23 +95,23 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeRaw) EXPECT_EQ(CborErrorOutOfMemory, oc_rep_get_cbor_errno()); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeNull) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeNull) { /* null */ - constexpr size_t json_null_size = 4; - SetRepBuffer(1, json_null_size); + size_t kNullRepSize = 4; + SetRepBuffer(1, kNullRepSize); ASSERT_EQ(CborNoError, oc_rep_encode_null(oc_rep_get_encoder())); EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_null(oc_rep_get_encoder())); - SetRepBuffer(1, 8 * json_null_size); + SetRepBuffer(1, 8 * kNullRepSize); for (size_t i = 0; i < 8; ++i) { ASSERT_EQ(CborNoError, oc_rep_encode_null(oc_rep_get_encoder())); } - EXPECT_EQ(8 * json_null_size, oc_rep_get_encoded_payload_size()); + EXPECT_EQ(8 * kNullRepSize, oc_rep_get_encoded_payload_size()); EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_null(oc_rep_get_encoder())); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeNull_InvalidNullMapKey) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeNull_InvalidNullMapKey) { SetRepBuffer(); CborEncoder map{}; @@ -215,26 +121,31 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeNull_InvalidNullMapKey) EXPECT_EQ(CborErrorImproperValue, oc_rep_encode_null(&map)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeBool) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeBool) { - /* true, false */ - SetRepBuffer(1, 5); + /* true */ + constexpr size_t kTrueRepSize = 4; + /* false */ + constexpr size_t kFalseRepSize = 5; + + SetRepBuffer(1, kFalseRepSize); ASSERT_EQ(CborNoError, oc_rep_encode_boolean(oc_rep_get_encoder(), false)); EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_boolean(oc_rep_get_encoder(), true)); - // 4 * true + 4 * false = 36 - SetRepBuffer(1, 4 * 4 + 4 * 5); + // 4 * true + 4 * false + SetRepBuffer(1, 4 * kTrueRepSize + 4 * kFalseRepSize); for (size_t i = 0; i < 8; ++i) { ASSERT_EQ(CborNoError, oc_rep_encode_boolean(oc_rep_get_encoder(), i % 2 == 0)); } - ASSERT_EQ(4 * 4 + 4 * 5, oc_rep_get_encoded_payload_size()); + ASSERT_EQ(4 * kTrueRepSize + 4 * kFalseRepSize, + oc_rep_get_encoded_payload_size()); EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_boolean(oc_rep_get_encoder(), false)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeBool_InvalidBoolMapKey) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeBool_InvalidBoolMapKey) { SetRepBuffer(); CborEncoder map{}; @@ -244,7 +155,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeBool_InvalidBoolMapKey) EXPECT_EQ(CborErrorImproperValue, oc_rep_encode_boolean(&map, true)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeInt) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeInt) { SetRepBuffer(1, 1); EXPECT_EQ(CborErrorOutOfMemory, @@ -259,7 +170,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeInt) oc_rep_encode_int(oc_rep_get_encoder(), OC_REP_JSON_INT_MAX)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeInt_InvalidIntMapKey) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeInt_InvalidIntMapKey) { SetRepBuffer(); CborEncoder map{}; @@ -269,7 +180,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeInt_InvalidIntMapKey) EXPECT_EQ(CborErrorImproperValue, oc_rep_encode_int(&map, 1)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeInt_InvalidIntValue) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeInt_InvalidIntValue) { SetRepBuffer(); EXPECT_EQ(CborErrorDataTooLarge, @@ -278,7 +189,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeInt_InvalidIntValue) oc_rep_encode_int(oc_rep_get_encoder(), OC_REP_JSON_INT_MIN - 1)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeUint) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeUint) { SetRepBuffer(1, 1); EXPECT_EQ(CborErrorOutOfMemory, @@ -293,7 +204,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeUint) oc_rep_encode_uint(oc_rep_get_encoder(), OC_REP_JSON_UINT_MAX)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeUint_InvalidUintMapKey) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeUint_InvalidUintMapKey) { SetRepBuffer(); CborEncoder map{}; @@ -303,14 +214,14 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeUint_InvalidUintMapKey) EXPECT_EQ(CborErrorImproperValue, oc_rep_encode_uint(&map, 1)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeUint_InvalidUintValue) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeUint_InvalidUintValue) { SetRepBuffer(); EXPECT_EQ(CborErrorDataTooLarge, oc_rep_encode_uint(oc_rep_get_encoder(), OC_REP_JSON_UINT_MAX + 1)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeFloat_UnsupportedType) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeFloat_UnsupportedType) { float val = 0; SetRepBuffer(); @@ -319,7 +230,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeFloat_UnsupportedType) oc_rep_encode_floating_point(oc_rep_get_encoder(), CborFloatType, &val)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeDouble) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeDouble) { SetRepBuffer(1, 1); EXPECT_EQ(CborErrorOutOfMemory, @@ -337,7 +248,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeDouble) std::numeric_limits::max())); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeDouble_InvalidDoubleMapKey) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeDouble_InvalidDoubleMapKey) { SetRepBuffer(); CborEncoder map{}; @@ -347,7 +258,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeDouble_InvalidDoubleMapKey) EXPECT_EQ(CborErrorImproperValue, oc_rep_encode_double(&map, 0.0)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeTextString) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeTextString) { SetRepBuffer(1, 1); std::string str = "test"; @@ -369,7 +280,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeTextString) oc_rep_encode_text_string(oc_rep_get_encoder(), str.c_str(), str.length())); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeByteString_UnsupportedType) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeByteString_UnsupportedType) { std::vector bstr = { 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, 0x0 }; @@ -379,7 +290,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeByteString_UnsupportedType) oc_rep_encode_byte_string(oc_rep_get_encoder(), bstr.data(), bstr.size())); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeArray) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeArray) { SetRepBuffer(1, 1); CborEncoder array{}; @@ -408,7 +319,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeArray) ASSERT_EQ(6, oc_rep_get_encoded_payload_size()); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeArray_InvalidArrayMapKey) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeArray_InvalidArrayMapKey) { SetRepBuffer(); CborEncoder map{}; @@ -420,7 +331,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeArray_InvalidArrayMapKey) oc_rep_encoder_create_array(&map, &array, CborIndefiniteLength)); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeMap) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeMap) { std::string key = "key"; SetRepBuffer(1, 7); @@ -456,7 +367,7 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeMap) OC_DBG("payload: %s", oc::RepPool::GetJson(rep.get(), true).data()); } -TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeMap_InvalidObjectMapKey) +TEST_F(TestJsonRepEncodeWithRealloc, EncodeMap_InvalidObjectMapKey) { SetRepBuffer(); CborEncoder map{}; @@ -468,4 +379,58 @@ TEST_F(TestJsonRepEncodeWithRealloc, OCRepEncodeMap_InvalidObjectMapKey) oc_rep_encoder_create_map(&map, &inner_map, CborIndefiniteLength)); } +TEST_F(TestJsonRepEncodeWithRealloc, EncodedPayloadRealloc) +{ + SetRepBuffer(1, 1024); + + oc_rep_start_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_text_string(root, hello, "world"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_double(root, double, 3.14); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_boolean(root, bool, true); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_int(root, int, -1); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_uint(root, uint, OC_REP_JSON_UINT_MAX); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); +#if 0 + std::vector byte_string = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + oc_rep_set_byte_string(root, byte_string_key, byte_string.data(), + byte_string.size()); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); +#endif + std::vector fib = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 }; + oc_rep_set_key(oc_rep_object(root), "fibonacci"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_begin_array(oc_rep_object(root), fibonacci); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + for (const auto &val : fib) { + oc_rep_add_int(fibonacci, val); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + } + oc_rep_end_array(oc_rep_object(root), fibonacci); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + std::vector math_constants = { 3.14159, 2.71828, 1.414121, 1.61803 }; + oc_rep_set_double_array(root, math_constants, math_constants.data(), + math_constants.size()); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + + auto rep = ParsePayload(); + ASSERT_NE(nullptr, rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(rep.get(), true).data()); + size_t payload_size = oc_rep_get_encoded_payload_size(); + EXPECT_EQ(176, payload_size); +#ifdef OC_DYNAMIC_ALLOCATION + EXPECT_GT(oc_rep_get_encoder_buffer_size(), payload_size); +#endif /* OC_DYNAMIC_ALLOCATION */ + Shrink(); +#ifdef OC_DYNAMIC_ALLOCATION + EXPECT_EQ(oc_rep_get_encoder_buffer_size(), payload_size); +#endif /* OC_DYNAMIC_ALLOCATION */ +} + #endif /* OC_JSON_ENCODER */ diff --git a/api/unittest/repencodetest.cpp b/api/unittest/repencodetest.cpp index 92a5179337..397e902869 100644 --- a/api/unittest/repencodetest.cpp +++ b/api/unittest/repencodetest.cpp @@ -16,354 +16,270 @@ * ******************************************************************/ +#include "encoder/TestEncoderBuffer.h" + #include "api/oc_rep_encode_internal.h" -#include "api/oc_rep_decode_internal.h" -#include "oc_rep.h" +#include "oc_buffer_settings.h" #include "port/oc_log_internal.h" +#include "util/oc_features.h" #include "tests/gtest/RepPool.h" #include -#include -#include -#include +#include #include -static const oc_rep_encoder_type_t g_rep_default_encoder = - oc_rep_encoder_get_type(); -static const oc_rep_decoder_type_t g_rep_default_decoder = - oc_rep_decoder_get_type(); - -class TestRepEncodeWithRealloc : public testing::Test { +class TestRepEncode : public testing::Test { public: - static void SetUpTestCase() - { - oc_rep_encoder_set_type(OC_REP_CBOR_ENCODER); - oc_rep_decoder_set_type(OC_REP_CBOR_DECODER); - } - - static void TearDownTestCase() - { - oc_rep_encoder_set_type(g_rep_default_encoder); - oc_rep_decoder_set_type(g_rep_default_decoder); - } + static void SetUpTestCase() { TestEncoderBuffer::StoreDefaults(); } - void TearDown() override - { -#ifdef OC_DYNAMIC_ALLOCATION - free(buffer_); -#endif /* OC_DYNAMIC_ALLOCATION */ - } + void TearDown() override { TestEncoderBuffer::RestoreDefaults(); } +}; - /* buffer for oc_rep_t */ - void SetRepBuffer(size_t size = 1024, size_t max_size = 1024) - { -#ifdef OC_DYNAMIC_ALLOCATION - if (buffer_ != nullptr) { - free(buffer_); - } - buffer_ = nullptr; - if (size > 0) { - buffer_ = static_cast(malloc(size)); +TEST_F(TestRepEncode, SetEncoderByAccept) +{ + ASSERT_TRUE(oc_rep_encoder_set_type_by_accept(APPLICATION_NOT_DEFINED)); + EXPECT_EQ(OC_REP_CBOR_ENCODER, oc_rep_encoder_get_type()); + + std::map encoders{ + { APPLICATION_CBOR, OC_REP_CBOR_ENCODER }, + { APPLICATION_VND_OCF_CBOR, OC_REP_CBOR_ENCODER }, +#ifdef OC_JSON_ENCODER + { APPLICATION_JSON, OC_REP_JSON_ENCODER }, + { APPLICATION_TD_JSON, OC_REP_JSON_ENCODER }, +#endif /* OC_JSON_ENCODER */ + { APPLICATION_NOT_DEFINED, OC_REP_CBOR_ENCODER }, + }; + + oc_rep_encoder_type_t et = oc_rep_encoder_get_type(); + for (int cf = 0; cf < APPLICATION_NOT_DEFINED; ++cf) { + if (encoders.find(static_cast(cf)) != encoders.end()) { + EXPECT_TRUE(oc_rep_encoder_set_type_by_accept( + static_cast(cf))); + et = oc_rep_encoder_get_type(); + EXPECT_EQ(encoders[static_cast(cf)], et); + continue; } - oc_rep_new_realloc_v1(&buffer_, size, max_size); -#else /* OC_DYNAMIC_ALLOCATION */ - (void)size; - buffer_.resize(max_size); - oc_rep_new_v1(buffer_.data(), buffer_.size()); - memset(rep_objects_alloc_, 0, OC_MAX_NUM_REP_OBJECTS * sizeof(char)); - memset(rep_objects_pool_, 0, OC_MAX_NUM_REP_OBJECTS * sizeof(oc_rep_t)); -#endif /* OC_DYNAMIC_ALLOCATION */ + EXPECT_FALSE( + oc_rep_encoder_set_type_by_accept(static_cast(cf))); + EXPECT_EQ(et, oc_rep_encoder_get_type()); } +} + +TEST_F(TestRepEncode, GetContentFormat) +{ + oc_content_format_t cf{}; + oc_rep_encoder_set_type(OC_REP_CBOR_ENCODER); + ASSERT_TRUE(oc_rep_encoder_get_content_format(&cf)); + EXPECT_EQ(APPLICATION_VND_OCF_CBOR, cf); +#ifdef OC_JSON_ENCODER + oc_rep_encoder_set_type(OC_REP_JSON_ENCODER); + ASSERT_TRUE(oc_rep_encoder_get_content_format(&cf)); + EXPECT_EQ(APPLICATION_JSON, cf); +#endif /* OC_JSON_ENCODER */ +#ifdef OC_HAS_FEATURE_CRC_ENCODER + oc_rep_encoder_set_type(OC_REP_CRC_ENCODER); + ASSERT_FALSE(oc_rep_encoder_get_content_format(&cf)); +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ +} + +TEST_F(TestRepEncode, ShrinkEncoderBuffer) +{ + EXPECT_EQ(nullptr, oc_rep_shrink_encoder_buf(nullptr)); + + uint8_t byte; + EXPECT_EQ(&byte, oc_rep_shrink_encoder_buf(&byte)); - void Shrink() - { #ifdef OC_DYNAMIC_ALLOCATION - buffer_ = oc_rep_shrink_encoder_buf(buffer_); + // with enabled realloc + auto *buf = static_cast(malloc(1)); + oc_rep_new_realloc_v1(&buf, 1, 8); + EXPECT_EQ(buf, oc_rep_shrink_encoder_buf(buf)); + + // with disabled realloc + oc_rep_new_v1(buf, 1); + EXPECT_EQ(buf, oc_rep_shrink_encoder_buf(buf)); + + free(buf); #endif /* OC_DYNAMIC_ALLOCATION */ - } - oc::oc_rep_unique_ptr ParsePayload() - { - const uint8_t *payload = oc_rep_get_encoder_buf(); - int payload_len = oc_rep_get_encoded_payload_size(); - EXPECT_NE(payload_len, -1); - oc_rep_set_pool(&rep_objects_); - oc_rep_t *rep = nullptr; - EXPECT_EQ(CborNoError, oc_parse_rep(payload, payload_len, &rep)); - return oc::oc_rep_unique_ptr(rep, &oc_free_rep); - } + memset(oc_rep_global_encoder(), 0, sizeof(oc_rep_encoder_t)); +} #ifdef OC_DYNAMIC_ALLOCATION - uint8_t *buffer_{ nullptr }; - oc_memb rep_objects_{ sizeof(oc_rep_t), 0, nullptr, nullptr, nullptr }; -#else /* !OC_DYNAMIC_ALLOCATION */ - std::vector buffer_{}; - char rep_objects_alloc_[OC_MAX_NUM_REP_OBJECTS]; - oc_rep_t rep_objects_pool_[OC_MAX_NUM_REP_OBJECTS]; - oc_memb rep_objects_{ sizeof(oc_rep_t), OC_MAX_NUM_REP_OBJECTS, - rep_objects_alloc_, (void *)rep_objects_pool_, - nullptr }; + +TEST_F(TestRepEncode, ShrinkBuffer_Fail) +{ + oc_rep_encoder_t encoder{}; + // buffer.enable_realloc is false + EXPECT_FALSE(oc_rep_encoder_shrink_buffer(&encoder)); + + encoder.buffer.enable_realloc = true; + // buffer.pptr is nullptr + EXPECT_FALSE(oc_rep_encoder_shrink_buffer(&encoder)); + + // shrink not needed -> buffer is larger than the payload + constexpr size_t kBufferSize = 8; + constexpr size_t kMaxBufferSize = 1024; + auto *buf = static_cast(malloc(kBufferSize)); + oc_rep_encoder_buffer_t eb{}; + eb.ptr = buf; + eb.pptr = &buf; + eb.size = kBufferSize; + eb.max_size = kMaxBufferSize; + eb.enable_realloc = true; + encoder = oc_rep_encoder(OC_REP_CBOR_ENCODER, eb); + EXPECT_FALSE(oc_rep_encoder_shrink_buffer(&encoder)); + free(buf); +} + +TEST_F(TestRepEncode, WriteRaw_Fail) +{ + constexpr size_t kBufferSize = 8; + constexpr size_t kMaxBufferSize = 1024; + auto *buf = static_cast(malloc(kBufferSize)); + oc_rep_encoder_buffer_t eb{}; + eb.ptr = buf; + eb.pptr = &buf; + eb.size = kBufferSize; + eb.max_size = kMaxBufferSize; + eb.enable_realloc = false; + oc_rep_encoder_t encoder = oc_rep_encoder(OC_REP_CBOR_ENCODER, eb); + + std::vector rawData{}; + rawData.resize(kBufferSize + 1); + // buffer too small and enable_realloc == false + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encoder_write_raw(&encoder, rawData.data(), rawData.size())); + + // buffer too small, and maximum size is smaller than the payload + eb.enable_realloc = true; + encoder = oc_rep_encoder(OC_REP_CBOR_ENCODER, eb); + ASSERT_EQ(CborNoError, + oc_rep_encoder_write_raw(&encoder, rawData.data(), rawData.size())); + + encoder = oc_rep_encoder(OC_REP_CBOR_ENCODER, eb); + rawData.resize(kMaxBufferSize + 1); + EXPECT_EQ(CborErrorOutOfMemory, + oc_rep_encoder_write_raw(&encoder, rawData.data(), rawData.size())); + free(buf); +} + #endif /* OC_DYNAMIC_ALLOCATION */ -}; -TEST_F(TestRepEncodeWithRealloc, OCRepEncodedPayloadRealloc) +TEST_F(TestRepEncode, MultipleCBorEncoders) { - SetRepBuffer(1, 1024); + TestEncoderBuffer cborBuf1{ OC_REP_CBOR_ENCODER }; + cborBuf1.SetRepBuffer(1, 1024); oc_rep_start_root_object(); ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); oc_rep_set_text_string(root, hello, "world"); ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_double(root, double, 3.14); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_boolean(root, bool, true); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_int(root, int, -1); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_set_uint(root, uint, -1); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - std::vector byte_string = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; - oc_rep_set_byte_string(root, byte_string_key, byte_string.data(), - byte_string.size()); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - std::vector fib = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 }; - oc_rep_set_key(oc_rep_object(root), "fibonacci"); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_begin_array(oc_rep_object(root), fibonacci); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - for (const auto &val : fib) { - oc_rep_add_int(fibonacci, val); - ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - } - oc_rep_end_array(oc_rep_object(root), fibonacci); + + auto cborEncoder1 = oc_rep_global_encoder_reset(nullptr); + + TestEncoderBuffer cborBuf2{ OC_REP_CBOR_ENCODER }; + cborBuf2.SetRepBuffer(1, 1024); + oc_rep_start_root_object(); ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - std::vector math_constants = { 3.14159, 2.71828, 1.414121, 1.61803 }; - oc_rep_set_double_array(root, math_constants, math_constants.data(), - math_constants.size()); + oc_rep_set_int(root, int, 42); ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); oc_rep_end_root_object(); ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - auto rep = ParsePayload(); - ASSERT_NE(nullptr, rep.get()); - OC_DBG("payload: %s", oc::RepPool::GetJson(rep.get(), true).data()); - size_t payload_size = oc_rep_get_encoded_payload_size(); - EXPECT_EQ(156, payload_size); -#ifdef OC_DYNAMIC_ALLOCATION - EXPECT_GT(oc_rep_get_encoder_buffer_size(), payload_size); -#endif /* OC_DYNAMIC_ALLOCATION */ - Shrink(); -#ifdef OC_DYNAMIC_ALLOCATION - EXPECT_EQ(oc_rep_get_encoder_buffer_size(), payload_size); -#endif /* OC_DYNAMIC_ALLOCATION */ -} + auto cbor2Rep = cborBuf2.ParsePayload(); + ASSERT_NE(nullptr, cbor2Rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(cbor2Rep.get(), true).data()); -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeRaw) -{ - std::vector in{ '\0' }; - SetRepBuffer(0, 0); - oc_rep_encode_raw(in.data(), in.size()); - EXPECT_EQ(CborErrorInternalError, oc_rep_get_cbor_errno()); - - SetRepBuffer(1, 1); - oc_rep_encode_raw(in.data(), in.size()); - EXPECT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_encode_raw(in.data(), in.size()); - EXPECT_EQ(CborErrorOutOfMemory, oc_rep_get_cbor_errno()); - - SetRepBuffer(1, 8); - for (size_t i = 0; i < 8; ++i) { - oc_rep_encode_raw(in.data(), in.size()); - EXPECT_EQ(CborNoError, oc_rep_get_cbor_errno()); - } - EXPECT_EQ(8, oc_rep_get_encoded_payload_size()); + oc_rep_global_encoder_reset(&cborEncoder1); + oc_rep_set_text_string(root, goodbye, "underworld"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - oc_rep_encode_raw(in.data(), in.size()); - EXPECT_EQ(CborErrorOutOfMemory, oc_rep_get_cbor_errno()); + auto cbor1Rep = cborBuf1.ParsePayload(); + ASSERT_NE(nullptr, cbor1Rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(cbor1Rep.get(), true).data()); } -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeNull) -{ - SetRepBuffer(1, 1); - ASSERT_EQ(CborNoError, oc_rep_encode_null(oc_rep_get_encoder())); - EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_null(oc_rep_get_encoder())); - - SetRepBuffer(1, 8); - for (size_t i = 0; i < 8; ++i) { - ASSERT_EQ(CborNoError, oc_rep_encode_null(oc_rep_get_encoder())); - } - ASSERT_EQ(8, oc_rep_get_encoded_payload_size()); - EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_null(oc_rep_get_encoder())); -} +#ifdef OC_JSON_ENCODER -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeBool) +TEST_F(TestRepEncode, JsonAndCborEncoder) { - SetRepBuffer(1, 1); - ASSERT_EQ(CborNoError, oc_rep_encode_boolean(oc_rep_get_encoder(), false)); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_boolean(oc_rep_get_encoder(), true)); + TestEncoderBuffer cborBuf1{ OC_REP_JSON_ENCODER }; + cborBuf1.SetRepBuffer(1, 1024); - SetRepBuffer(1, 8); - for (size_t i = 0; i < 8; ++i) { - ASSERT_EQ(CborNoError, - oc_rep_encode_boolean(oc_rep_get_encoder(), i % 2 == 0)); - } - ASSERT_EQ(8, oc_rep_get_encoded_payload_size()); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_boolean(oc_rep_get_encoder(), false)); -} + oc_rep_start_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_text_string(root, hello, "world"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeInt) -{ - SetRepBuffer(1, 1); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_int(oc_rep_get_encoder(), INT64_MAX)); + auto cborEncoder1 = oc_rep_global_encoder_reset(nullptr); - SetRepBuffer(1, 9); - ASSERT_EQ(CborNoError, oc_rep_encode_int(oc_rep_get_encoder(), INT64_MAX)); - ASSERT_EQ(9, oc_rep_get_encoded_payload_size()); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_int(oc_rep_get_encoder(), INT64_MAX)); -} + TestEncoderBuffer cborBuf2{ OC_REP_CBOR_ENCODER }; + cborBuf2.SetRepBuffer(1, 1024); + oc_rep_start_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_int(root, int, 42); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeUint) -{ - SetRepBuffer(1, 1); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_uint(oc_rep_get_encoder(), UINT64_MAX)); + auto cbor2Rep = cborBuf2.ParsePayload(); + ASSERT_NE(nullptr, cbor2Rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(cbor2Rep.get(), true).data()); - SetRepBuffer(1, 9); - ASSERT_EQ(CborNoError, oc_rep_encode_uint(oc_rep_get_encoder(), UINT64_MAX)); - ASSERT_EQ(9, oc_rep_get_encoded_payload_size()); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_uint(oc_rep_get_encoder(), UINT64_MAX)); -} + oc_rep_global_encoder_reset(&cborEncoder1); + oc_rep_set_text_string(root, goodbye, "underworld"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeFloat) -{ - float val = 0; - SetRepBuffer(1, 1); - EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_floating_point( - oc_rep_get_encoder(), CborFloatType, &val)); - - SetRepBuffer(1, 5); - val = std::numeric_limits::max(); - ASSERT_EQ(CborNoError, oc_rep_encode_floating_point(oc_rep_get_encoder(), - CborFloatType, &val)); - ASSERT_EQ(5, oc_rep_get_encoded_payload_size()); - EXPECT_EQ(CborErrorOutOfMemory, oc_rep_encode_floating_point( - oc_rep_get_encoder(), CborFloatType, &val)); + auto cbor1Rep = cborBuf1.ParsePayload(); + ASSERT_NE(nullptr, cbor1Rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(cbor1Rep.get(), true).data()); } -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeDouble) -{ - SetRepBuffer(1, 1); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_double(oc_rep_get_encoder(), - std::numeric_limits::max())); - - SetRepBuffer(1, 9); - ASSERT_EQ(CborNoError, - oc_rep_encode_double(oc_rep_get_encoder(), - std::numeric_limits::max())); - ASSERT_EQ(9, oc_rep_get_encoded_payload_size()); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encode_double(oc_rep_get_encoder(), - std::numeric_limits::max())); -} +#endif /* OC_JSON_ENCODER */ -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeTextString) -{ - SetRepBuffer(1, 1); - std::string str = "test"; - EXPECT_EQ( - CborErrorOutOfMemory, - oc_rep_encode_text_string(oc_rep_get_encoder(), str.c_str(), str.length())); - - SetRepBuffer(1, 17); - str = "this is 16 chars"; - ASSERT_EQ(CborNoError, oc_rep_encode_text_string(oc_rep_get_encoder(), - str.c_str(), str.length())); - ASSERT_EQ(17, oc_rep_get_encoded_payload_size()); - - str = "c"; - EXPECT_EQ( - CborErrorOutOfMemory, - oc_rep_encode_text_string(oc_rep_get_encoder(), str.c_str(), str.length())); -} +#ifdef OC_HAS_FEATURE_CRC_ENCODER -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeByteString) +TEST_F(TestRepEncode, CborAndCrcEncoder) { - SetRepBuffer(1, 1); - std::vector bstr = { 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, - 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x42, 0x0 }; - EXPECT_EQ( - CborErrorOutOfMemory, - oc_rep_encode_byte_string(oc_rep_get_encoder(), bstr.data(), bstr.size())); - - SetRepBuffer(1, 20); - EXPECT_EQ(CborNoError, oc_rep_encode_byte_string(oc_rep_get_encoder(), - bstr.data(), bstr.size())); -} + TestEncoderBuffer cborBuf1{ OC_REP_CBOR_ENCODER }; + cborBuf1.SetRepBuffer(1, 1024); -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeArray) -{ - SetRepBuffer(1, 1); - CborEncoder array{}; - CborEncoder inner_array{}; - ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( - oc_rep_get_encoder(), &array, CborIndefiniteLength)); - EXPECT_EQ( - CborErrorOutOfMemory, - oc_rep_encoder_create_array(&array, &inner_array, CborIndefiniteLength)); - - SetRepBuffer(1, 1); - array = {}; - ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( - oc_rep_get_encoder(), &array, CborIndefiniteLength)); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encoder_close_container(oc_rep_get_encoder(), &array)); + oc_rep_start_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_text_string(root, hello, "world"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - SetRepBuffer(1, 3); - array = {}; - ASSERT_EQ(CborNoError, oc_rep_encoder_create_array( - oc_rep_get_encoder(), &array, CborIndefiniteLength)); - ASSERT_EQ(CborNoError, oc_rep_encode_boolean(&array, true)); - ASSERT_EQ(CborNoError, - oc_rep_encoder_close_container(oc_rep_get_encoder(), &array)); - ASSERT_EQ(3, oc_rep_get_encoded_payload_size()); -} + auto cborEncoder1 = oc_rep_global_encoder_reset(nullptr); -TEST_F(TestRepEncodeWithRealloc, OCRepEncodeMap) -{ - SetRepBuffer(1, 1); - CborEncoder map{}; - CborEncoder inner_map{}; - ASSERT_EQ(CborNoError, oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, - CborIndefiniteLength)); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encoder_create_map(&map, &inner_map, CborIndefiniteLength)); + TestEncoderBuffer cborBuf2{ OC_REP_CRC_ENCODER }; + cborBuf2.SetRepBuffer(1, 1024); + oc_rep_start_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_set_text_string(root, hello, "world"); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - SetRepBuffer(1, 1); - map = {}; - ASSERT_EQ(CborNoError, oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, - CborIndefiniteLength)); - EXPECT_EQ(CborErrorOutOfMemory, - oc_rep_encoder_close_container(oc_rep_get_encoder(), &map)); + int payload_len = oc_rep_get_encoded_payload_size(); + uint64_t crc; + ASSERT_EQ(sizeof(crc), payload_len); + const uint8_t *payload = oc_rep_get_encoder_buf(); + memcpy(&crc, payload, sizeof(crc)); - std::string key = "key"; - SetRepBuffer(1, 7); - map = {}; - ASSERT_EQ(CborNoError, oc_rep_encoder_create_map(oc_rep_get_encoder(), &map, - CborIndefiniteLength)); - ASSERT_EQ(CborNoError, - oc_rep_encode_text_string(&map, key.c_str(), key.length())); - ASSERT_EQ(CborNoError, oc_rep_encode_boolean(&map, true)); - ASSERT_EQ(CborNoError, - oc_rep_encoder_close_container(oc_rep_get_encoder(), &map)); - ASSERT_EQ(7, oc_rep_get_encoded_payload_size()); + oc_rep_global_encoder_reset(&cborEncoder1); + oc_rep_set_uint(root, crc, crc); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); - auto rep = ParsePayload(); - ASSERT_NE(nullptr, rep.get()); - OC_DBG("payload: %s", oc::RepPool::GetJson(rep.get(), true).data()); + auto cbor1Rep = cborBuf1.ParsePayload(); + ASSERT_NE(nullptr, cbor1Rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(cbor1Rep.get(), true).data()); } + +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ diff --git a/api/unittest/repjsontest.cpp b/api/unittest/repjsontest.cpp index b4abbb362d..979ff04337 100644 --- a/api/unittest/repjsontest.cpp +++ b/api/unittest/repjsontest.cpp @@ -1218,8 +1218,6 @@ class TestJsonRepWithServer : public testing::Test { oc_rep_encoder_set_type(OC_REP_CBOR_ENCODER); oc_rep_decoder_set_type(OC_REP_CBOR_DECODER); - - oc_log_set_level(OC_LOG_LEVEL_INFO); } }; diff --git a/api/unittest/reptest.cpp b/api/unittest/reptest.cpp index 9e539e4aa0..d88c6104fa 100644 --- a/api/unittest/reptest.cpp +++ b/api/unittest/reptest.cpp @@ -1047,11 +1047,11 @@ static int oc_rep_encode_tagged_string(CborEncoder *encoder, CborTag tag, const std::string &key, const std::string &value) { - oc_rep_encoder_convert_offset_to_ptr(encoder); + oc_rep_encoder_convert_offset_to_ptr(oc_rep_global_encoder(), encoder); int err = cbor_encode_text_string(encoder, key.c_str(), key.length()); err |= cbor_encode_tag(encoder, tag); err |= cbor_encode_text_string(encoder, value.c_str(), value.length()); - oc_rep_encoder_convert_ptr_to_offset(encoder); + oc_rep_encoder_convert_ptr_to_offset(oc_rep_global_encoder(), encoder); return err; } diff --git a/apps/push_configurator_multithread_linux.c b/apps/push_configurator_multithread_linux.c index 6039f24e23..9fa9c3248c 100644 --- a/apps/push_configurator_multithread_linux.c +++ b/apps/push_configurator_multithread_linux.c @@ -129,66 +129,66 @@ create_notification_selector(void) if (!is_resource_found()) return; - if (oc_init_post(PUSHCONFIG_RESOURCE_PATH, &originserver_ep, - "if=oic.if.create", - &cb_create_notification_selector_response, LOW_QOS, NULL)) { - oc_string_t pushtarget_ep_str; - oc_string_t pushtarget_str; - - oc_rep_begin_root_object(); - - oc_rep_open_array(root, rt); - oc_rep_add_text_string(rt, "oic.r.notificationselector"); - oc_rep_add_text_string(rt, "oic.r.pushproxy"); - oc_rep_close_array(root, rt); - - oc_rep_open_array(root, if); - oc_rep_add_text_string(if, "oic.if.rw"); - oc_rep_add_text_string(if, "oic.if.baseline"); - oc_rep_close_array(root, if); - - oc_rep_open_object(root, p); - oc_rep_set_uint(p, bm, 3); - oc_rep_close_object(root, p); - - /* ----- begin of "rep" ----- */ - oc_rep_open_object(root, rep); - - /* phref (optinal) */ - oc_rep_set_text_string(rep, phref, push_rsc_uri); + if (!oc_init_post(PUSHCONFIG_RESOURCE_PATH, &originserver_ep, + "if=oic.if.create", + &cb_create_notification_selector_response, LOW_QOS, NULL)) { + OC_PRINTF("could not initiate oc_init_post()\n"); + return; + } + oc_rep_begin_root_object(); - /* prt (optinal) */ - oc_rep_open_array(rep, prt); - oc_rep_add_text_string(prt, resource_rt); - oc_rep_close_array(rep, prt); + oc_rep_open_array(root, rt); + oc_rep_add_text_string(rt, "oic.r.notificationselector"); + oc_rep_add_text_string(rt, "oic.r.pushproxy"); + oc_rep_close_array(root, rt); - /* pushtarget */ - oc_endpoint_to_string(&targetserver_ep, &pushtarget_ep_str); - OC_PRINTF("target server's ep: %s \n", oc_string(pushtarget_ep_str)); - oc_concat_strings(&pushtarget_str, oc_string(pushtarget_ep_str), recv_path); - OC_PRINTF("targetpath: %s \n", oc_string(pushtarget_str)); - oc_rep_set_text_string(rep, pushtarget, oc_string(pushtarget_str)); + oc_rep_open_array(root, if); + oc_rep_add_text_string(if, "oic.if.rw"); + oc_rep_add_text_string(if, "oic.if.baseline"); + oc_rep_close_array(root, if); - /* pushqif */ - oc_rep_set_text_string(rep, pushqif, "oic.if.rw"); + oc_rep_open_object(root, p); + oc_rep_set_uint(p, bm, 3); + oc_rep_close_object(root, p); - /* sourcert */ - oc_rep_open_array(rep, sourcert); - oc_rep_add_text_string(sourcert, "oic.r.pushpayload"); - oc_rep_close_array(rep, sourcert); + /* ----- begin of "rep" ----- */ + oc_rep_open_object(root, rep); - /* state */ - /* ----- end of "rep" ----- */ - oc_rep_close_object(root, rep); + /* phref (optinal) */ + oc_rep_set_text_string(rep, phref, push_rsc_uri); - oc_rep_end_root_object(); + /* prt (optinal) */ + oc_rep_open_array(rep, prt); + oc_rep_add_text_string(prt, resource_rt); + oc_rep_close_array(rep, prt); - oc_free_string(&pushtarget_ep_str); - oc_free_string(&pushtarget_str); - } else { - OC_PRINTF("could not initiate oc_init_post()\n"); + /* pushtarget */ + oc_string_t pushtarget_ep_str; + if (oc_endpoint_to_string(&targetserver_ep, &pushtarget_ep_str) != 0) { + OC_PRINTF("error converting target server endpoint to string\n"); return; } + OC_PRINTF("target server's ep: %s \n", oc_string(pushtarget_ep_str)); + oc_string_t pushtarget_str; + oc_concat_strings(&pushtarget_str, oc_string(pushtarget_ep_str), recv_path); + OC_PRINTF("targetpath: %s \n", oc_string(pushtarget_str)); + oc_rep_set_text_string(rep, pushtarget, oc_string(pushtarget_str)); + oc_free_string(&pushtarget_str); + oc_free_string(&pushtarget_ep_str); + + /* pushqif */ + oc_rep_set_text_string(rep, pushqif, "oic.if.rw"); + + /* sourcert */ + oc_rep_open_array(rep, sourcert); + oc_rep_add_text_string(sourcert, "oic.r.pushpayload"); + oc_rep_close_array(rep, sourcert); + + /* state */ + /* ----- end of "rep" ----- */ + oc_rep_close_object(root, rep); + + oc_rep_end_root_object(); if (!oc_do_post()) { OC_PRINTF("oc_do_post() failed\n"); diff --git a/include/oc_rep.h b/include/oc_rep.h index 340b7045ff..c20b244664 100644 --- a/include/oc_rep.h +++ b/include/oc_rep.h @@ -1628,15 +1628,18 @@ typedef enum oc_rep_encoder_type_t { #ifdef OC_JSON_ENCODER OC_REP_JSON_ENCODER = 1, #endif /* OC_JSON_ENCODER */ +#ifdef OC_HAS_FEATURE_CRC_ENCODER + OC_REP_CRC_ENCODER = 2, +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ } oc_rep_encoder_type_t; /** - * @brief Set the encoder type used to encode the response payloads. + * @brief Set the global encoder used to encode the response payloads. * - * @param encoder_type encoder type + * @param type encoder type */ OC_API -void oc_rep_encoder_set_type(oc_rep_encoder_type_t encoder_type); +void oc_rep_encoder_set_type(oc_rep_encoder_type_t type); /** * @brief Get the encoder type used to encode the response payloads. diff --git a/messaging/coap/oscore.c b/messaging/coap/oscore.c index bc135faf71..3d649c2c84 100644 --- a/messaging/coap/oscore.c +++ b/messaging/coap/oscore.c @@ -19,8 +19,8 @@ #ifdef OC_SECURITY #ifdef OC_OSCORE -#include "api/oc_ri_internal.h" #include "api/oc_message_internal.h" +#include "api/oc_ri_internal.h" #include "oscore.h" #include "coap.h" #include "coap_log.h" diff --git a/port/esp32/main/CMakeLists.txt b/port/esp32/main/CMakeLists.txt index 0c6517a4ed..580dbf059f 100644 --- a/port/esp32/main/CMakeLists.txt +++ b/port/esp32/main/CMakeLists.txt @@ -51,6 +51,7 @@ set(sources ${CMAKE_CURRENT_SOURCE_DIR}/../../../api/oc_rep.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../api/oc_rep_decode.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../api/oc_rep_encode.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../api/oc_rep_encode_cbor.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../api/oc_rep_to_json.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../api/oc_resource.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../api/oc_ri.c diff --git a/port/linux/Makefile b/port/linux/Makefile index a3b8216c4c..36f8e00c0f 100644 --- a/port/linux/Makefile +++ b/port/linux/Makefile @@ -56,9 +56,12 @@ COMMON_TEST_SRC_FILES := $(wildcard $(COMMON_TEST_DIR)/*.cpp $(COMMON_TEST_TLS_D COMMON_TEST_OBJ_FILES := $(patsubst $(COMMON_TEST_DIR)/%.cpp,$(COMMON_TEST_OBJ_DIR)/%.o,$(COMMON_TEST_SRC_FILES)) COMMON_TEST_OBJ_FILES := $(patsubst $(COMMON_TEST_TLS_DIR)/%.cpp,$(COMMON_TEST_OBJ_DIR)/%.o, $(COMMON_TEST_OBJ_FILES)) API_TEST_DIR = $(ROOT_DIR)/api/unittest +API_TEST_ENCODER_DIR = $(ROOT_DIR)/api/unittest/encoder API_TEST_OBJ_DIR = $(API_TEST_DIR)/obj -API_TEST_SRC_FILES := $(wildcard $(API_TEST_DIR)/*.cpp) +API_TEST_ENCODER_OBJ_DIR = $(API_TEST_DIR)/encoder/obj +API_TEST_SRC_FILES := $(wildcard $(API_TEST_DIR)/*.cpp $(API_TEST_ENCODER_DIR)/*.cpp) API_TEST_OBJ_FILES := $(patsubst $(API_TEST_DIR)/%.cpp,$(API_TEST_OBJ_DIR)/%.o,$(API_TEST_SRC_FILES)) +API_TEST_OBJ_FILES := $(patsubst $(API_TEST_ENCODER_DIR)/%.cpp,$(API_TEST_ENCODER_OBJ_DIR)/%.o,$(API_TEST_OBJ_FILES)) SECURITY_TEST_DIR = $(ROOT_DIR)/security/unittest SECURITY_TEST_OBJ_DIR = $(SECURITY_TEST_DIR)/obj SECURITY_TEST_SRC_FILES := $(wildcard $(SECURITY_TEST_DIR)/*.cpp) @@ -374,6 +377,10 @@ $(API_TEST_OBJ_DIR)/%.o: $(API_TEST_DIR)/%.cpp @mkdir -p ${@D} $(CXX) $(GTEST_CPPFLAGS) $(TEST_CXXFLAGS) $(EXTRA_CFLAGS) $(HEADER_DIR) -c $< -o $@ +$(API_TEST_ENCODER_OBJ_DIR)/%.o: $(API_TEST_ENCODER_DIR)/%.cpp + @mkdir -p ${@D} + $(CXX) $(GTEST_CPPFLAGS) $(TEST_CXXFLAGS) $(EXTRA_CFLAGS) $(HEADER_DIR) -c $< -o $@ + apitest: $(API_TEST_OBJ_FILES) $(COMMON_TEST_OBJ_FILES) libiotivity-lite-client-server.a | $(GTEST) $(CXX) $^ -o $@ $(GTEST_CPPFLAGS) $(TEST_CXXFLAGS) $(EXTRA_CFLAGS) $(HEADER_DIR) -L$(OUT_DIR) -L$(GTEST_DIR)/make -l:gtest_main.a -liotivity-lite-client-server -lpthread @@ -674,7 +681,7 @@ endif clean: rm -rf obj $(PC) $(CONSTRAINED_LIBS) $(COMMON_TEST_OBJ_FILES) $(API_TEST_OBJ_FILES) $(SECURITY_TEST_OBJ_FILES) $(PLATFORM_TEST_OBJ_FILES) $(MESSAGING_TEST_OBJ_FILES) $(UNIT_TESTS) $(STORAGE_TEST_DIR) $(CLOUD_TEST_OBJ_FILES) $(CLOUD_TEST_STORAGE_DIR) $(RD_CLIENT_TEST_OBJ_FILES) - rm -rf $(COMMON_TEST_OBJ_DIR)/*.gcda $(COMMON_TEST_TLS_OBJ_DIR)/*.gcda $(API_TEST_OBJ_DIR)/*.gcda $(SECURITY_TEST_OBJ_DIR)/*.gcda $(PLATFORM_TEST_OBJ_DIR)/*.gcda $(MESSAGING_TEST_OBJ_DIR)/*.gcda + rm -rf $(COMMON_TEST_OBJ_DIR)/*.gcda $(COMMON_TEST_TLS_OBJ_DIR)/*.gcda $(API_TEST_OBJ_DIR)/*.gcda $(API_TEST_ENCODER_OBJ_DIR)/*.gcda $(SECURITY_TEST_OBJ_DIR)/*.gcda $(PLATFORM_TEST_OBJ_DIR)/*.gcda $(MESSAGING_TEST_OBJ_DIR)/*.gcda rm -rf pki_certs smart_home_server_linux_IDD.cbor server_certification_tests_IDD.cbor client_certification_tests_IDD.cbor server_rules_IDD.cbor cloud_proxy_IDD.cbor cleanall: clean diff --git a/tools/test_float16.c b/tools/test_float16.c new file mode 100644 index 0000000000..cdfbfa0fa8 --- /dev/null +++ b/tools/test_float16.c @@ -0,0 +1,10 @@ +#include +#include + +int +main() +{ + _Float16 f = 0.0; + printf("f16 = %f\n", (double)f); + return 0; +} diff --git a/util/oc_crc.c b/util/oc_crc.c index 8037f87482..38d7320fdb 100644 --- a/util/oc_crc.c +++ b/util/oc_crc.c @@ -18,7 +18,7 @@ #include "util/oc_features.h" -#ifdef OC_HAS_FEATURE_CRC64 +#ifdef OC_HAS_FEATURE_CRC_ENCODER #include "util/oc_crc_internal.h" @@ -43,13 +43,12 @@ crc64_update(uint64_t crc, uint8_t byte) } uint64_t -oc_crc64(const uint8_t *buffer, size_t size) +oc_crc64(uint64_t crc, const uint8_t *buffer, size_t size) { - uint64_t crc = 0; for (size_t i = 0; i < size; i++) { crc = crc64_update(crc, buffer[i]); } return crc; } -#endif /* OC_HAS_FEATURE_CRC64 */ +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ diff --git a/util/oc_crc_internal.h b/util/oc_crc_internal.h index 440994b5d1..1d427021df 100644 --- a/util/oc_crc_internal.h +++ b/util/oc_crc_internal.h @@ -21,7 +21,7 @@ #include "util/oc_features.h" -#ifdef OC_HAS_FEATURE_CRC64 +#ifdef OC_HAS_FEATURE_CRC_ENCODER #include "util/oc_compiler.h" #include @@ -34,17 +34,19 @@ extern "C" { /** * @brief Calculate CRC64 for a buffer of data. * - * @param buffer The buffer of data to calculate CRC64 for (cannot be NULL); + * @param crc The initial CRC64 value (use 0 to start a new CRC64 calculation). + * @param buffer The buffer of data to calculate CRC64 for (cannot be NULL). * @param size The size of the buffer of data to calculate CRC64 for. * * @return The CRC64 value. */ -uint64_t oc_crc64(const uint8_t *buffer, size_t size) OC_NONNULL(); +uint64_t oc_crc64(uint64_t crc, const uint8_t *buffer, size_t size) + OC_NONNULL(); #ifdef __cplusplus } #endif -#endif /* OC_HAS_FEATURE_CRC64 */ +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ #endif /* OC_CRC_INTERNAL_H */ diff --git a/util/oc_features.h b/util/oc_features.h index 17eea4b858..62100c55a3 100644 --- a/util/oc_features.h +++ b/util/oc_features.h @@ -63,7 +63,7 @@ #endif /* OC_ETAG && OC_SERVER */ #ifdef OC_HAS_FEATURE_ETAG -#define OC_HAS_FEATURE_CRC64 +#define OC_HAS_FEATURE_CRC_ENCODER #endif /* OC_HAS_FEATURE_ETAG */ #endif /* OC_FEATURES_H */ diff --git a/util/unittest/crc64test.cpp b/util/unittest/crc64test.cpp index bdbe7fea09..6f2d811293 100644 --- a/util/unittest/crc64test.cpp +++ b/util/unittest/crc64test.cpp @@ -44,7 +44,7 @@ TEST(TestCRC, CRC64) for (auto &input : inputs) { EXPECT_EQ(input.crc, - oc_crc64((uint8_t *)&input.input[0], input.input.size())); + oc_crc64(0, (uint8_t *)&input.input[0], input.input.size())); } }