From 7fc87d9e2cebfad3a2937dc30da0cca1ed019a64 Mon Sep 17 00:00:00 2001 From: Daniel Adam Date: Fri, 13 Oct 2023 13:01:52 +0200 Subject: [PATCH] fixup! CRC64 Encoder --- api/cloud/unittest/cloud_manager_test.cpp | 1 + api/oc_client_api.c | 196 +++-- api/oc_rep.c | 9 +- api/oc_rep_encode.c | 776 +++++++++++------- api/oc_rep_encode_cbor.c | 27 + api/oc_rep_encode_cbor_internal.h | 51 ++ api/oc_rep_encode_crc.c | 6 +- api/oc_rep_encode_crc_internal.h | 2 +- api/oc_rep_encode_internal.h | 145 +++- api/oc_rep_encode_json.c | 18 +- api/oc_rep_encode_json_internal.h | 4 +- api/oc_runtime.c | 1 + ...{TestEncoder.cpp => TestEncoderBuffer.cpp} | 58 +- .../{TestEncoder.h => TestEncoderBuffer.h} | 33 +- api/unittest/etagtest.cpp | 54 +- api/unittest/repencodecbortest.cpp | 12 +- api/unittest/repencodecrctest.cpp | 20 +- api/unittest/repencodejsontest.cpp | 12 +- api/unittest/repencodetest.cpp | 231 ++++++ api/unittest/repjsontest.cpp | 2 - api/unittest/reptest.cpp | 4 +- apps/push_configurator_multithread_linux.c | 102 +-- port/esp32/main/CMakeLists.txt | 1 + 23 files changed, 1215 insertions(+), 550 deletions(-) create mode 100644 api/oc_rep_encode_cbor.c create mode 100644 api/oc_rep_encode_cbor_internal.h rename api/unittest/encoder/{TestEncoder.cpp => TestEncoderBuffer.cpp} (61%) rename api/unittest/encoder/{TestEncoder.h => TestEncoderBuffer.h} (60%) create mode 100644 api/unittest/repencodetest.cpp 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..1efec95ebd 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) { + int cf = oc_rep_encoder_get_content_format(); + if (cf == -1) { + 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, (oc_content_format_t)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); } + int cf = oc_rep_encoder_get_content_format(); + if (cf == -1) { + 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, (oc_content_format_t)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()); + int cf = oc_rep_encoder_get_content_format(); + if (cf == -1) { + goto do_multicast_update_error; } + coap_options_set_content_format(&g_request.packet, (oc_content_format_t)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_encode.c b/api/oc_rep_encode.c index 029cdafc5e..fa1f3a03d9 100644 --- a/api/oc_rep_encode.c +++ b/api/oc_rep_encode.c @@ -16,6 +16,7 @@ * ****************************************************************************/ +#include "api/oc_rep_encode_cbor_internal.h" #include "api/oc_rep_encode_internal.h" #include "oc_rep.h" #include "port/oc_log_internal.h" @@ -34,145 +35,170 @@ #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; - -static 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, \ - \ - .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, \ +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 = g_rep_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 -rep_buffer_realloc(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_init(oc_rep_encoder_t *encoder, oc_rep_encoder_buffer_t buffer, + oc_rep_encoder_type_t encoder_type) { if (encoder_type == OC_REP_CBOR_ENCODER) { - g_rep_encoder = oc_rep_cbor_encoder(); + encoder->type = OC_REP_CBOR_ENCODER; + encoder->impl = oc_rep_cbor_encoder(); + encoder->buffer = buffer; + rep_cbor_context_init(encoder, encoder->buffer.size); return; } #ifdef OC_JSON_ENCODER if (encoder_type == OC_REP_JSON_ENCODER) { - g_rep_encoder = oc_rep_json_encoder(); + encoder->type = OC_REP_JSON_ENCODER; + encoder->impl = oc_rep_json_encoder(); + encoder->buffer = buffer; + rep_cbor_context_init(encoder, encoder->buffer.size); return; } #endif /* OC_JSON_ENCODER */ #ifdef OC_HAS_FEATURE_CRC_ENCODER if (encoder_type == OC_REP_CRC_ENCODER) { - g_rep_encoder = oc_rep_crc_encoder(); + encoder->type = OC_REP_CRC_ENCODER; + encoder->impl = oc_rep_crc_encoder(); + encoder->buffer = buffer; + rep_cbor_context_init(encoder, encoder->buffer.size); return; } #endif /* OC_HAS_FEATURE_CRC_ENCODER */ } +void +oc_rep_encoder_set_type(oc_rep_encoder_type_t encoder_type) +{ + oc_rep_encoder_init(&g_rep_encoder, g_rep_encoder.buffer, encoder_type); +} + oc_rep_encoder_type_t oc_rep_encoder_get_type(void) { @@ -196,7 +222,7 @@ oc_rep_encoder_set_type_by_accept(oc_content_format_t accept) return false; } -oc_content_format_t +int oc_rep_encoder_get_content_format(void) { #ifdef OC_JSON_ENCODER @@ -204,92 +230,109 @@ oc_rep_encoder_get_content_format(void) return APPLICATION_JSON; } #endif /* OC_JSON_ENCODER */ +#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 -1; + } +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ + return APPLICATION_VND_OCF_CBOR; } -void -oc_rep_buffer_init(uint8_t *buffer, size_t size) +oc_rep_encoder_reset_t +oc_rep_global_encoder_reset(const oc_rep_encoder_reset_t *reset) { - 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); -} + oc_rep_encoder_reset_t prev = { + .encoder = g_rep_encoder, + }; + prev.root_map_ctx = root_map; + prev.links_array_ctx = links_array; -#ifdef OC_DYNAMIC_ALLOCATION -void -oc_rep_buffer_realloc_init(uint8_t **buffer, size_t size, size_t max_size) -{ - 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); + 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 = g_rep_encoder.get_buffer_size(&g_encoder, g_rep_buffer.buffer); - size_t needed = g_rep_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)", @@ -302,410 +345,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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 = - rep_buffer_realloc(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 = rep_buffer_realloc(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 = rep_buffer_realloc(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 index da241f74da..583198401a 100644 --- a/api/oc_rep_encode_crc.c +++ b/api/oc_rep_encode_crc.c @@ -192,12 +192,10 @@ rep_crc_encoder_close_container(CborEncoder *encoder, return rep_crc_append_to_buffer(encoder, type, &close_byte, 1); } -oc_rep_encoder_t +oc_rep_encoder_implementation_t oc_rep_crc_encoder(void) { - return (oc_rep_encoder_t){ - .type = OC_REP_CRC_ENCODER, - + return (oc_rep_encoder_implementation_t){ .get_buffer_size = &rep_crc_get_buffer_size, .get_extra_bytes_needed = &rep_crc_get_extra_bytes_needed, diff --git a/api/oc_rep_encode_crc_internal.h b/api/oc_rep_encode_crc_internal.h index 399a577f89..443c2aca43 100644 --- a/api/oc_rep_encode_crc_internal.h +++ b/api/oc_rep_encode_crc_internal.h @@ -36,7 +36,7 @@ extern "C" { #define OC_CRC_CLOSE_CONTAINER (0x1) /** Return an initialized CRC encoder. */ -oc_rep_encoder_t oc_rep_crc_encoder(void); +oc_rep_encoder_implementation_t oc_rep_crc_encoder(void); #ifdef __cplusplus } diff --git a/api/oc_rep_encode_internal.h b/api/oc_rep_encode_internal.h index 609bcba528..503eb22557 100644 --- a/api/oc_rep_encode_internal.h +++ b/api/oc_rep_encode_internal.h @@ -32,6 +32,18 @@ extern "C" { #endif +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(); @@ -76,10 +88,8 @@ 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; @@ -94,10 +104,34 @@ 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); + +/** Initialize encoder object. */ +void oc_rep_encoder_init(oc_rep_encoder_t *encoder, + oc_rep_encoder_buffer_t buffer, + oc_rep_encoder_type_t encoder_type) OC_NONNULL(); /** * @brief Initialize global encoder buffer. @@ -105,13 +139,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. @@ -119,23 +157,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 @@ -146,8 +199,72 @@ 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 */ +int oc_rep_encoder_get_content_format(void); + +/** @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 83a4d10cd0..56964afe5e 100644 --- a/api/oc_rep_encode_json.c +++ b/api/oc_rep_encode_json.c @@ -56,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.bytes_needed += (ptrdiff_t)n; - return; - } - encoder->data.ptr += n; -} - static CborError rep_json_append_to_buffer(CborEncoder *encoder, const void *data, size_t len) { @@ -76,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; } @@ -328,12 +318,10 @@ 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, 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_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/TestEncoder.cpp b/api/unittest/encoder/TestEncoderBuffer.cpp similarity index 61% rename from api/unittest/encoder/TestEncoder.cpp rename to api/unittest/encoder/TestEncoderBuffer.cpp index 1d03ff9a19..1a45ac855e 100644 --- a/api/unittest/encoder/TestEncoder.cpp +++ b/api/unittest/encoder/TestEncoderBuffer.cpp @@ -16,40 +16,66 @@ * ******************************************************************/ -#include "TestEncoder.h" +#include "TestEncoderBuffer.h" #include "oc_rep.h" #include "port/oc_log_internal.h" #include -oc_rep_encoder_type_t const TestEncoder::default_encoder = +oc_rep_encoder_type_t TestEncoderBuffer::default_encoder = oc_rep_encoder_get_type(); -oc_rep_decoder_type_t const TestEncoder::default_decoder = +oc_rep_decoder_type_t TestEncoderBuffer::default_decoder = oc_rep_decoder_get_type(); -TestEncoder::TestEncoder(oc_rep_encoder_type_t encoder_type, - std::optional decoder_type) - : has_decoder_(decoder_type.has_value()) +TestEncoderBuffer::TestEncoderBuffer(oc_rep_encoder_type_t encoder_type) + : encoder_type_(encoder_type) { oc_rep_encoder_set_type(encoder_type); - if (decoder_type.has_value()) { - oc_rep_decoder_set_type(*decoder_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 */ } -TestEncoder::~TestEncoder() +TestEncoderBuffer::~TestEncoderBuffer() { #ifdef OC_DYNAMIC_ALLOCATION free(buffer_); - buffer_ = nullptr; #endif /* OC_DYNAMIC_ALLOCATION */ +} + +bool +TestEncoderBuffer::HasDecoder() const +{ + return encoder_type_ == OC_REP_CBOR_ENCODER +#ifdef OC_JSON_ENCODER + || encoder_type_ == OC_REP_JSON_ENCODER +#endif /* OC_JSON_ENCODER */ + ; +} + +void +TestEncoderBuffer::RestoreDefaults() +{ oc_rep_encoder_set_type(default_encoder); oc_rep_decoder_set_type(default_decoder); } void -TestEncoder::SetRepBuffer(size_t size, size_t max_size) +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_); @@ -63,21 +89,19 @@ TestEncoder::SetRepBuffer(size_t size, size_t max_size) (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)); + 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 -TestEncoder::Shrink() +TestEncoderBuffer::Shrink() { -#ifdef OC_DYNAMIC_ALLOCATION buffer_ = oc_rep_shrink_encoder_buf(buffer_); -#endif /* OC_DYNAMIC_ALLOCATION */ } oc::oc_rep_unique_ptr -TestEncoder::ParsePayload() +TestEncoderBuffer::ParsePayload() { if (!HasDecoder()) { return oc::oc_rep_unique_ptr(nullptr, &oc_free_rep); diff --git a/api/unittest/encoder/TestEncoder.h b/api/unittest/encoder/TestEncoderBuffer.h similarity index 60% rename from api/unittest/encoder/TestEncoder.h rename to api/unittest/encoder/TestEncoderBuffer.h index 9d5261ed3f..8f79595a4e 100644 --- a/api/unittest/encoder/TestEncoder.h +++ b/api/unittest/encoder/TestEncoderBuffer.h @@ -19,21 +19,29 @@ #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 TestEncoder { +class TestEncoderBuffer { public: - TestEncoder(oc_rep_encoder_type_t encoder_type, - std::optional decoder_type = {}); - ~TestEncoder(); + explicit TestEncoderBuffer(oc_rep_encoder_type_t encoder_type); + ~TestEncoderBuffer(); - bool HasDecoder() const { return has_decoder_; } + TestEncoderBuffer(TestEncoderBuffer &other) = delete; + TestEncoderBuffer &operator=(TestEncoderBuffer &other) = delete; + TestEncoderBuffer(TestEncoderBuffer &&other) = delete; + TestEncoderBuffer &operator=(TestEncoderBuffer &&other) = delete; + + static void RestoreDefaults(); + static void StoreDefaults(); + + bool HasDecoder() const; /* buffer for oc_rep_t */ void SetRepBuffer(size_t size = 1024, size_t max_size = 1024); @@ -43,19 +51,20 @@ class TestEncoder { oc::oc_rep_unique_ptr ParsePayload(); private: - static const oc_rep_encoder_type_t default_encoder; - static const oc_rep_decoder_type_t default_decoder; + static oc_rep_encoder_type_t default_encoder; + static oc_rep_decoder_type_t default_decoder; - bool has_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_{}; - char rep_objects_alloc_[OC_MAX_NUM_REP_OBJECTS]{}; - oc_rep_t rep_objects_pool_[OC_MAX_NUM_REP_OBJECTS]{}; + 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_, rep_objects_pool_, nullptr }; + rep_objects_alloc_.data(), rep_objects_pool_.data(), + nullptr }; #endif /* OC_DYNAMIC_ALLOCATION */ }; diff --git a/api/unittest/etagtest.cpp b/api/unittest/etagtest.cpp index 6eb3eb94f3..c49d6546a7 100644 --- a/api/unittest/etagtest.cpp +++ b/api/unittest/etagtest.cpp @@ -876,43 +876,47 @@ TEST_F(TestETagWithServer, GetCRC64Collection) #endif // OC_SERVER && OC_COLLECTIONS -TEST_F(TestETagWithServer, GetCRC64AllResources) +using CheckSumMap = std::map>; + +static bool +storeChecksums(oc_resource_t *resource, void *data) { - auto store_checksums = [](oc_resource_t *resource, void *data) { - auto uri = std::string(oc_string(resource->uri)); - if (uri == OC_INTROSPECTION_WK_URI || uri == OC_INTROSPECTION_DATA_URI || - uri == OCF_RES_URI) { - return true; - } + auto uri = std::string(oc_string(resource->uri)); + if (uri == OC_INTROSPECTION_WK_URI || uri == OC_INTROSPECTION_DATA_URI || + uri == OCF_RES_URI) { + return true; + } #ifdef OC_WKCORE - if (uri == "/.well-known/core") { - return true; - } + if (uri == "/.well-known/core") { + return true; + } #endif // OC_WKCORE #ifdef OC_SECURITY - if (uri == OCF_SEC_CSR_URI) { - return true; - } + if (uri == OCF_SEC_CSR_URI) { + return true; + } #endif // OC_SECURITY - auto &checksums = *static_cast *>(data); - uint64_t crc64 = 0; - if (!oc_resource_get_crc64(resource, &crc64)) { - throw std::string("failed to get crc64 for resource(") + uri + ")"; - } - checksums[uri] = crc64; - return true; - }; + auto &checksums = *static_cast(data); + uint64_t crc64 = 0; + if (!oc_resource_get_crc64(resource, &crc64)) { + throw std::string("failed to get crc64 for resource(") + uri + ")"; + } + checksums[uri] = crc64; + return true; +} +TEST_F(TestETagWithServer, GetCRC64AllResources) +{ // iterate all resources -> store to map[uri]checksum - std::map> checksums_1{}; - oc_resources_iterate(kDeviceID1, true, true, true, true, store_checksums, + CheckSumMap checksums_1{}; + oc_resources_iterate(kDeviceID1, true, true, true, true, storeChecksums, &checksums_1); ASSERT_FALSE(checksums_1.empty()); // iterate all resources for the second time - std::map> checksums_2{}; - oc_resources_iterate(kDeviceID1, true, true, true, true, store_checksums, + CheckSumMap checksums_2{}; + oc_resources_iterate(kDeviceID1, true, true, true, true, storeChecksums, &checksums_2); ASSERT_FALSE(checksums_2.empty()); diff --git a/api/unittest/repencodecbortest.cpp b/api/unittest/repencodecbortest.cpp index 513902ee8c..2f26090410 100644 --- a/api/unittest/repencodecbortest.cpp +++ b/api/unittest/repencodecbortest.cpp @@ -16,7 +16,7 @@ * ******************************************************************/ -#include "encoder/TestEncoder.h" +#include "encoder/TestEncoderBuffer.h" #include "api/oc_rep_encode_internal.h" #include "api/oc_rep_decode_internal.h" @@ -35,14 +35,16 @@ class TestCborRepEncodeWithRealloc : public testing::Test { public: static void SetUpTestCase() { + TestEncoderBuffer::StoreDefaults(); TestCborRepEncodeWithRealloc::encoder = - std::make_unique(OC_REP_CBOR_ENCODER, OC_REP_CBOR_DECODER); + 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) @@ -57,10 +59,12 @@ class TestCborRepEncodeWithRealloc : public testing::Test { static void Shrink() { TestCborRepEncodeWithRealloc::encoder->Shrink(); } - static std::unique_ptr encoder; + static std::unique_ptr encoder; }; -std::unique_ptr TestCborRepEncodeWithRealloc::encoder{ nullptr }; +std::unique_ptr TestCborRepEncodeWithRealloc::encoder{ + nullptr +}; TEST_F(TestCborRepEncodeWithRealloc, EncodeRaw) { diff --git a/api/unittest/repencodecrctest.cpp b/api/unittest/repencodecrctest.cpp index 1c47d31123..e96ceade28 100644 --- a/api/unittest/repencodecrctest.cpp +++ b/api/unittest/repencodecrctest.cpp @@ -20,7 +20,7 @@ #ifdef OC_HAS_FEATURE_CRC_ENCODER -#include "encoder/TestEncoder.h" +#include "encoder/TestEncoderBuffer.h" #include "api/oc_rep_encode_crc_internal.h" #include "oc_rep.h" @@ -32,19 +32,22 @@ #include #include #include +#include class TestCrcRepEncodeWithRealloc : public testing::Test { public: static void SetUpTestCase() { + TestEncoderBuffer::StoreDefaults(); TestCrcRepEncodeWithRealloc::encoder = - std::make_unique(OC_REP_CRC_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) @@ -66,10 +69,12 @@ class TestCrcRepEncodeWithRealloc : public testing::Test { return crc; } - static std::unique_ptr encoder; + static std::unique_ptr encoder; }; -std::unique_ptr TestCrcRepEncodeWithRealloc::encoder{ nullptr }; +std::unique_ptr TestCrcRepEncodeWithRealloc::encoder{ + nullptr +}; static uint64_t calculateCrc(uint64_t crc, CborType type, const uint8_t *buffer, size_t size) @@ -103,19 +108,16 @@ TEST_F(TestCrcRepEncodeWithRealloc, EncodeBool) 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()); - ASSERT_EQ(8, oc_rep_get_encoded_payload_size()); - uint64_t expCrc = 0; - for (size_t i = 0; i < crcData.size(); ++i) { - expCrc = calculateCrc(expCrc, CborBooleanType, &crcData[i], 1); - } EXPECT_EQ(expCrc, *crc); } diff --git a/api/unittest/repencodejsontest.cpp b/api/unittest/repencodejsontest.cpp index b47202fc47..bc5462bbf2 100644 --- a/api/unittest/repencodejsontest.cpp +++ b/api/unittest/repencodejsontest.cpp @@ -20,7 +20,7 @@ #ifdef OC_JSON_ENCODER -#include "encoder/TestEncoder.h" +#include "encoder/TestEncoderBuffer.h" #include "api/oc_rep_encode_internal.h" #include "api/oc_rep_encode_json_internal.h" @@ -40,14 +40,16 @@ class TestJsonRepEncodeWithRealloc : public testing::Test { public: static void SetUpTestCase() { + TestEncoderBuffer::StoreDefaults(); TestJsonRepEncodeWithRealloc::encoder = - std::make_unique(OC_REP_JSON_ENCODER, OC_REP_JSON_DECODER); + std::make_unique(OC_REP_JSON_ENCODER); ASSERT_EQ(OC_REP_JSON_ENCODER, oc_rep_encoder_get_type()); } static void TearDownTestCase() { TestJsonRepEncodeWithRealloc::encoder.reset(); + TestEncoderBuffer::RestoreDefaults(); } static void SetRepBuffer(size_t size = 1024, size_t max_size = 1024) @@ -62,10 +64,12 @@ class TestJsonRepEncodeWithRealloc : public testing::Test { static void Shrink() { TestJsonRepEncodeWithRealloc::encoder->Shrink(); } - static std::unique_ptr encoder; + static std::unique_ptr encoder; }; -std::unique_ptr TestJsonRepEncodeWithRealloc::encoder{ nullptr }; +std::unique_ptr TestJsonRepEncodeWithRealloc::encoder{ + nullptr +}; TEST_F(TestJsonRepEncodeWithRealloc, EncodeRaw) { diff --git a/api/unittest/repencodetest.cpp b/api/unittest/repencodetest.cpp new file mode 100644 index 0000000000..c2319aefe4 --- /dev/null +++ b/api/unittest/repencodetest.cpp @@ -0,0 +1,231 @@ +/****************************************************************** + * + * 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 "oc_buffer_settings.h" +#include "port/oc_log_internal.h" +#include "util/oc_features.h" +#include "tests/gtest/RepPool.h" + +#include +#include +#include + +class TestRepEncode : public testing::Test { +public: + static void SetUpTestCase() + { + // TODO: rm + oc_log_set_level(OC_LOG_LEVEL_DEBUG); + + TestEncoderBuffer::StoreDefaults(); + } + + static void TearDownTestCase() + { + // TODO: rm + oc_log_set_level(OC_LOG_LEVEL_INFO); + } + + void TearDown() override { TestEncoderBuffer::RestoreDefaults(); } +}; + +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; + } + 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_rep_encoder_set_type(OC_REP_CBOR_ENCODER); + EXPECT_EQ(APPLICATION_VND_OCF_CBOR, oc_rep_encoder_get_content_format()); +#ifdef OC_JSON_ENCODER + oc_rep_encoder_set_type(OC_REP_JSON_ENCODER); + EXPECT_EQ(APPLICATION_JSON, oc_rep_encoder_get_content_format()); +#endif /* OC_JSON_ENCODER */ +#ifdef OC_HAS_FEATURE_CRC_ENCODER + oc_rep_encoder_set_type(OC_REP_CRC_ENCODER); + EXPECT_EQ(-1, oc_rep_encoder_get_content_format()); +#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)); + +#ifdef OC_DYNAMIC_ALLOCATION + // with enabled realloc + uint8_t *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 */ + + memset(oc_rep_global_encoder(), 0, sizeof(oc_rep_encoder_t)); +} + +#ifdef OC_DYNAMIC_ALLOCATION + +TEST_F(TestRepEncode, ShrinkBuffer_Fail) +{ + oc_rep_encoder_t encoder{}; + // buffer.enable_realloc == false; + EXPECT_FALSE(oc_rep_encoder_shrink_buffer(&encoder)); + + // buffer.pptr == nullptr + encoder.buffer.enable_realloc = true; + 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; + uint8_t *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; + oc_rep_encoder_init(&encoder, eb, OC_REP_CBOR_ENCODER); + 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; + uint8_t *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_init(&encoder, eb, OC_REP_CBOR_ENCODER); + + 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; + oc_rep_encoder_init(&encoder, eb, OC_REP_CBOR_ENCODER); + ASSERT_EQ(CborNoError, + oc_rep_encoder_write_raw(&encoder, rawData.data(), rawData.size())); + + oc_rep_encoder_init(&encoder, eb, OC_REP_CBOR_ENCODER); + 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(TestRepEncode, MultipleCBorEncoders) +{ + 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()); + + 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()); + 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 cbor2Rep = cborBuf2.ParsePayload(); + ASSERT_NE(nullptr, cbor2Rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(cbor2Rep.get(), true).data()); + + 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()); + + auto cbor1Rep = cborBuf1.ParsePayload(); + ASSERT_NE(nullptr, cbor1Rep.get()); + OC_DBG("payload: %s", oc::RepPool::GetJson(cbor1Rep.get(), true).data()); +} + +#ifdef OC_JSON_ENCODER + +TEST_F(TestRepEncode, LocalJsonEncoder) +{ + // TODO +} + +#endif /* OC_JSON_ENCODER */ + +#ifdef OC_HAS_FEATURE_CRC_ENCODER + +TEST_F(TestRepEncode, LocalCrcEncoder) +{ + // TODO +} + +#endif /* OC_HAS_FEATURE_CRC_ENCODER */ \ No newline at end of file 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/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