diff --git a/lib/cmp_chunk.h b/lib/cmp_chunk.h index 82db9d08c5ec3349661ff7058f4567be1a58dca2..a61787ebb56dc5e01e93824da2e47e4a8061afd3 100644 --- a/lib/cmp_chunk.h +++ b/lib/cmp_chunk.h @@ -24,6 +24,11 @@ #include "common/cmp_entity.h" #include "common/cmp_error_list.h" +/* valid specific compression parameter ranges for chunk compression + * (every parameter except cmp_mode, model_value, lossy_par) + */ +#define MIN_CHUNK_CMP_PAR 1U +#define MAX_CHUNK_CMP_PAR UINT16_MAX /* the compression entity does not allow larger values */ #define ROUND_UP_TO_4(x) ((((x)+3)/4)*4) diff --git a/lib/common/cmp_error.c b/lib/common/cmp_error.c index 2a78dd6ab7251955e875755a8d1efacfa0f4b4c1..7e8caf562e8999d956010af61724d346ec494b3b 100644 --- a/lib/common/cmp_error.c +++ b/lib/common/cmp_error.c @@ -88,6 +88,8 @@ const char* cmp_get_error_string(enum cmp_error code) return "Buffer related parameter is not valid"; case CMP_ERROR_PAR_NULL: return "Pointer to the compression parameters structure is NULL"; + case CMP_ERROR_PAR_NO_MODEL: + return "Model need for model mode compression"; case CMP_ERROR_CHUNK_NULL: return "Pointer to the chunk is NULL. No data, no compression"; diff --git a/lib/common/cmp_error_list.h b/lib/common/cmp_error_list.h index 06fa16875123f77443daa6cb3c9e6625c6f5b1b4..94476c9455701071c3c68feb01ab9a0aa912ae78 100644 --- a/lib/common/cmp_error_list.h +++ b/lib/common/cmp_error_list.h @@ -35,6 +35,7 @@ enum cmp_error { CMP_ERROR_PAR_SPECIFIC = 21, CMP_ERROR_PAR_BUFFERS = 22, CMP_ERROR_PAR_NULL = 24, + CMP_ERROR_PAR_NO_MODEL = 25, /* chunk errors */ CMP_ERROR_CHUNK_NULL = 40, CMP_ERROR_CHUNK_TOO_LARGE = 41, diff --git a/lib/common/cmp_support.c b/lib/common/cmp_support.c index a4362e69c17362ba873b4ac802c7840fbf278948..357ae544b945bde352c202410ecd067f15b4f95b 100644 --- a/lib/common/cmp_support.c +++ b/lib/common/cmp_support.c @@ -399,79 +399,6 @@ int cmp_cfg_gen_par_is_invalid(const struct cmp_cfg *cfg) } -/** - * @brief check if the ICU buffer parameters are invalid - * - * @param cfg pointer to the compressor configuration - * - * @returns 0 if the buffer parameters are valid, otherwise invalid - */ - -int cmp_cfg_icu_buffers_is_invalid(const struct cmp_cfg *cfg) -{ - int cfg_invalid = 0; - - if (!cfg) - return 1; - - if (cfg->src == NULL) { - debug_print("Error: The data_to_compress buffer for the data to be compressed is NULL."); - cfg_invalid++; - } - - if (cfg->samples == 0) - debug_print("Warning: The samples parameter is 0. No data are compressed. This behavior may not be intended."); - - if (cfg->dst) { - if (cfg->stream_size == 0 && cfg->samples != 0) { - debug_print("Error: The buffer_length is set to 0. There is no space to store the compressed data."); - cfg_invalid++; - } - - if (raw_mode_is_used(cfg->cmp_mode) && cfg->stream_size < cfg->samples) { - debug_print("Error: The compressed_data_len_samples is to small to hold the data form the data_to_compress."); - cfg_invalid++; - } - - if (cfg->dst == cfg->src) { - debug_print("Error: The compressed_data buffer is the same as the data_to_compress buffer."); - cfg_invalid++; - } - } - - if (model_mode_is_used(cfg->cmp_mode)) { - if (cfg->model_buf == NULL) { - debug_print("Error: The model_of_data buffer for the model data is NULL."); - cfg_invalid++; - } - - if (cfg->model_buf == cfg->src) { - debug_print("Error: The model_of_data buffer is the same as the data_to_compress buffer."); - cfg_invalid++; - } - - if (cfg->model_buf == cfg->dst) { - debug_print("Error: The model_of_data buffer is the same as the compressed_data buffer."); - cfg_invalid++; - } - - if (cfg->updated_model_buf) { - if (cfg->updated_model_buf == cfg->src) { - debug_print("Error: The updated_model buffer is the same as the data_to_compress buffer."); - cfg_invalid++; - } - - if (cfg->updated_model_buf == cfg->dst) { - debug_print("Error: The compressed_data buffer is the same as the compressed_data buffer."); - cfg_invalid++; - } - } - } - - return cfg_invalid; -} - - /** * @brief check if the combination of the different compression parameters is invalid * @@ -735,38 +662,6 @@ int cmp_cfg_aux_is_invalid(const struct cmp_cfg *cfg) } -/** - * @brief check if a compression configuration is invalid for a ICU compression - * - * @param cfg pointer to a compressor configuration - * - * @returns 0 if the compression configuration is valid, otherwise invalid - */ - -int cmp_cfg_icu_is_invalid(const struct cmp_cfg *cfg) -{ - int cfg_invalid = 0; - - if (!cfg) - return 1; - - cfg_invalid += cmp_cfg_gen_par_is_invalid(cfg); - - cfg_invalid += cmp_cfg_icu_buffers_is_invalid(cfg); - - if (cmp_imagette_data_type_is_used(cfg->data_type)) - cfg_invalid += cmp_cfg_imagette_is_invalid(cfg); - else if (cmp_fx_cob_data_type_is_used(cfg->data_type)) - cfg_invalid += cmp_cfg_fx_cob_is_invalid(cfg); - else if (cmp_aux_data_type_is_used(cfg->data_type)) - cfg_invalid += cmp_cfg_aux_is_invalid(cfg); - else - cfg_invalid++; - - return cfg_invalid; -} - - /** * @brief print the cmp_info structure * diff --git a/lib/common/cmp_support.h b/lib/common/cmp_support.h index cc5232afcf7f413ad498686784b2227ed7c06173..14c77a89dc6c51bb04817871e1c4fd15cf1ec054 100644 --- a/lib/common/cmp_support.h +++ b/lib/common/cmp_support.h @@ -331,9 +331,7 @@ int is_a_pow_of_2(unsigned int v); unsigned int ilog_2(uint32_t x); unsigned int cmp_bit_to_byte(unsigned int cmp_size_bit); -int cmp_cfg_icu_is_invalid(const struct cmp_cfg *cfg); int cmp_cfg_gen_par_is_invalid(const struct cmp_cfg *cfg); -int cmp_cfg_icu_buffers_is_invalid(const struct cmp_cfg *cfg); int cmp_cfg_imagette_is_invalid(const struct cmp_cfg *cfg); int cmp_cfg_fx_cob_is_invalid(const struct cmp_cfg *cfg); int cmp_cfg_aux_is_invalid(const struct cmp_cfg *cfg); diff --git a/lib/icu_compress/cmp_icu.c b/lib/icu_compress/cmp_icu.c index 45791ee565469c3c47d3e8f5032a9d69dcf63292..82e8160d34d18700ab9fe56d22cf2d10355fb5c6 100644 --- a/lib/icu_compress/cmp_icu.c +++ b/lib/icu_compress/cmp_icu.c @@ -137,7 +137,7 @@ static uint32_t map_to_pos(uint32_t value_to_map, unsigned int max_data_bits) */ static uint32_t put_n_bits32(uint32_t value, unsigned int n_bits, uint32_t bit_offset, - uint32_t *bitstream_adr, unsigned int max_stream_len) + uint32_t *bitstream_adr, unsigned int max_stream_len) { /* * UNSEGMENTED @@ -1470,6 +1470,78 @@ static uint32_t compress_smearing(const struct cmp_cfg *cfg, uint32_t stream_len } +/** + * @brief check if two buffers are overlapping + * @see https://stackoverflow.com/a/325964 + * + * @param buf_a start address of the 1st buffer (can be NULL) + * @param size_a byte size of the 1st buffer + * @param buf_b start address of the 2nd buffer (can be NULL) + * @param size_b byte size of the 2nd buffer + * + * @returns 0 if buffers are not overlapping, otherwise buffers are + * overlapping + */ + +static int buffer_overlaps(const void *buf_a, size_t size_a, + const void *buf_b, size_t size_b) +{ + if (!buf_a) + return 0; + + if (!buf_b) + return 0; + + if ((const char *)buf_a < (const char *)buf_b + size_b && + (const char *)buf_b < (const char *)buf_a + size_a) + return 1; + + return 0; +} + + +/** + * @brief check if the ICU buffer parameters are invalid + * + * @param cfg pointer to the compressor configuration to check + * + * @returns 0 if the buffer parameters are valid, otherwise invalid + */ + +static uint32_t check_compression_buffers(const struct cmp_cfg *cfg) +{ + size_t data_size; + + RETURN_ERROR_IF(cfg == NULL , GENERIC, ""); + + RETURN_ERROR_IF(cfg->src == NULL , CHUNK_NULL, ""); + + data_size = size_of_a_sample(cfg->data_type) * cfg->samples; + + if (cfg->samples == 0) + debug_print("Warning: The samples parameter is 0. No data are compressed. This behavior may not be intended."); + + RETURN_ERROR_IF(buffer_overlaps(cfg->dst, cfg->stream_size, cfg->src, data_size), PAR_BUFFERS, + "The compressed data buffer and the data to compress buffer are overlapping."); + + if (model_mode_is_used(cfg->cmp_mode)) { + RETURN_ERROR_IF(cfg->model_buf == NULL , PAR_NO_MODEL, ""); + + RETURN_ERROR_IF(buffer_overlaps(cfg->model_buf, data_size, cfg->src, data_size), PAR_BUFFERS, + "The model buffer and the data to compress buffer are overlapping."); + RETURN_ERROR_IF(buffer_overlaps(cfg->model_buf, data_size, cfg->dst, cfg->stream_size), PAR_BUFFERS, + "The model buffer and the compressed data buffer are overlapping."); + + RETURN_ERROR_IF(buffer_overlaps(cfg->updated_model_buf, data_size, cfg->src, data_size), PAR_BUFFERS, + "The updated model buffer and the data to compress buffer are overlapping."); + RETURN_ERROR_IF(buffer_overlaps(cfg->updated_model_buf, data_size, cfg->dst, cfg->stream_size), PAR_BUFFERS, + "The updated model buffer and the compressed data buffer are overlapping."); + } + + return CMP_ERROR(NO_ERROR); +} + + /** * @brief checks if the ICU compression configuration is valid * @@ -1483,18 +1555,17 @@ static uint32_t cmp_cfg_icu_is_invalid_error_code(const struct cmp_cfg *cfg) { RETURN_ERROR_IF(cmp_cfg_gen_par_is_invalid(cfg) , PAR_GENERIC, ""); - RETURN_ERROR_IF(cmp_cfg_icu_buffers_is_invalid(cfg), PAR_BUFFERS, ""); if (cmp_imagette_data_type_is_used(cfg->data_type)) { RETURN_ERROR_IF(cmp_cfg_imagette_is_invalid(cfg), PAR_SPECIFIC, ""); } else if (cmp_fx_cob_data_type_is_used(cfg->data_type)) { RETURN_ERROR_IF(cmp_cfg_fx_cob_is_invalid(cfg), PAR_SPECIFIC, ""); - } else if (cmp_aux_data_type_is_used(cfg->data_type)) { - RETURN_ERROR_IF(cmp_cfg_aux_is_invalid(cfg), PAR_SPECIFIC, ""); } else { - RETURN_ERROR(INT_DATA_TYPE_UNSUPPORTED, ""); + RETURN_ERROR_IF(cmp_cfg_aux_is_invalid(cfg), PAR_SPECIFIC, ""); } + FORWARD_IF_ERROR(check_compression_buffers(cfg), ""); + return CMP_ERROR(NO_ERROR); } @@ -1563,12 +1634,10 @@ static uint32_t compress_data_internal(const struct cmp_cfg *cfg, uint32_t strea /* TODO: move this check to the memcpy */ RETURN_ERROR_IF(raw_stream_size > cfg->stream_size, SMALL_BUF_, ""); } + if (cfg->samples == 0) /* nothing to compress we are done */ return stream_len; - FORWARD_IF_ERROR(cmp_cfg_icu_is_invalid_error_code(cfg), ""); - - if (raw_mode_is_used(cfg->cmp_mode)) { uint32_t raw_size = cfg->samples * (uint32_t)size_of_a_sample(cfg->data_type); @@ -1576,7 +1645,8 @@ static uint32_t compress_data_internal(const struct cmp_cfg *cfg, uint32_t strea uint8_t *p = (uint8_t *)cfg->dst + (stream_len >> 3); memcpy(p, cfg->src, raw_size); - RETURN_ERROR_IF(cpu_to_be_data_type(p, raw_size, cfg->data_type), GENERIC, ""); + RETURN_ERROR_IF(cpu_to_be_data_type(p, raw_size, cfg->data_type), + INT_DATA_TYPE_UNSUPPORTED, ""); } bitsize += stream_len + raw_size*8; /* convert to bits */ } else { @@ -1707,7 +1777,6 @@ static uint32_t set_cmp_col_size(uint8_t *cmp_col_size_field, uint32_t cmp_col_s * success or an error code if it fails (which can be tested with * cmp_is_error()) */ - static uint32_t cmp_collection(const uint8_t *col, const uint8_t *model, uint8_t *updated_model, uint32_t *dst, uint32_t dst_capacity, @@ -1722,12 +1791,19 @@ static uint32_t cmp_collection(const uint8_t *col, /* sanity check of the collection header */ cfg->data_type = convert_subservice_to_cmp_data_type(cmp_col_get_subservice(col_hdr)); sample_size = (uint16_t)size_of_a_sample(cfg->data_type); - RETURN_ERROR_IF(sample_size == 0, COL_SUBSERVICE_UNSUPPORTED, - "unsupported subservice: %u", cmp_col_get_subservice(col_hdr)); RETURN_ERROR_IF(col_data_length % sample_size, COL_SIZE_INCONSISTENT, "col_data_length: %u %% sample_size: %u != 0", col_data_length, sample_size); cfg->samples = col_data_length/sample_size; + /* prepare the different buffers */ + cfg->src = col + COLLECTION_HDR_SIZE; + if (model) + cfg->model_buf = model + COLLECTION_HDR_SIZE; + if (updated_model) + cfg->updated_model_buf = updated_model + COLLECTION_HDR_SIZE; + cfg->dst = dst; + cfg->stream_size = dst_capacity; + FORWARD_IF_ERROR(cmp_cfg_icu_is_invalid_error_code(cfg), ""); if (cfg->cmp_mode != CMP_MODE_RAW) { /* hear we reserve space for the compressed data size field */ @@ -1746,14 +1822,6 @@ static uint32_t cmp_collection(const uint8_t *col, if (model_mode_is_used(cfg->cmp_mode) && updated_model) memcpy(updated_model, col, COLLECTION_HDR_SIZE); - /* prepare the different buffers */ - cfg->dst = dst; - cfg->src = col + COLLECTION_HDR_SIZE; - if (model) - cfg->model_buf = model + COLLECTION_HDR_SIZE; - if (updated_model) - cfg->updated_model_buf = updated_model + COLLECTION_HDR_SIZE; - /* is enough capacity in the dst buffer to store the data uncompressed */ if ((dst == NULL || dst_capacity >= dst_size + col_data_length) && cfg->cmp_mode != CMP_MODE_RAW) { @@ -1940,22 +2008,29 @@ static enum chunk_type cmp_col_get_chunk_type(const struct collection_hdr *col) /** * @brief Set the compression configuration from the compression parameters - * based on the chunk type + * based on the chunk type of the collection * - * @param[in] par pointer to a compression parameters struct - * @param[in] chunk_type the type of the chunk to be compressed - * @param[out] cfg pointer to a compression configuration + * @param[in] col pointer to a collection header + * @param[in] par pointer to a compression parameters struct + * @param[out] cfg pointer to a compression configuration + * + * @returns the chunk type of the collection */ -static void init_cmp_cfg_from_cmp_par(const struct cmp_par *par, enum chunk_type chunk_type, - struct cmp_cfg *cfg) +static enum chunk_type init_cmp_cfg_from_cmp_par(const struct collection_hdr *col, + const struct cmp_par *par, + struct cmp_cfg *cfg) { + enum chunk_type chunk_type = cmp_col_get_chunk_type(col); + memset(cfg, 0, sizeof(struct cmp_cfg)); - /* the ranges of the parameters are checked in cmp_cfg_icu_is_invalid() */ + /* the ranges of the parameters are checked in cmp_cfg_icu_is_invalid_error_code() */ cfg->cmp_mode = par->cmp_mode; cfg->model_value = par->model_value; - cfg->round = par->lossy_par; + if (par->lossy_par) + debug_print("Warning: lossy compression is not supported for chunk compression, lossy_par will be ignored."); + cfg->round = 0; switch (chunk_type) { case CHUNK_TYPE_NCAM_IMAGETTE: @@ -2005,6 +2080,9 @@ static void init_cmp_cfg_from_cmp_par(const struct cmp_par *par, enum chunk_type cfg->cmp_par_background_pixels_error = par->fc_background_outlier_pixels; break; case CHUNK_TYPE_UNKNOWN: + default: /* default case never reached because cmp_col_get_chunk_type + returns CHUNK_TYPE_UNKNOWN if the type is unknown */ + chunk_type = CHUNK_TYPE_UNKNOWN; break; } @@ -2014,6 +2092,8 @@ static void init_cmp_cfg_from_cmp_par(const struct cmp_par *par, enum chunk_type cfg->spill_par_4 = cmp_guess_good_spill(cfg->cmp_par_4); cfg->spill_par_5 = cmp_guess_good_spill(cfg->cmp_par_5); cfg->spill_par_6 = cmp_guess_good_spill(cfg->cmp_par_6); + + return chunk_type; } @@ -2083,21 +2163,17 @@ uint32_t compress_chunk(const void *chunk, uint32_t chunk_size, RETURN_ERROR_IF(chunk_size > CMP_ENTITY_MAX_ORIGINAL_SIZE, CHUNK_TOO_LARGE, "chunk_size: %"PRIu32"", chunk_size); - chunk_type = cmp_col_get_chunk_type(col); + chunk_type = init_cmp_cfg_from_cmp_par(col, cmp_par, &cfg); RETURN_ERROR_IF(chunk_type == CHUNK_TYPE_UNKNOWN, COL_SUBSERVICE_UNSUPPORTED, "unsupported subservice: %u", cmp_col_get_subservice(col)); - init_cmp_cfg_from_cmp_par(cmp_par, chunk_type, &cfg); - /* reserve space for the compression entity header, we will build the * header after the compression of the chunk */ cmp_size_byte = cmp_ent_build_chunk_header(NULL, chunk_size, &cfg, start_timestamp, 0); - if (dst) { - RETURN_ERROR_IF(dst_capacity < cmp_size_byte, SMALL_BUF_, - "dst_capacity must be at least as large as the minimum size of the compression unit."); - memset(dst, 0, cmp_size_byte); - } + RETURN_ERROR_IF(dst && dst_capacity < cmp_size_byte, SMALL_BUF_, + "dst_capacity must be at least as large as the minimum size of the compression unit."); + /* compress one collection after another */ for (read_bytes = 0; @@ -2257,25 +2333,22 @@ int32_t compress_like_rdcu(const struct rdcu_cfg *rcfg, struct cmp_info *info) info->samples_used = rcfg->samples; info->rdcu_new_model_adr_used = rcfg->rdcu_new_model_adr; info->rdcu_cmp_adr_used = rcfg->rdcu_buffer_adr; - - if (rcfg->ap1_golomb_par && rcfg->ap1_golomb_par) { - uint32_t ap1_cmp_size, ap2_cmp_size; - - cfg.cmp_par_imagette = rcfg->ap1_golomb_par; - cfg.spill_imagette = rcfg->ap1_spill; - ap1_cmp_size = compress_data_internal(&cfg, 0); - if (cmp_is_error(ap1_cmp_size) || ap1_cmp_size > INT32_MAX) - ap1_cmp_size = 0; - - cfg.cmp_par_imagette = rcfg->ap2_golomb_par; - cfg.spill_imagette = rcfg->ap2_spill; - ap2_cmp_size = compress_data_internal(&cfg, 0); - if (cmp_is_error(ap2_cmp_size) || ap2_cmp_size > INT32_MAX) - ap2_cmp_size = 0; - - info->ap1_cmp_size = ap1_cmp_size; - info->ap2_cmp_size = ap2_cmp_size; - } + info->cmp_size = 0; + info->ap1_cmp_size = 0; + info->ap2_cmp_size = 0; + + cfg.cmp_par_imagette = rcfg->ap1_golomb_par; + cfg.spill_imagette = rcfg->ap1_spill; + if (cfg.cmp_par_imagette && + cmp_cfg_icu_is_invalid_error_code(&cfg) == CMP_ERROR_NO_ERROR) + info->ap1_cmp_size = compress_data_internal(&cfg, 0); + + + cfg.cmp_par_imagette = rcfg->ap2_golomb_par; + cfg.spill_imagette = rcfg->ap2_spill; + if (cfg.cmp_par_imagette && + cmp_cfg_icu_is_invalid_error_code(&cfg) == CMP_ERROR_NO_ERROR) + info->ap2_cmp_size = compress_data_internal(&cfg, 0); } cfg.cmp_par_imagette = rcfg->golomb_par; @@ -2283,15 +2356,21 @@ int32_t compress_like_rdcu(const struct rdcu_cfg *rcfg, struct cmp_info *info) cfg.updated_model_buf = rcfg->icu_new_model_buf; cfg.dst = rcfg->icu_output_buf; + if (cmp_is_error(cmp_cfg_icu_is_invalid_error_code(&cfg))) + return (int32_t)cmp_cfg_icu_is_invalid_error_code(&cfg); + cmp_size_bit = compress_data_internal(&cfg, 0); if (info) { if (cmp_get_error_code(cmp_size_bit) == CMP_ERROR_SMALL_BUF_) info->cmp_err |= 1UL << 0;/* SMALL_BUFFER_ERR_BIT;*/ /* set small buffer error */ - if (cmp_is_error(cmp_size_bit)) + if (cmp_is_error(cmp_size_bit)) { info->cmp_size = 0; - else + info->ap1_cmp_size = 0; + info->ap2_cmp_size = 0; + } else { info->cmp_size = cmp_size_bit; + } } return (int32_t)cmp_size_bit; diff --git a/test/cmp_icu/test_cmp_icu.c b/test/cmp_icu/test_cmp_icu.c index 2dfd9d426ea139d67e9f3ae413fd43dcc6983e17..b0b2f03582bf27be8f5a1667cf1b3d8401e28485 100644 --- a/test/cmp_icu/test_cmp_icu.c +++ b/test/cmp_icu/test_cmp_icu.c @@ -1130,6 +1130,7 @@ void test_compress_imagette_diff(void) struct rdcu_cfg rcfg = {0}; int error; int32_t cmp_size; + struct cmp_info info; uint32_t golomb_par = 1; uint32_t spill = 8; @@ -1151,6 +1152,74 @@ void test_compress_imagette_diff(void) TEST_ASSERT_EQUAL_HEX(0xFEB70000, be32_to_cpu(output_buf[1])); TEST_ASSERT_EQUAL_HEX(0x00000000, be32_to_cpu(output_buf[2])); + rcfg.ap1_golomb_par = 2; + rcfg.ap1_spill = 1000; + rcfg.ap2_golomb_par = 1; + rcfg.ap2_spill = 0; + cmp_size = compress_like_rdcu(&rcfg, &info); + TEST_ASSERT_EQUAL_INT(66, cmp_size); + TEST_ASSERT_EQUAL_HEX(0xDF6002AB, be32_to_cpu(output_buf[0])); + TEST_ASSERT_EQUAL_HEX(0xFEB70000, be32_to_cpu(output_buf[1])); + TEST_ASSERT_EQUAL_HEX(0x00000000, be32_to_cpu(output_buf[2])); + TEST_ASSERT_EQUAL_INT(CMP_MODE_DIFF_ZERO, info.cmp_mode_used); + TEST_ASSERT_EQUAL_INT(8, info.spill_used); + TEST_ASSERT_EQUAL_INT(1, info.golomb_par_used); + TEST_ASSERT_EQUAL_INT(7, info.samples_used); + TEST_ASSERT_EQUAL_INT(66, info.cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.ap1_cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.ap2_cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.rdcu_new_model_adr_used); + TEST_ASSERT_EQUAL_INT(0, info.rdcu_cmp_adr_used); + TEST_ASSERT_EQUAL_INT(8, info.model_value_used); + TEST_ASSERT_EQUAL_INT(0, info.round_used); + TEST_ASSERT_EQUAL_INT(0, info.cmp_err); + + rcfg.ap1_golomb_par = 0; + rcfg.ap1_spill = 1000; + rcfg.ap2_golomb_par = 0; + rcfg.ap2_spill = 0; + cmp_size = compress_like_rdcu(&rcfg, &info); + TEST_ASSERT_EQUAL_INT(66, cmp_size); + TEST_ASSERT_EQUAL_HEX(0xDF6002AB, be32_to_cpu(output_buf[0])); + TEST_ASSERT_EQUAL_HEX(0xFEB70000, be32_to_cpu(output_buf[1])); + TEST_ASSERT_EQUAL_HEX(0x00000000, be32_to_cpu(output_buf[2])); + TEST_ASSERT_EQUAL_INT(CMP_MODE_DIFF_ZERO, info.cmp_mode_used); + TEST_ASSERT_EQUAL_INT(8, info.spill_used); + TEST_ASSERT_EQUAL_INT(1, info.golomb_par_used); + TEST_ASSERT_EQUAL_INT(7, info.samples_used); + TEST_ASSERT_EQUAL_INT(66, info.cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.ap1_cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.ap2_cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.rdcu_new_model_adr_used); + TEST_ASSERT_EQUAL_INT(0, info.rdcu_cmp_adr_used); + TEST_ASSERT_EQUAL_INT(8, info.model_value_used); + TEST_ASSERT_EQUAL_INT(0, info.round_used); + TEST_ASSERT_EQUAL_INT(0, info.cmp_err); + + /* small buffer error */ + rcfg.ap1_golomb_par = 1; + rcfg.ap1_spill = 8; + rcfg.ap2_golomb_par = 1; + rcfg.ap2_spill = 8; + rcfg.buffer_length = 3; + cmp_size = compress_like_rdcu(&rcfg, &info); + TEST_ASSERT_EQUAL_INT(-2, cmp_size); + TEST_ASSERT_EQUAL_HEX(0xDF6002AB, be32_to_cpu(output_buf[0])); + TEST_ASSERT_EQUAL_HEX(0xFEB70000, be32_to_cpu(output_buf[1])); + TEST_ASSERT_EQUAL_HEX(0x00000000, be32_to_cpu(output_buf[2])); + TEST_ASSERT_EQUAL_INT(CMP_MODE_DIFF_ZERO, info.cmp_mode_used); + TEST_ASSERT_EQUAL_INT(8, info.spill_used); + TEST_ASSERT_EQUAL_INT(1, info.golomb_par_used); + TEST_ASSERT_EQUAL_INT(7, info.samples_used); + TEST_ASSERT_EQUAL_INT(0, info.cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.ap1_cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.ap2_cmp_size); + TEST_ASSERT_EQUAL_INT(0, info.rdcu_new_model_adr_used); + TEST_ASSERT_EQUAL_INT(0, info.rdcu_cmp_adr_used); + TEST_ASSERT_EQUAL_INT(8, info.model_value_used); + TEST_ASSERT_EQUAL_INT(0, info.round_used); + TEST_ASSERT_EQUAL_INT(0x1, info.cmp_err); + /* test: icu_output_buf = NULL */ rcfg.icu_output_buf = NULL; cmp_size = compress_like_rdcu(&rcfg, NULL); @@ -1208,7 +1277,7 @@ void test_compress_imagette_model(void) rcfg.model_buf = NULL; /* this is the error */ cmp_size = compress_like_rdcu(&rcfg, NULL); TEST_ASSERT_TRUE(cmp_is_error((uint32_t)cmp_size)); - TEST_ASSERT_EQUAL(CMP_ERROR_PAR_BUFFERS, cmp_get_error_code((uint32_t)cmp_size)); + TEST_ASSERT_EQUAL(CMP_ERROR_PAR_NO_MODEL, cmp_get_error_code((uint32_t)cmp_size)); } @@ -1253,6 +1322,10 @@ void test_compress_imagette_raw(void) cmp_size = compress_like_rdcu(&rcfg, NULL); TEST_ASSERT_EQUAL_INT(7*16, cmp_size); + /* error case: cfg = NULL */ + cmp_size = compress_like_rdcu(NULL, NULL); + TEST_ASSERT_TRUE(cmp_is_error((uint32_t)cmp_size)); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_GENERIC, cmp_get_error_code((uint32_t)cmp_size)); /* error case: input_buf = NULL */ memset(&rcfg, 0, sizeof(rcfg)); @@ -1263,7 +1336,7 @@ void test_compress_imagette_raw(void) cmp_size = compress_like_rdcu(&rcfg, NULL); TEST_ASSERT_TRUE(cmp_is_error((uint32_t)cmp_size)); - TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_BUFFERS, cmp_get_error_code((uint32_t)cmp_size)); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_CHUNK_NULL, cmp_get_error_code((uint32_t)cmp_size)); /* error case: compressed data buffer to small */ @@ -1293,7 +1366,7 @@ void test_compress_imagette_error_cases(void) int32_t cmp_size; rcfg.cmp_mode = CMP_MODE_DIFF_ZERO; - rcfg.input_buf = NULL; + rcfg.input_buf = data; rcfg.samples = 0; /* nothing to compress */ rcfg.golomb_par = 1; rcfg.spill = 8; @@ -1855,6 +1928,7 @@ void test_collection_zero_data_length(void) /* compress the data */ cmp_par.cmp_mode = CMP_MODE_DIFF_MULTI; + cmp_par.nc_imagette = 1; dst = NULL; cmp_size = compress_chunk(chunk, CHUNK_SIZE, NULL, NULL, dst, @@ -1942,23 +2016,257 @@ void nootest_collection_zero_data_length_2(void) } #endif + +static int n_timestamp_fail; /* fail after n calls */ +static uint64_t get_timstamp_test(void) +{ + static int n; + + if (n < n_timestamp_fail) { + n++; + return 42; + } + n = 0; + return 1ULL << 48; /* invalid time stamp */ +} + /** - * @test compress_like_rdcu + * @test compress_chunk */ -void test_compress_like_rdcu_error_cases(void) +void test_compress_chunk_error_cases(void) { - int32_t cmp_size; - struct rdcu_cfg rcfg = {0}; + enum { DATA_SIZE_1 = 2*sizeof(struct s_fx), + DATA_SIZE_2 = 3*sizeof(struct s_fx_efx_ncob_ecob), + CHUNK_SIZE = 2*COLLECTION_HDR_SIZE + DATA_SIZE_1 + DATA_SIZE_2 + }; + uint8_t chunk[CHUNK_SIZE]; + uint8_t const chunk_model[CHUNK_SIZE] = {0}; /* model is set to zero */ + uint8_t updated_chunk_model[CHUNK_SIZE]; + uint32_t dst[COMPRESS_CHUNK_BOUND(CHUNK_SIZE, 2)/sizeof(uint32_t)]; + uint32_t dst_capacity = sizeof(dst); + struct cmp_par cmp_par; + uint32_t cmp_size; + struct collection_hdr *col2; - /* cfg = NULL test */ - cmp_size = compress_like_rdcu(NULL, NULL); - TEST_ASSERT_EQUAL(-1, cmp_size); + { /* create a chunk with two collection */ + struct collection_hdr *col1 = (struct collection_hdr *)chunk; + struct s_fx *data1 = (struct s_fx *)col1->entry; + struct s_fx_efx_ncob_ecob *data2; + memset(col1, 0, COLLECTION_HDR_SIZE); + TEST_ASSERT_FALSE(cmp_col_set_subservice(col1, SST_NCxx_S_SCIENCE_S_FX)); + TEST_ASSERT_FALSE(cmp_col_set_data_length(col1, DATA_SIZE_1)); + data1[0].exp_flags = 0; + data1[0].fx = 1; + data1[1].exp_flags = 0xF0; + data1[1].fx = 0xABCDE0FF; + col2 = (struct collection_hdr *)(chunk + COLLECTION_HDR_SIZE + DATA_SIZE_1); + memset(col2, 0, COLLECTION_HDR_SIZE); + TEST_ASSERT_FALSE(cmp_col_set_subservice(col2, SST_NCxx_S_SCIENCE_S_FX_EFX_NCOB_ECOB)); + TEST_ASSERT_FALSE(cmp_col_set_data_length(col2, DATA_SIZE_2)); + data2 = (struct s_fx_efx_ncob_ecob *)col2->entry; + data2[0].exp_flags = 1; + data2[0].fx = 2; + data2[0].efx = 3; + data2[0].ncob_x = 4; + data2[0].ncob_y = 5; + data2[0].ecob_x = 6; + data2[0].ecob_y = 7; + data2[1].exp_flags = 0; + data2[1].fx = 0; + data2[1].efx = 0; + data2[1].ncob_x = 0; + data2[1].ncob_y = 0; + data2[1].ecob_x = 0; + data2[1].ecob_y = 0; + data2[2].exp_flags = 0xF; + data2[2].fx = ~0U; + data2[2].efx = ~0U; + data2[2].ncob_x = ~0U; + data2[2].ncob_y = ~0U; + data2[2].ecob_x = ~0U; + data2[2].ecob_y = ~0U; + } - /* samples = 0 test */ - rcfg.samples = 0; - cmp_size = compress_like_rdcu(&rcfg, NULL); - TEST_ASSERT_EQUAL(0, cmp_size); + /* compress the data */ + cmp_par.cmp_mode = CMP_MODE_MODEL_ZERO; + cmp_par.model_value = 16; + cmp_par.lossy_par = 0; + + cmp_par.nc_imagette = 1; + + cmp_par.s_exp_flags = MAX_CHUNK_CMP_PAR; + cmp_par.s_fx = MIN_CHUNK_CMP_PAR; + cmp_par.s_ncob = 2; + cmp_par.s_efx = 0xFFFE; + cmp_par.s_ecob = 1; + + compress_chunk_init(NULL, 23); + + /* this sound not return an error */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + NULL, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_NO_ERROR, cmp_get_error_code(cmp_size)); + TEST_ASSERT_EQUAL(124, cmp_size); + + /* error: no chunk */ + cmp_size = compress_chunk(NULL, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_CHUNK_NULL, cmp_get_error_code(cmp_size)); + + /* error: chunk_size = 0 */ + cmp_size = compress_chunk(chunk, 0, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_CHUNK_SIZE_INCONSISTENT, cmp_get_error_code(cmp_size)); + + /* error: chunk_size does not match up with the collection size */ + TEST_ASSERT_FALSE(cmp_col_set_data_length((struct collection_hdr *) chunk, 100)); + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_CHUNK_SIZE_INCONSISTENT, cmp_get_error_code(cmp_size)); + TEST_ASSERT_FALSE(cmp_col_set_data_length((struct collection_hdr *) chunk, DATA_SIZE_1)); + + /* error: no model when needed */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, NULL, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_NO_MODEL, cmp_get_error_code(cmp_size)); + /* this should work */ + cmp_par.cmp_mode = CMP_MODE_DIFF_ZERO; + cmp_size = compress_chunk(chunk, CHUNK_SIZE, NULL, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_NO_ERROR, cmp_get_error_code(cmp_size)); + cmp_par.cmp_mode = CMP_MODE_MODEL_ZERO; + + memset(dst, 0xFF, sizeof(dst)); + + /* error chunk and model are the same */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_BUFFERS, cmp_get_error_code(cmp_size)); + + /* error chunk and updated model are the same */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + chunk, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_BUFFERS, cmp_get_error_code(cmp_size)); + + /* buffer and dst are the same */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, dst, + updated_chunk_model, dst, dst_capacity, &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_BUFFERS, cmp_get_error_code(cmp_size)); + + /* error updated model buffer and dst are the same */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + dst, dst, dst_capacity, &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_BUFFERS, cmp_get_error_code(cmp_size)); + + /* chunk buffer and dst are the same */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, (void*)chunk, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_BUFFERS, cmp_get_error_code(cmp_size)); + + /* error: cmp_par = NULL */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + NULL); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_NULL, cmp_get_error_code(cmp_size)); + + /* error: cmp_par invalid*/ + cmp_par.s_exp_flags = 0; + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_PAR_SPECIFIC, cmp_get_error_code(cmp_size)); + cmp_par.s_exp_flags = MAX_CHUNK_CMP_PAR; + + /* error: chunk size to big */ + cmp_size = compress_chunk(chunk, CMP_ENTITY_MAX_ORIGINAL_SIZE+1, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_CHUNK_TOO_LARGE, cmp_get_error_code(cmp_size)); + + /* error: dst buffer smaller than entity header */ + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, 5, &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF_, cmp_get_error_code(cmp_size)); + + /* error: invalid collection type */ + TEST_ASSERT_FALSE(cmp_col_set_subservice((struct collection_hdr *)chunk, 42)); + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_COL_SUBSERVICE_UNSUPPORTED, cmp_get_error_code(cmp_size)); + TEST_ASSERT_FALSE(cmp_col_set_subservice((struct collection_hdr *)chunk, SST_NCxx_S_SCIENCE_S_FX)); + + /* error: TODO */ + TEST_ASSERT_FALSE(cmp_col_set_data_length(col2, DATA_SIZE_2-1)); + cmp_size = compress_chunk(chunk, CHUNK_SIZE-1, chunk_model, + updated_chunk_model, NULL, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_COL_SIZE_INCONSISTENT, cmp_get_error_code(cmp_size)); + TEST_ASSERT_FALSE(cmp_col_set_data_length(col2, DATA_SIZE_2)); + + /* this sound work */ + cmp_par.lossy_par = 0x1; + { + size_t i; + for (i = 0; i < ARRAY_SIZE(dst); i++) + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, dst[i]); + } + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_NO_ERROR, cmp_get_error_code(cmp_size)); + TEST_ASSERT_EQUAL(124, cmp_size); + + /* error: invalid collection combination */ + TEST_ASSERT_FALSE(cmp_col_set_subservice((struct collection_hdr *)(chunk + COLLECTION_HDR_SIZE + DATA_SIZE_1), + SST_NCxx_S_SCIENCE_SMEARING)); + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_CHUNK_SUBSERVICE_INCONSISTENT, cmp_get_error_code(cmp_size)); + TEST_ASSERT_FALSE(cmp_col_set_subservice((struct collection_hdr *)(chunk + COLLECTION_HDR_SIZE + DATA_SIZE_1), + SST_NCxx_S_SCIENCE_S_FX_EFX_NCOB_ECOB)); + + /* error: start time stamp error */ + compress_chunk_init(&get_timstamp_test, 23); + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_ENTITY_TIMESTAMP, cmp_get_error_code(cmp_size)); + + /* error: end time stamp error */ + n_timestamp_fail = 1; + compress_chunk_init(&get_timstamp_test, 23); + cmp_size = compress_chunk(chunk, CHUNK_SIZE, chunk_model, + updated_chunk_model, dst, dst_capacity, + &cmp_par); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_ENTITY_TIMESTAMP, cmp_get_error_code(cmp_size)); + n_timestamp_fail = INT_MAX; + + { /* error: trigger CMP_ERROR_ENTITY_HEADER */ + uint32_t ent_hdr_size; + uint32_t entity[25]; + uint32_t chunk_size = 42; + struct cmp_cfg cfg = {0}; + uint64_t start_timestamp = 123; + uint32_t cmp_ent_size_byte = sizeof(entity); + + cfg.cmp_mode = CMP_MODE_DIFF_ZERO; + cfg.cmp_par_1 = UINT16_MAX + 1; /* to big for entity header */ + ent_hdr_size = cmp_ent_build_chunk_header(entity, chunk_size, &cfg, + start_timestamp, cmp_ent_size_byte); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_ENTITY_HEADER, cmp_get_error_code(ent_hdr_size)); + } } @@ -2195,15 +2503,12 @@ void test_support_function_call_NULL(void) cfg.cmp_mode = CMP_MODE_DIFF_ZERO; TEST_ASSERT_TRUE(cmp_cfg_gen_par_is_invalid(NULL)); - TEST_ASSERT_TRUE(cmp_cfg_icu_buffers_is_invalid(NULL)); TEST_ASSERT_TRUE(cmp_cfg_imagette_is_invalid(NULL)); TEST_ASSERT_TRUE(cmp_cfg_fx_cob_is_invalid(NULL)); TEST_ASSERT_TRUE(cmp_cfg_aux_is_invalid(NULL)); TEST_ASSERT_TRUE(cmp_cfg_aux_is_invalid(&cfg)); - TEST_ASSERT_TRUE(cmp_cfg_icu_is_invalid(NULL)); - cfg.data_type = DATA_TYPE_UNKNOWN; - TEST_ASSERT_TRUE(cmp_cfg_icu_is_invalid(&cfg)); TEST_ASSERT_TRUE(cmp_cfg_fx_cob_get_need_pars(DATA_TYPE_S_FX, NULL)); + TEST_ASSERT_TRUE(check_compression_buffers(NULL)); } @@ -2231,3 +2536,35 @@ void test_print_cmp_info(void) print_cmp_info(&info); print_cmp_info(NULL); } + + +/** + * @test detect_buf_overlap + */ + +void test_buffer_overlaps(void) +{ + char buf_a[3]; + char buf_b[3]; + int overlap; + + + overlap = buffer_overlaps(buf_a, sizeof(buf_a), buf_b, sizeof(buf_b)); + TEST_ASSERT_FALSE(overlap); + overlap = buffer_overlaps(NULL, sizeof(buf_a), buf_b, sizeof(buf_b)); + TEST_ASSERT_FALSE(overlap); + overlap = buffer_overlaps(buf_a, sizeof(buf_a), NULL, sizeof(buf_b)); + TEST_ASSERT_FALSE(overlap); + + overlap = buffer_overlaps(buf_a, sizeof(buf_a), buf_a, sizeof(buf_a)); + TEST_ASSERT_TRUE(overlap); + + overlap = buffer_overlaps(&buf_a[1], 1, buf_a, sizeof(buf_a)); + TEST_ASSERT_TRUE(overlap); + + overlap = buffer_overlaps(&buf_a[0], 2, &buf_a[1], 2); + overlap = buffer_overlaps(&buf_a[1], 2, &buf_a[0], 2); + TEST_ASSERT_TRUE(overlap); +} + + diff --git a/test/fuzz/fuzz_compression.c b/test/fuzz/fuzz_compression.c index bde54b3930fb61d89697c8cae7978d0a8135dde2..d42d4ddd15c9c2d07ccca6a8194cbfcacf3ca6d4 100644 --- a/test/fuzz/fuzz_compression.c +++ b/test/fuzz/fuzz_compression.c @@ -65,7 +65,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) cmp_data = (uint32_t *)TEST_malloc(cmp_data_capacity); FUZZ_dataProducer_cmp_par(producer, &cmp_par); - cmp_par.lossy_par = 0; /*TODO: implement lossy */ if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) cmp_par_ptr = &cmp_par; @@ -101,6 +100,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) case CMP_ERROR_PAR_SPECIFIC: case CMP_ERROR_PAR_BUFFERS: case CMP_ERROR_PAR_NULL: + case CMP_ERROR_PAR_NO_MODEL: /* chunk errors */ case CMP_ERROR_CHUNK_NULL: case CMP_ERROR_CHUNK_TOO_LARGE: diff --git a/test/fuzz/fuzz_round_trip.c b/test/fuzz/fuzz_round_trip.c index b71948f0f898f3f0a63078828b9587848fedb6b0..8dea441126549d2feb21083c00b790b12b07a73f 100644 --- a/test/fuzz/fuzz_round_trip.c +++ b/test/fuzz/fuzz_round_trip.c @@ -57,7 +57,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) /* generate compression parameters */ FUZZ_dataProducer_cmp_par(producer, &cmp_par); - cmp_par.lossy_par = 0; /*TODO: implement lossy */ if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) cmp_par_ptr = &cmp_par; @@ -89,6 +88,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) case CMP_ERROR_PAR_SPECIFIC: case CMP_ERROR_PAR_BUFFERS: case CMP_ERROR_PAR_NULL: + case CMP_ERROR_PAR_NO_MODEL: /* chunk errors */ case CMP_ERROR_CHUNK_NULL: case CMP_ERROR_CHUNK_TOO_LARGE: