diff --git a/cmp_tool.c b/cmp_tool.c index 19213b8c4ad394671a07eba4ddbeea18532432b2..e9cd735ab2a4ad7b0cd580d120e133a977b258af 100644 --- a/cmp_tool.c +++ b/cmp_tool.c @@ -367,26 +367,22 @@ int main(int argc, char **argv) printf("DONE\n"); printf("Importing compressed data file %s ... ", data_file_name); - cmp_size_byte = cmp_bit_to_4byte(info.cmp_size); ent_size = cmp_ent_create(NULL, DATA_TYPE_IMAGETTE, info.cmp_mode_used == CMP_MODE_RAW, - cmp_size_byte); + cmp_bit_to_4byte(info.cmp_size)); if (!ent_size) goto fail; - decomp_entity = malloc(ent_size); + decomp_entity = calloc(1, ent_size); if (!decomp_entity) { fprintf(stderr, "%s: Error allocating memory for decompression input buffer.\n", PROGRAM_NAME); goto fail; } ent_size = cmp_ent_create(decomp_entity, DATA_TYPE_IMAGETTE, info.cmp_mode_used == CMP_MODE_RAW, - cmp_size_byte); + cmp_bit_to_4byte(info.cmp_size)); if (!ent_size) goto fail; - if (info.cmp_mode_used == CMP_MODE_RAW) - /* the raw data does not have to be a multiple of 4 bytes */ - cmp_size_byte = (info.cmp_size+7)/CHAR_BIT; - + cmp_size_byte = (info.cmp_size+7)/CHAR_BIT; f_size = read_file8(data_file_name, cmp_ent_get_data_buf(decomp_entity), cmp_size_byte, verbose_en); if (f_size < 0) @@ -407,17 +403,26 @@ int main(int argc, char **argv) /* to be save allocate at least the size of the cmp_entity struct */ if (buf_size < sizeof(struct cmp_entity)) buf_size = sizeof(struct cmp_entity); + /* The compressed data is read in 4-byte words, so our + * data buffer must be a multiple of 4 bytes. + */ + buf_size = (buf_size + 3) & ~((size_t)0x3); - decomp_entity = malloc(buf_size); + decomp_entity = calloc(1, buf_size); if (!decomp_entity) { fprintf(stderr, "%s: Error allocating memory for the compression entity buffer.\n", PROGRAM_NAME); goto fail; } size = read_file_cmp_entity(data_file_name, decomp_entity, - size, verbose_en); + (uint32_t)size, verbose_en); if (size < 0) goto fail; + if (cmp_ent_get_size(decomp_entity) & 0x3) { + printf("\nThe size of the compression entity is not a multiple of 4 bytes. Padding the compression entity to a multiple of 4 bytes.\n"); + cmp_ent_set_size(decomp_entity, (uint32_t)buf_size); + } + if (verbose_en) { cmp_ent_print(decomp_entity); printf("\n"); diff --git a/lib/cmp_entity.c b/lib/cmp_entity.c index 64052c14b554bdbe0119a5eada0ad56b1976290d..3336e674f0445011e5866950ba39ac76c134d703 100644 --- a/lib/cmp_entity.c +++ b/lib/cmp_entity.c @@ -2413,7 +2413,7 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent) debug_print("Compressed with cmp_tool version: %u.%02u\n", major, minor); } else - debug_print("ICU ASW Version ID: %" PRIu32 "\n", version_id); + debug_print("ICU ASW Version ID: %08" PRIx32 "\n", version_id); cmp_ent_size = cmp_ent_get_size(ent); debug_print("Compression Entity Size: %" PRIu32 " byte\n", cmp_ent_size); diff --git a/lib/cmp_io.c b/lib/cmp_io.c index 4f3ba6ac2fa824f3f70a422f2c6e80f244aa46ad..9cf36eac9f5c1224aedd275cd3548e5b575feacc 100644 --- a/lib/cmp_io.c +++ b/lib/cmp_io.c @@ -1230,8 +1230,8 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t buf_size, if (!data) /* finished counting the sample */ break; - fprintf(stderr, "%s: %s: Error: The files do not contain enough data as requested.\n", - PROGRAM_NAME, file_name); + fprintf(stderr, "%s: %s: Error: The files do not contain enough data. Expected: 0x%x, has 0x%zx.\n", + PROGRAM_NAME, file_name, buf_size, i); return -1; } @@ -1275,12 +1275,12 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t buf_size, nptr = eptr; } - /* did we read all data in the string? */ - while (isspace(*nptr) || *nptr == '#') { + /* did we read all data in the string? 0 at the end are ignored */ + while (isspace(*nptr) || *nptr == '0' || *nptr == '#') { if (*nptr == '#') nptr = skip_comment(nptr); else - nptr = skip_space(nptr); + nptr++; } if (*nptr != '\0') { fprintf(stderr, "%s: %s: Warning: The file may contain more data than specified by the samples or cmp_size parameter.\n", @@ -1339,7 +1339,7 @@ ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size, int v return 0; } if ((unsigned long)file_size < buf_size) { - fprintf(stderr, "%s: %s: Error: The files do not contain enough data as requested.\n", PROGRAM_NAME, file_name); + fprintf(stderr, "%s: %s: Error: The files do not contain enough data.\n", PROGRAM_NAME, file_name); goto fail; } /* reset the file position indicator to the beginning of the file */ @@ -1451,13 +1451,13 @@ ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent, enum cmp_data_type data_type = cmp_ent_get_data_type(ent); if (data_type == DATA_TYPE_UNKNOWN) { - fprintf(stderr, "%s: %s: Error: Compression data type is not supported.\n", + fprintf(stderr, "%s: %s: Error: Compression data type is not supported. The header of the compression entity may be corrupted.\n", PROGRAM_NAME, file_name); return -1; } if (size != (ssize_t)cmp_ent_get_size(ent)) { - fprintf(stderr, "%s: %s: The size of the compression entity set in the header of the compression entity is not the same size as the read-in file has.\n", - PROGRAM_NAME, file_name); + fprintf(stderr, "%s: %s: The size of the compression entity set in the header of the compression entity is not the same size as the read-in file has. Expected: 0x%x, has 0x%zx.\n", + PROGRAM_NAME, file_name, cmp_ent_get_size(ent), size); return -1; } diff --git a/test/cmp_tool/cmp_tool_integration_test.py b/test/cmp_tool/cmp_tool_integration_test.py index 7d58943afab15702f38a6142e43de20de4118b6c..c5e489861be23a0dc8b4a26087f06383b1256418 100755 --- a/test/cmp_tool/cmp_tool_integration_test.py +++ b/test/cmp_tool/cmp_tool_integration_test.py @@ -21,6 +21,7 @@ IMAGETTE_HEADER_SIZE = GENERIC_HEADER_SIZE+4 IMAGETTE_ADAPTIVE_HEADER_SIZE = GENERIC_HEADER_SIZE+12 NON_IMAGETTE_HEADER_SIZE = GENERIC_HEADER_SIZE+32 + def call_cmp_tool(args): args = shlex.split(PATH_CMP_TOOL + " " + args) @@ -1016,6 +1017,81 @@ def test_sample_used_is_to_big(): del_file(info_file_name) +def test_cmp_entity_not_4_byte_aligned(): + cmp_data = '444444' # cmp data are not a multiple of 4 + + version_id = 0x8001_0042 + cmp_ent_size = IMAGETTE_HEADER_SIZE + len(cmp_data)//2 + original_size = 0xA + + start_time = cuc_timestamp(datetime.utcnow()) + end_time = cuc_timestamp(datetime.utcnow()) + + data_type = 1 + cmp_mode_used = 2 + model_value_used = 8 + model_id = 0xBEEF + model_counter = 0 + lossy_cmp_par_used = 0 + + generic_header = build_generic_header(version_id, cmp_ent_size, + original_size, start_time, end_time, data_type, + cmp_mode_used, model_value_used, model_id, + model_counter, lossy_cmp_par_used) + spill_used = 60 + golomb_par_used = 7 + + ima_header = build_imagette_header(spill_used, golomb_par_used) + cmp_data_header = generic_header + ima_header + cmp_data + + data_exp = '00 01 00 02 00 03 00 04 00 05 \n' + info = ("cmp_size = 20\n" + "golomb_par_used = 7\n" + "spill_used = 60\n" + + "cmp_mode_used = 2\n" +"samples_used=5\n") + + cmp_file_name = 'unaligned_cmp_size.cmp' + info_file_name = 'unaligned_cmp_size.info' + output_prefix = '4_byte_aligned' + pars = ['-i %s -d %s --no_header -o %s' % (info_file_name, cmp_file_name, output_prefix), + '-d %s -o %s' % (cmp_file_name, output_prefix)] + + try: + with open(info_file_name, 'w') as f: + f.write(info) + + for par in pars: + with open(cmp_file_name, 'w') as f: + if '--no_header' in par: + f.write(cmp_data) + else: + f.write(cmp_data_header) + + returncode, stdout, stderr = call_cmp_tool(par) + + assert(stderr == "") + + if '--no_header' in par: + assert(stdout == CMP_START_STR_DECMP + + "Importing decompression information file %s ... DONE\n" % (info_file_name) + + "Importing compressed data file %s ... DONE\n" % (cmp_file_name) + + "Decompress data ... DONE\n" + + "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix)) + else: + assert(stdout == CMP_START_STR_DECMP + + "Importing compressed data file %s ... \n" % (cmp_file_name) + + "The size of the compression entity is not a multiple of 4 bytes. Padding the compression entity to a multiple of 4 bytes.\n" + + "DONE\n" + + "Decompress data ... DONE\n"+ + "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix)) + + assert(returncode == EXIT_SUCCESS) + with open(output_prefix+".dat", encoding='utf-8') as f: + assert(f.read() == data_exp) # decompressed data == input data + + finally: + del_file(cmp_file_name) + del_file(info_file_name) + del_file(output_prefix+".dat") + def test_header_wrong_formatted(): cmp_file_name = 'read_wrong_format_header.cmp' @@ -1072,7 +1148,9 @@ def test_header_read_in(): assert(returncode == EXIT_FAILURE) assert(stdout == CMP_START_STR_DECMP + "Importing compressed data file %s ... FAILED\n" % (cmp_file_name)) - assert(stderr == "cmp_tool: %s: The size of the compression entity set in the header of the compression entity is not the same size as the read-in file has.\n" %(cmp_file_name)) + assert(stderr == "cmp_tool: %s: The size of the compression entity set in the " + "header of the compression entity is not the same size as the read-in " + "file has. Expected: 0x28, has 0x26.\n" %(cmp_file_name)) # false data type data_type = 0x7FFE @@ -1090,7 +1168,8 @@ def test_header_read_in(): assert(returncode == EXIT_FAILURE) assert(stdout == CMP_START_STR_DECMP + "Importing compressed data file %s ... FAILED\n" % (cmp_file_name)) - assert(stderr == "cmp_tool: %s: Error: Compression data type is not supported.\n" % (cmp_file_name)) + assert(stderr == "cmp_tool: %s: Error: Compression data type is not supported. The " + "header of the compression entity may be corrupted.\n" % (cmp_file_name)) # false cmp_mode_used cmp_mode_used = 0xFF @@ -1153,7 +1232,7 @@ def test_model_fiel_erros(): "Importing configuration file %s ... DONE\n" % (cfg_file_name) + "Importing data file %s ... DONE\n" % (data_file_name) + "Importing model file %s ... FAILED\n" % (model_file_name) ) - assert(stderr == "cmp_tool: %s: Error: The files do not contain enough data as requested.\n" % (model_file_name)) + assert(stderr == "cmp_tool: %s: Error: The files do not contain enough data. Expected: 0xa, has 0x8.\n" % (model_file_name)) # updated model can not write with open(model_file_name, 'w', encoding='utf-8') as f: