From abb7bafc4af036cc7727d057700bb4334e719b52 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Tue, 17 Jan 2017 18:42:36 +0100 Subject: [PATCH] gmio_core: fix zip64 corrupted output --- src/gmio_core/internal/zip_utils.c | 99 ++++++---- src/gmio_core/internal/zip_utils.h | 42 ++++- tests/main_test_core.c | 1 + tests/test_amf_io.c | 220 ++++++---------------- tests/test_core_internal.c | 284 +++++++++++++++++++++++++++++ 5 files changed, 432 insertions(+), 214 deletions(-) diff --git a/src/gmio_core/internal/zip_utils.c b/src/gmio_core/internal/zip_utils.c index 47b17be..87c0f63 100644 --- a/src/gmio_core/internal/zip_utils.c +++ b/src/gmio_core/internal/zip_utils.c @@ -38,15 +38,8 @@ * Constants * ---------- */ -enum { - GMIO_ZIP_SIZE_LOCAL_FILE_HEADER = 4 + 5*2 + 3*4 + 2*2, - GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER = 4 + 6*2 + 3*4 + 5*2 +2*4, - GMIO_ZIP_SIZE_DATA_DESCRIPTOR = 4 + 4 + 4 + 4, - GMIO_ZIP64_SIZE_DATA_DESCRIPTOR = 4 + 4 + 2*8, - GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD = 4 + 8 + 2*2 + 2*4 + 4*8, - GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_LOCATOR = 4 + 4 + 8 + 4, - GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD = 4 + 4*2 + 2*4 + 2 -}; +static const uint16_t zip64_extrablock_tag = 0x0001; +static const uint16_t zip64_extrablock_size = 3*8 + 4; /* ---------- * Internal functions @@ -238,7 +231,7 @@ size_t gmio_zip_read_central_directory_header( gmio_adv_decode_uint16_le(&buff); /* disk_nb_start */ info->internal_file_attrs = gmio_adv_decode_uint16_le(&buff); info->external_file_attrs = gmio_adv_decode_uint32_le(&buff); - info->relative_offset_local_header = gmio_adv_decode_uint32_le(&buff); + info->local_header_offset = gmio_adv_decode_uint32_le(&buff); info->filename = NULL; info->extrafield = NULL; @@ -247,6 +240,36 @@ size_t gmio_zip_read_central_directory_header( return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error); } +size_t gmio_zip64_read_extrafield( + struct gmio_stream *stream, + struct gmio_zip64_extrafield *info, + int *ptr_error) +{ +#ifdef GMIO_HAVE_INT64_TYPE + uint8_t bytes[GMIO_ZIP64_SIZE_EXTRAFIELD]; + const uint8_t* buff = bytes; + size_t read_len = 0; + if (!gmio_zip_readcheckbytes(stream, bytes, sizeof(bytes), &read_len, ptr_error)) + return read_len; + if (gmio_adv_decode_uint16_le(&buff) != zip64_extrablock_tag) { + return gmio_zip_io_returnerr( + read_len, GMIO_ZIP_UTILS_ERROR_BAD_EXTRAFIELD_TAG, ptr_error); + } + if (gmio_adv_decode_uint16_le(&buff) != zip64_extrablock_size) { + return gmio_zip_io_returnerr( + read_len, GMIO_ZIP_UTILS_ERROR_BAD_EXTRAFIELD_SIZE, ptr_error); + } + info->uncompressed_size = gmio_adv_decode_uint64_le(&buff); + info->compressed_size = gmio_adv_decode_uint64_le(&buff); + info->local_header_offset = gmio_adv_decode_uint64_le(&buff); + gmio_adv_decode_uint32_le(&buff); /* Disk start number */ + return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error); +#else + return gmio_zip_io_returnerr( + 0, GMIO_ERROR_ZIP_INT64_TYPE_REQUIRED, ptr_error); +#endif +} + size_t gmio_zip64_read_end_of_central_directory_record( struct gmio_stream *stream, struct gmio_zip64_end_of_central_directory_record *info, @@ -269,7 +292,7 @@ size_t gmio_zip64_read_end_of_central_directory_record( gmio_adv_decode_uint64_le(&buff); /* total_entry_count_in_central_dir_on_disk */ info->entry_count = gmio_adv_decode_uint64_le(&buff); info->central_dir_size = gmio_adv_decode_uint64_le(&buff); - info->start_offset = gmio_adv_decode_uint64_le(&buff); + info->central_dir_offset = gmio_adv_decode_uint64_le(&buff); return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error); #else return gmio_zip_io_returnerr( @@ -293,7 +316,7 @@ size_t gmio_zip64_read_end_of_central_directory_locator( /* Number of the disk with the start of the zip64 end of central directory */ gmio_adv_decode_uint32_le(&buff); /* Relative offset of the zip64 end of central directory record */ - info->relative_offset = gmio_adv_decode_uint64_le(&buff); + info->zip64_end_of_central_dir_offset = gmio_adv_decode_uint64_le(&buff); /* Total number of disks */ gmio_adv_decode_uint32_le(&buff); return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error); @@ -320,7 +343,7 @@ size_t gmio_zip_read_end_of_central_directory_record( gmio_adv_decode_uint16_le(&buff); /* total_entry_count_in_central_dir_on_disk */ info->entry_count = gmio_adv_decode_uint16_le(&buff); info->central_dir_size = gmio_adv_decode_uint32_le(&buff); - info->start_offset = gmio_adv_decode_uint32_le(&buff); + info->central_dir_offset = gmio_adv_decode_uint32_le(&buff); info->filecomment_len = gmio_adv_decode_uint16_le(&buff); info->filecomment = NULL; return gmio_zip_io_returnerr(read_len, GMIO_ERROR_OK, ptr_error); @@ -437,9 +460,9 @@ size_t gmio_zip_write_central_directory_header( gmio_adv_encode_uint16_le(0, &buff); /* Disk number start */ gmio_adv_encode_uint16_le(info->internal_file_attrs, &buff); gmio_adv_encode_uint32_le(info->external_file_attrs, &buff); - const uint32_t relative_offset_local_header = - info->use_zip64 ? UINT32_MAX : info->relative_offset_local_header; - gmio_adv_encode_uint32_le(relative_offset_local_header, &buff); + const uint32_t local_header_offset = + info->use_zip64 ? UINT32_MAX : info->local_header_offset; + gmio_adv_encode_uint32_le(local_header_offset, &buff); /* Write to stream */ const size_t expected_written_len = @@ -469,13 +492,11 @@ size_t gmio_zip64_write_extrafield( 0, GMIO_ERROR_INVALID_MEMBLOCK_SIZE, ptr_error); } #ifdef GMIO_HAVE_INT64_TYPE - static const uint16_t extrablock_tag = 0x0001; - static const uint16_t extrablock_size = 3*8 + 4; - gmio_adv_encode_uint16_le(extrablock_tag, &buff); - gmio_adv_encode_uint16_le(extrablock_size, &buff); + gmio_adv_encode_uint16_le(zip64_extrablock_tag, &buff); + gmio_adv_encode_uint16_le(zip64_extrablock_size, &buff); gmio_adv_encode_uint64_le(info->uncompressed_size, &buff); gmio_adv_encode_uint64_le(info->compressed_size, &buff); - gmio_adv_encode_uint64_le(info->relative_offset_local_header, &buff); + gmio_adv_encode_uint64_le(info->local_header_offset, &buff); gmio_adv_encode_uint32_le(0, &buff); /* Disk start number */ return gmio_zip_io_returnerr( GMIO_ZIP64_SIZE_EXTRAFIELD, GMIO_ERROR_OK, ptr_error); @@ -505,7 +526,7 @@ size_t gmio_zip64_write_end_of_central_directory_record( gmio_adv_encode_uint64_le(disk_entry_count, &buff); gmio_adv_encode_uint64_le(info->entry_count, &buff); gmio_adv_encode_uint64_le(info->central_dir_size, &buff); - gmio_adv_encode_uint64_le(info->start_offset, &buff); + gmio_adv_encode_uint64_le(info->central_dir_offset, &buff); /* Note: don't write any PKWARE reserved "zip64 extensible data sector" /* Write to stream */ const size_t expected_written_len = sizeof(bytes); @@ -531,7 +552,7 @@ size_t gmio_zip64_write_end_of_central_directory_locator( const uint32_t disk_count = 1; gmio_adv_encode_uint32_le(0x07064b50, &buff); gmio_adv_encode_uint32_le(disk_nb, &buff); - gmio_adv_encode_uint64_le(info->relative_offset, &buff); + gmio_adv_encode_uint64_le(info->zip64_end_of_central_dir_offset, &buff); gmio_adv_encode_uint32_le(disk_count, &buff); /* Write to stream */ const size_t expected_written_len = sizeof(bytes); @@ -573,9 +594,9 @@ size_t gmio_zip_write_end_of_central_directory_record( info->use_zip64 ? UINT32_MAX : info->central_dir_size; gmio_adv_encode_uint32_le(central_dir_size, &buff); - const uint32_t start_offset = - info->use_zip64 ? UINT32_MAX : info->start_offset; - gmio_adv_encode_uint32_le(start_offset, &buff); + const uint32_t central_dir_offset = + info->use_zip64 ? UINT32_MAX : info->central_dir_offset; + gmio_adv_encode_uint32_le(central_dir_offset, &buff); gmio_adv_encode_uint16_le(info->filecomment_len, &buff); @@ -606,18 +627,20 @@ bool gmio_zip_write_single_file( file_entry->feature_version >= GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS; uint8_t extrafield[GMIO_ZIP64_SIZE_EXTRAFIELD]; - size_t zip_write_pos = 0; + uintmax_t zip_write_pos = 0; /* Write local file header */ struct gmio_zip_local_file_header lfh = {0}; + lfh.version_needed_to_extract = file_entry->feature_version; lfh.general_purpose_flags = GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR; lfh.compress_method = file_entry->compress_method; lfh.filename = file_entry->filename; lfh.filename_len = file_entry->filename_len; if (use_zip64_format_extensions) { + lfh.compressed_size = UINT32_MAX; + lfh.uncompressed_size = UINT32_MAX; const struct gmio_zip64_extrafield zip64extra = {0}; - zip_write_pos += - gmio_zip64_write_extrafield( + gmio_zip64_write_extrafield( extrafield, sizeof(extrafield), &zip64extra, ptr_error); if (gmio_error(*ptr_error)) return false; @@ -653,7 +676,7 @@ bool gmio_zip_write_single_file( return false; /* Write central directory header */ - const uintmax_t pos_start_central_dir = zip_write_pos; + const uintmax_t pos_central_dir = zip_write_pos; struct gmio_zip_central_directory_header cdh = {0}; cdh.use_zip64 = needs_zip64; cdh.version_needed_to_extract = version_needed; @@ -668,30 +691,28 @@ bool gmio_zip_write_single_file( struct gmio_zip64_extrafield zip64extra = {0}; zip64extra.compressed_size = dd.compressed_size; zip64extra.uncompressed_size = dd.uncompressed_size; - zip64extra.relative_offset_local_header = 0; - zip_write_pos += - gmio_zip64_write_extrafield( + gmio_zip64_write_extrafield( extrafield, sizeof(extrafield), &zip64extra, ptr_error); if (gmio_error(*ptr_error)) return false; cdh.extrafield = extrafield; cdh.extrafield_len = sizeof(extrafield); } - const uintmax_t central_dir_startpos = zip_write_pos; + const uintmax_t central_dir_pos = zip_write_pos; const size_t central_dir_size = gmio_zip_write_central_directory_header(stream, &cdh, ptr_error); zip_write_pos += central_dir_size; if (gmio_error(*ptr_error)) return false; - const uintmax_t pos_end_central_dir = zip_write_pos; if (needs_zip64) { /* Write Zip64 end of central directory record */ + const uintmax_t pos_zip64_end_of_central_dir = zip_write_pos; struct gmio_zip64_end_of_central_directory_record eocdr64 = {0}; eocdr64.version_needed_to_extract = version_needed; eocdr64.entry_count = 1; - eocdr64.central_dir_size = pos_end_central_dir - pos_start_central_dir; - eocdr64.start_offset = pos_start_central_dir; + eocdr64.central_dir_size = central_dir_size; + eocdr64.central_dir_offset = pos_central_dir; zip_write_pos += gmio_zip64_write_end_of_central_directory_record( stream, &eocdr64, ptr_error); @@ -700,7 +721,7 @@ bool gmio_zip_write_single_file( /* Write Zip64 end of central directory locator */ struct gmio_zip64_end_of_central_directory_locator eocdl64 = {0}; - eocdl64.relative_offset = pos_end_central_dir; + eocdl64.zip64_end_of_central_dir_offset = pos_zip64_end_of_central_dir; zip_write_pos += gmio_zip64_write_end_of_central_directory_locator( stream, &eocdl64, ptr_error); @@ -713,7 +734,7 @@ bool gmio_zip_write_single_file( eocdr.use_zip64 = needs_zip64; eocdr.entry_count = 1; eocdr.central_dir_size = (uint32_t)central_dir_size; - eocdr.start_offset = (uint32_t)central_dir_startpos; + eocdr.central_dir_offset = (uint32_t)central_dir_pos; zip_write_pos += gmio_zip_write_end_of_central_directory_record( stream, &eocdr, ptr_error); diff --git a/src/gmio_core/internal/zip_utils.h b/src/gmio_core/internal/zip_utils.h index aaa1525..27e2ba0 100644 --- a/src/gmio_core/internal/zip_utils.h +++ b/src/gmio_core/internal/zip_utils.h @@ -192,26 +192,35 @@ struct gmio_zip_central_directory_header { uint16_t filecomment_len; uint16_t internal_file_attrs; uint32_t external_file_attrs; - uint32_t relative_offset_local_header; + uint32_t local_header_offset; const char* filename; const uint8_t* extrafield; const char* filecomment; }; -enum { GMIO_ZIP64_SIZE_EXTRAFIELD = 2*2 + 3*8 + 4 }; +enum { + GMIO_ZIP_SIZE_LOCAL_FILE_HEADER = 4 + 5*2 + 3*4 + 2*2, + GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER = 4 + 6*2 + 3*4 + 5*2 +2*4, + GMIO_ZIP_SIZE_DATA_DESCRIPTOR = 4 + 4 + 4 + 4, + GMIO_ZIP64_SIZE_EXTRAFIELD = 2*2 + 3*8 + 4, + GMIO_ZIP64_SIZE_DATA_DESCRIPTOR = 4 + 4 + 2*8, + GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD = 4 + 8 + 2*2 + 2*4 + 4*8, + GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_LOCATOR = 4 + 4 + 8 + 4, + GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD = 4 + 4*2 + 2*4 + 2 +}; /*! Zip64 extended info (extra field) */ struct gmio_zip64_extrafield { uintmax_t compressed_size; uintmax_t uncompressed_size; - uintmax_t relative_offset_local_header; + uintmax_t local_header_offset; }; struct gmio_zip_end_of_central_directory_record { bool use_zip64; uint16_t entry_count; uint32_t central_dir_size; - uint32_t start_offset; + uint32_t central_dir_offset; uint16_t filecomment_len; const char* filecomment; }; @@ -219,20 +228,26 @@ struct gmio_zip_end_of_central_directory_record { struct gmio_zip64_end_of_central_directory_record { uint16_t version_made_by; enum gmio_zip_feature_version version_needed_to_extract; - uintmax_t entry_count; /* should be 64b */ - uintmax_t central_dir_size; /* should be 64b */ - uintmax_t start_offset; /* should be 64b */ + uintmax_t entry_count; /* should be 64b */ + uintmax_t central_dir_size; /* should be 64b */ + uintmax_t central_dir_offset; /* should be 64b */ }; struct gmio_zip64_end_of_central_directory_locator { - uintmax_t relative_offset; /* should be 64b */ + uintmax_t zip64_end_of_central_dir_offset; /* should be 64b */ }; enum { GMIO_ZIP_UTILS_ERROR_TAG = 0x00100000 }; enum gmio_zip_utils_error { - GMIO_ZIP_UTILS_ERROR_BAD_MAGIC = GMIO_ZIP_UTILS_ERROR_TAG + 1 + GMIO_ZIP_UTILS_ERROR_BAD_MAGIC = GMIO_ZIP_UTILS_ERROR_TAG + 1, + GMIO_ZIP_UTILS_ERROR_BAD_EXTRAFIELD_TAG, + GMIO_ZIP_UTILS_ERROR_BAD_EXTRAFIELD_SIZE }; +/* + * ZIP read functions + */ + size_t gmio_zip_read_local_file_header( struct gmio_stream* stream, struct gmio_zip_local_file_header* info, @@ -253,6 +268,11 @@ size_t gmio_zip_read_central_directory_header( struct gmio_zip_central_directory_header* info, int* ptr_error); +size_t gmio_zip64_read_extrafield( + struct gmio_stream* stream, + struct gmio_zip64_extrafield* info, + int* ptr_error); + size_t gmio_zip64_read_end_of_central_directory_record( struct gmio_stream* stream, struct gmio_zip64_end_of_central_directory_record* info, @@ -268,6 +288,10 @@ size_t gmio_zip_read_end_of_central_directory_record( struct gmio_zip_end_of_central_directory_record* info, int* ptr_error); +/* + * ZIP write functions + */ + size_t gmio_zip_write_local_file_header( struct gmio_stream* stream, const struct gmio_zip_local_file_header* info, diff --git a/tests/main_test_core.c b/tests/main_test_core.c index aa6bb30..31f3a0d 100644 --- a/tests/main_test_core.c +++ b/tests/main_test_core.c @@ -56,6 +56,7 @@ const char* all_tests() UTEST_RUN(test_internal__stringstream); UTEST_RUN(test_internal__string_ascii_utils); UTEST_RUN(test_internal__benchmark_gmio_fast_atof); + UTEST_RUN(test_internal__zip_utils); return NULL; } diff --git a/tests/test_amf_io.c b/tests/test_amf_io.c index cf7122b..7da98e4 100644 --- a/tests/test_amf_io.c +++ b/tests/test_amf_io.c @@ -256,7 +256,6 @@ static int __tamf__write_amf( return gmio_amf_write(&stream, doc, opts); } - static const char* test_amf_write_doc_1_plaintext() { static const size_t wbuffsize = 8192; @@ -282,27 +281,6 @@ static const char* test_amf_write_doc_1_plaintext() static const char zip_entry_filename[] = "test.amf"; static const uint16_t zip_entry_filename_len = sizeof(zip_entry_filename) - 1; -static const char* __tamf__check_zip_local_file_header( - const struct gmio_zip_local_file_header* zip_lfh) -{ - UTEST_COMPARE_UINT( - zip_lfh->compress_method, - GMIO_ZIP_COMPRESS_METHOD_DEFLATE); - UTEST_ASSERT( - (zip_lfh->general_purpose_flags & - GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR) - != 0); - UTEST_COMPARE_UINT( - zip_lfh->filename_len, - zip_entry_filename_len); - UTEST_ASSERT(strncmp( - zip_lfh->filename, - zip_entry_filename, - zip_entry_filename_len) - == 0); - return NULL; -} - static const char* test_amf_write_doc_1_zip() { static const size_t wbuffsize = 8192; @@ -319,10 +297,10 @@ static const char* test_amf_write_doc_1_zip() UTEST_COMPARE_INT(error, GMIO_ERROR_OK); } - const size_t source_len = wbuff.pos; - const uint32_t crc32_amf_data = gmio_zlib_crc32(wbuff.ptr, source_len); - uint8_t* source = calloc(source_len, 1); - memcpy(source, wbuff.ptr, source_len); + const size_t amf_data_len = wbuff.pos; + const uint32_t crc32_amf_data = gmio_zlib_crc32(wbuff.ptr, amf_data_len); + uint8_t* amf_data = calloc(amf_data_len, 1); + memcpy(amf_data, wbuff.ptr, amf_data_len); { /* Write compressed(ZIP) */ wbuff.pos = 0; @@ -347,79 +325,45 @@ static const char* test_amf_write_doc_1_zip() wbuff.pos = 0; struct gmio_stream stream = gmio_stream_buffer(&wbuff); int error = GMIO_ERROR_OK; - /* -- Read ZIP local file header */ + /* -- Read ZIP end of central directory record */ + wbuff.pos = + zip_archive_len - GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD; + struct gmio_zip_end_of_central_directory_record zip_eocdr = {0}; + gmio_zip_read_end_of_central_directory_record(&stream, &zip_eocdr, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + /* -- Read ZIP central directory */ + wbuff.pos = zip_eocdr.central_dir_offset; + struct gmio_zip_central_directory_header zip_cdh = {0}; + gmio_zip_read_central_directory_header(&stream, &zip_cdh, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(amf_data_len, zip_cdh.uncompressed_size); + const uint32_t amf_zdata_len = zip_cdh.compressed_size; + /* -- Read(skip) ZIP local file header */ + wbuff.pos = 0; struct gmio_zip_local_file_header zip_lfh = {0}; const size_t lfh_read_len = gmio_zip_read_local_file_header(&stream, &zip_lfh, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - zip_lfh.filename = (const char*)wbuff.ptr + wbuff.pos; - const char* check_str = __tamf__check_zip_local_file_header(&zip_lfh); - if (check_str != NULL) - return check_str; - /* -- Read ZIP end of central directory record */ - static const size_t end_of_central_dir_record_len = 22; - wbuff.pos = zip_archive_len - end_of_central_dir_record_len;; - struct gmio_zip_end_of_central_directory_record zip_eocdr = {0}; - gmio_zip_read_end_of_central_directory_record( - &stream, &zip_eocdr, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT(zip_eocdr.entry_count, 1); - /* -- Read ZIP central directory */ - wbuff.pos = zip_eocdr.start_offset; - struct gmio_zip_central_directory_header zip_cdh = {0}; - gmio_zip_read_central_directory_header(&stream, &zip_cdh, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT( - zip_cdh.compress_method, - GMIO_ZIP_COMPRESS_METHOD_DEFLATE); - UTEST_ASSERT( - (zip_cdh.general_purpose_flags & - GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR) - != 0); - UTEST_COMPARE_UINT(crc32_amf_data, zip_cdh.crc32); - UTEST_COMPARE_UINT( - zip_cdh.filename_len, zip_entry_filename_len); - UTEST_ASSERT(strncmp( - (const char*)wbuff.ptr + wbuff.pos, - zip_entry_filename, - zip_entry_filename_len) - == 0); - /* -- Read compressed AMF data */ - const size_t pos_start_amf_data = - lfh_read_len + zip_lfh.filename_len + zip_lfh.extrafield_len; - wbuff.pos = pos_start_amf_data; + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + /* -- Read and check compressed AMF data */ + wbuff.pos = lfh_read_len + zip_lfh.filename_len + zip_lfh.extrafield_len; { - uint8_t* dest = calloc(zip_cdh.uncompressed_size, 1); - size_t dest_len = zip_cdh.uncompressed_size; - const int error = - gmio_zlib_uncompress_buffer( - dest, - &dest_len, - (const uint8_t*)wbuff.ptr + wbuff.pos, - zip_cdh.compressed_size); + uint8_t* dest = calloc(amf_data_len, 1); + size_t dest_len = amf_data_len; + const uint8_t* amf_zdata = (const uint8_t*)wbuff.ptr + wbuff.pos; + const int error = gmio_zlib_uncompress_buffer( + dest, &dest_len, amf_zdata, amf_zdata_len); printf("\n-- Info: z_len=%i src_len=%i\n", - zip_cdh.compressed_size, source_len); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT(source_len, dest_len); - UTEST_COMPARE_UINT(dest_len, zip_cdh.uncompressed_size); - UTEST_COMPARE_INT(memcmp(dest, source, source_len), 0); + amf_zdata_len, amf_data_len); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(dest_len, amf_data_len); + UTEST_COMPARE_INT(memcmp(dest, amf_data, amf_data_len), 0); const uint32_t crc32_uncomp = gmio_zlib_crc32(dest, dest_len); UTEST_COMPARE_UINT(crc32_amf_data, crc32_uncomp); free(dest); } - /* -- Read ZIP data descriptor */ - wbuff.pos = pos_start_amf_data + zip_cdh.compressed_size; - struct gmio_zip_data_descriptor zip_dd = {0}; - gmio_zip_read_data_descriptor(&stream, &zip_dd, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT(zip_dd.crc32, crc32_amf_data); - UTEST_COMPARE_UINT( - zip_dd.compressed_size, zip_cdh.compressed_size); - UTEST_COMPARE_UINT( - zip_dd.uncompressed_size, zip_cdh.uncompressed_size); } - free(source); + free(amf_data); free(wbuff.ptr); return NULL; } @@ -440,13 +384,8 @@ static const char* test_amf_write_doc_1_zip64() UTEST_COMPARE_INT(error, GMIO_ERROR_OK); } - const size_t source_len = wbuff.pos; - const uint32_t crc32_amf_data = gmio_zlib_crc32(wbuff.ptr, source_len); - uint8_t* source = calloc(source_len, 1); - memcpy(source, wbuff.ptr, source_len); + const uintmax_t amf_data_len = wbuff.pos; - static const char zip_entry_filename[] = "test.amf"; - static const uint16_t zip_entry_filename_len = sizeof(zip_entry_filename) - 1; { /* Write compressed(Zip64) */ wbuff.pos = 0; struct gmio_amf_write_options options = {0}; @@ -471,83 +410,32 @@ static const char* test_amf_write_doc_1_zip64() wbuff.pos = 0; struct gmio_stream stream = gmio_stream_buffer(&wbuff); int error = GMIO_ERROR_OK; - /* -- Read ZIP local file header */ - struct gmio_zip_local_file_header zip_lfh = {0}; - const size_t lfh_read_len = - gmio_zip_read_local_file_header(&stream, &zip_lfh, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - zip_lfh.filename = (const char*)wbuff.ptr + wbuff.pos; - const char* check_str = __tamf__check_zip_local_file_header(&zip_lfh); - if (check_str != NULL) - return check_str; - /* -- Read ZIP end of central directory record */ - static const size_t end_of_central_dir_record_len = 22; - wbuff.pos = zip_archive_len - end_of_central_dir_record_len;; - struct gmio_zip_end_of_central_directory_record zip_eocdr = {0}; - gmio_zip_read_end_of_central_directory_record( - &stream, &zip_eocdr, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT(zip_eocdr.entry_count, 0xFFFF); - UTEST_COMPARE_UINT(zip_eocdr.central_dir_size, 0xFFFFFFFF); - UTEST_COMPARE_UINT(zip_eocdr.start_offset, 0xFFFFFFFF); -#if 0 + /* -- Read Zip64 end of central directory record */ + wbuff.pos = + zip_archive_len + - GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD + - GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_LOCATOR + - GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD; + struct gmio_zip64_end_of_central_directory_record zip64_eocdr = {0}; + gmio_zip64_read_end_of_central_directory_record( + &stream, &zip64_eocdr, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); /* -- Read ZIP central directory */ - wbuff.pos = zip_eocdr.start_offset_central_dir_from_disk_start_nb; + wbuff.pos = zip64_eocdr.central_dir_offset; struct gmio_zip_central_directory_header zip_cdh = {0}; gmio_zip_read_central_directory_header(&stream, &zip_cdh, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT( - zip_cdh.compress_method, - GMIO_ZIP_COMPRESS_METHOD_DEFLATE); - UTEST_ASSERT( - (zip_cdh.general_purpose_flags & - GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR) - != 0); - UTEST_COMPARE_UINT(crc32_amf_data, zip_cdh.crc32); - UTEST_COMPARE_UINT( - zip_cdh.filename_len, zip_entry_filename_len); - UTEST_ASSERT(strncmp( - (const char*)wbuff.ptr + wbuff.pos, - zip_entry_filename, - zip_entry_filename_len) - == 0); - /* -- Read compressed AMF data */ - const size_t pos_start_amf_data = - lfh_read_len + zip_lfh.filename_len + zip_lfh.extrafield_len; - wbuff.pos = pos_start_amf_data; - { - uint8_t* dest = calloc(zip_cdh.uncompressed_size, 1); - size_t dest_len = zip_cdh.uncompressed_size; - const int error = - gmio_zlib_uncompress_buffer( - dest, - &dest_len, - (const uint8_t*)wbuff.ptr + wbuff.pos, - zip_cdh.compressed_size); - printf("\n-- Info: z_len=%i src_len=%i\n", - zip_cdh.compressed_size, source_len); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT(source_len, dest_len); - UTEST_COMPARE_UINT(dest_len, zip_cdh.uncompressed_size); - UTEST_COMPARE_INT(memcmp(dest, source, source_len), 0); - const uint32_t crc32_uncomp = gmio_zlib_crc32(dest, dest_len); - UTEST_COMPARE_UINT(crc32_amf_data, crc32_uncomp); - free(dest); - } - /* -- Read ZIP data descriptor */ - wbuff.pos = pos_start_amf_data + zip_cdh.compressed_size; - struct gmio_zip_data_descriptor zip_dd = {0}; - gmio_zip64_read_data_descriptor(&stream, &zip_dd, &error); - UTEST_COMPARE_INT(error, GMIO_ERROR_OK); - UTEST_COMPARE_UINT(zip_dd.crc32, crc32_amf_data); - UTEST_COMPARE_UINT( - zip_dd.compressed_size, zip_cdh.compressed_size); - UTEST_COMPARE_UINT( - zip_dd.uncompressed_size, zip_cdh.uncompressed_size); -#endif + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + /* -- Read ZIP central directory Zip64 extrafield*/ + wbuff.pos = + zip64_eocdr.central_dir_offset + + GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER + + zip_cdh.filename_len; + struct gmio_zip64_extrafield zip64_extra = {0}; + gmio_zip64_read_extrafield(&stream, &zip64_extra, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(amf_data_len, zip64_extra.uncompressed_size); } - free(source); free(wbuff.ptr); return NULL; } diff --git a/tests/test_core_internal.c b/tests/test_core_internal.c index 28d5c20..2c2b5a1 100644 --- a/tests/test_core_internal.c +++ b/tests/test_core_internal.c @@ -37,6 +37,7 @@ #include "../src/gmio_core/internal/convert.h" #include "../src/gmio_core/internal/error_check.h" #include "../src/gmio_core/internal/fast_atof.h" +#include "../src/gmio_core/internal/helper_stream.h" #include "../src/gmio_core/internal/locale_utils.h" #include "../src/gmio_core/internal/numeric_utils.h" #include "../src/gmio_core/internal/ostringstream.h" @@ -44,6 +45,8 @@ #include "../src/gmio_core/internal/stringstream.h" #include "../src/gmio_core/internal/stringstream_fast_atof.h" #include "../src/gmio_core/internal/string_ascii_utils.h" +#include "../src/gmio_core/internal/zip_utils.h" +#include "../src/gmio_core/internal/zlib_utils.h" #include #include @@ -531,3 +534,284 @@ static const char* test_internal__error_check() return NULL; } + +static void __tc__write_file(const char* filepath, uint8_t* bytes, size_t len) +{ + FILE* file = fopen(filepath, "wb"); + fwrite(bytes, 1, len, file); + fclose(file); +} + +struct __tc__func_write_file_data_cookie { + struct gmio_stream* stream; + const uint8_t* data; + const uint8_t* zdata; + uint32_t data_crc32; + size_t data_len; + size_t zdata_len; +}; + +static int __tc__write_zip_file_data( + void* cookie, struct gmio_zip_data_descriptor* dd) +{ + struct __tc__func_write_file_data_cookie* fcookie = + (struct __tc__func_write_file_data_cookie*)cookie; + gmio_stream_write_bytes(fcookie->stream, fcookie->zdata, fcookie->zdata_len); + dd->crc32 = fcookie->data_crc32; + dd->uncompressed_size = fcookie->data_len; + dd->compressed_size = fcookie->zdata_len; + return GMIO_ERROR_OK; +} + +static const char* __tc__zip_compare_entry( + const struct gmio_zip_file_entry* lhs, + const struct gmio_zip_file_entry* rhs) +{ + UTEST_COMPARE_UINT(lhs->compress_method, rhs->compress_method); + UTEST_COMPARE_UINT(lhs->feature_version, rhs->feature_version); + UTEST_COMPARE_UINT(lhs->filename_len, rhs->filename_len); + UTEST_ASSERT(strncmp(lhs->filename, rhs->filename, lhs->filename_len) == 0); + return NULL; +} + +static const char* test_internal__zip_utils() +{ + static const unsigned bytes_size = 1024; + uint8_t* bytes = calloc(bytes_size, 1); + struct gmio_rw_buffer wbuff = gmio_rw_buffer(bytes, bytes_size, 0); + struct gmio_stream stream = gmio_stream_buffer(&wbuff); + int error; + + /* Write empty ZIP file */ + { + struct gmio_zip_end_of_central_directory_record eocdr = {0}; + gmio_zip_write_end_of_central_directory_record(&stream, &eocdr, &error); + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); +#if 1 + __tc__write_file("test_output_empty.zip", wbuff.ptr, wbuff.pos); +#endif + } + + /* Write empty Zip64 file */ + wbuff.pos = 0; + { + struct gmio_zip64_end_of_central_directory_record eocdr64 = {0}; + eocdr64.version_needed_to_extract = + GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS; + gmio_zip64_write_end_of_central_directory_record( + &stream, &eocdr64, &error); + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); + + struct gmio_zip64_end_of_central_directory_locator eocdl64 = {0}; + gmio_zip64_write_end_of_central_directory_locator( + &stream, &eocdl64, &error); + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); + + struct gmio_zip_end_of_central_directory_record eocdr = {0}; + gmio_zip_write_end_of_central_directory_record(&stream, &eocdr, &error); + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); +#if 1 + __tc__write_file("test_output_empty_64.zip", wbuff.ptr, wbuff.pos); +#endif + } + + /* Common constants */ + static const char zip_entry_filedata[] = + "On ne fait bien que ce qu'on fait soi-même"; + struct __tc__func_write_file_data_cookie fcookie = {0}; + fcookie.stream = &stream; + fcookie.data = (const uint8_t*)zip_entry_filedata; + fcookie.zdata = fcookie.data; /* No compression */ + fcookie.data_len = GMIO_ARRAY_SIZE(zip_entry_filedata) - 1; + fcookie.zdata_len = fcookie.data_len; /* No compression */ + fcookie.data_crc32 = gmio_zlib_crc32(fcookie.data, fcookie.data_len); + static const char zip_entry_filename[] = "file.txt"; + static const uint16_t zip_entry_filename_len = + GMIO_ARRAY_SIZE(zip_entry_filename) - 1; + + /* Common variables */ + struct gmio_zip_file_entry entry = {0}; + entry.compress_method = GMIO_ZIP_COMPRESS_METHOD_NO_COMPRESSION; + entry.feature_version = GMIO_ZIP_FEATURE_VERSION_DEFAULT; + entry.filename = zip_entry_filename; + entry.filename_len = zip_entry_filename_len; + entry.cookie_func_write_file_data = &fcookie; + entry.func_write_file_data = __tc__write_zip_file_data; + + /* + * Write one-entry ZIP file + */ + { + wbuff.pos = 0; + entry.feature_version = GMIO_ZIP_FEATURE_VERSION_DEFAULT; + UTEST_ASSERT(gmio_zip_write_single_file(&stream, &entry, &error)); + UTEST_COMPARE_UINT(error, GMIO_ERROR_OK); +#if 1 + __tc__write_file("test_output_one_file.zip", wbuff.ptr, wbuff.pos); +#endif + + const uintmax_t zip_archive_len = wbuff.pos; + wbuff.pos = 0; + /* -- Read ZIP local file header */ + struct gmio_zip_local_file_header zip_lfh = {0}; + const size_t lfh_read_len = + gmio_zip_read_local_file_header(&stream, &zip_lfh, &error); + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); + struct gmio_zip_file_entry lfh_entry = {0}; + lfh_entry.compress_method = zip_lfh.compress_method; + lfh_entry.feature_version = zip_lfh.version_needed_to_extract; + lfh_entry.filename = (const char*)wbuff.ptr + wbuff.pos; + lfh_entry.filename_len = zip_lfh.filename_len; + const char* check_str = __tc__zip_compare_entry(&entry, &lfh_entry); + if (check_str != NULL) return check_str; + /* -- Read ZIP end of central directory record */ + wbuff.pos = + zip_archive_len - GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD; + struct gmio_zip_end_of_central_directory_record zip_eocdr = {0}; + gmio_zip_read_end_of_central_directory_record( + &stream, &zip_eocdr, &error); + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); + UTEST_COMPARE_UINT(zip_eocdr.entry_count, 1); + /* -- Read ZIP central directory */ + wbuff.pos = zip_eocdr.central_dir_offset; + struct gmio_zip_central_directory_header zip_cdh = {0}; + gmio_zip_read_central_directory_header(&stream, &zip_cdh, &error); + struct gmio_zip_file_entry cdh_entry = {0}; + cdh_entry.compress_method = zip_cdh.compress_method; + cdh_entry.feature_version = zip_cdh.version_needed_to_extract; + cdh_entry.filename = (const char*)wbuff.ptr + wbuff.pos; + cdh_entry.filename_len = zip_lfh.filename_len; + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); + UTEST_ASSERT((zip_cdh.general_purpose_flags & + GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR) + != 0); + UTEST_COMPARE_UINT(fcookie.data_crc32, zip_cdh.crc32); + UTEST_COMPARE_UINT(fcookie.data_len, zip_cdh.uncompressed_size); + UTEST_COMPARE_UINT(fcookie.zdata_len, zip_cdh.compressed_size); + UTEST_COMPARE_UINT(zip_cdh.local_header_offset, 0); + check_str = __tc__zip_compare_entry(&entry, &cdh_entry); + if (check_str != NULL) return check_str; + /* -- Read file data */ + const size_t pos_file_data = + lfh_read_len + zip_lfh.filename_len + zip_lfh.extrafield_len; + UTEST_ASSERT(strncmp((const char*)wbuff.ptr + pos_file_data, + (const char*)fcookie.zdata, + fcookie.zdata_len) + == 0); + /* -- Read ZIP data descriptor */ + wbuff.pos = pos_file_data + zip_cdh.compressed_size; + struct gmio_zip_data_descriptor zip_dd = {0}; + gmio_zip_read_data_descriptor(&stream, &zip_dd, &error); + UTEST_COMPARE_INT(error, GMIO_ERROR_OK); + UTEST_COMPARE_UINT(zip_dd.crc32, zip_cdh.crc32); + UTEST_COMPARE_UINT(zip_dd.compressed_size, zip_cdh.compressed_size); + UTEST_COMPARE_UINT(zip_dd.uncompressed_size, zip_cdh.uncompressed_size); + } + + /* + * Write one-entry Zip64 file + */ + { + wbuff.pos = 0; + entry.feature_version = + GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS; + UTEST_ASSERT(gmio_zip_write_single_file(&stream, &entry, &error)); + UTEST_COMPARE_UINT(error, GMIO_ERROR_OK); +#if 1 + __tc__write_file("test_output_one_file_64.zip", wbuff.ptr, wbuff.pos); +#endif + + const uintmax_t zip_archive_len = wbuff.pos; + /* -- Read ZIP end of central directory record */ + wbuff.pos = + zip_archive_len - GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD; + struct gmio_zip_end_of_central_directory_record zip_eocdr = {0}; + gmio_zip_read_end_of_central_directory_record( + &stream, &zip_eocdr, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(UINT16_MAX, zip_eocdr.entry_count); + UTEST_COMPARE_UINT(UINT32_MAX, zip_eocdr.central_dir_size); + UTEST_COMPARE_UINT(UINT32_MAX, zip_eocdr.central_dir_offset); + /* -- Read Zip64 end of central directory locator */ + wbuff.pos = + zip_archive_len + - GMIO_ZIP_SIZE_END_OF_CENTRAL_DIRECTORY_RECORD + - GMIO_ZIP64_SIZE_END_OF_CENTRAL_DIRECTORY_LOCATOR; + struct gmio_zip64_end_of_central_directory_locator zip64_eocdl = {0}; + gmio_zip64_read_end_of_central_directory_locator( + &stream, &zip64_eocdl, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + /* -- Read Zip64 end of central directory record */ + wbuff.pos = zip64_eocdl.zip64_end_of_central_dir_offset; + struct gmio_zip64_end_of_central_directory_record zip64_eocdr = {0}; + gmio_zip64_read_end_of_central_directory_record( + &stream, &zip64_eocdr, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT( + GMIO_ZIP_FEATURE_VERSION_FILE_ZIP64_FORMAT_EXTENSIONS, + zip64_eocdr.version_needed_to_extract); + UTEST_COMPARE_UINT(1, zip64_eocdr.entry_count); + /* -- Read ZIP central directory header */ + wbuff.pos = zip64_eocdr.central_dir_offset; + struct gmio_zip_central_directory_header zip_cdh = {0}; + size_t zip_cdh_len = + gmio_zip_read_central_directory_header(&stream, &zip_cdh, &error); + zip_cdh_len += + zip_cdh.filename_len + + zip_cdh.extrafield_len + + zip_cdh.filecomment_len; + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(zip64_eocdr.central_dir_size, zip_cdh_len); + UTEST_ASSERT((zip_cdh.general_purpose_flags & + GMIO_ZIP_GENERAL_PURPOSE_FLAG_USE_DATA_DESCRIPTOR) + != 0); + UTEST_COMPARE_UINT(fcookie.data_crc32, zip_cdh.crc32); + UTEST_COMPARE_UINT(UINT32_MAX, zip_cdh.uncompressed_size); + UTEST_COMPARE_UINT(UINT32_MAX, zip_cdh.compressed_size); + UTEST_COMPARE_UINT(UINT32_MAX, zip_cdh.local_header_offset); + struct gmio_zip_file_entry cdh_entry = {0}; + cdh_entry.compress_method = zip_cdh.compress_method; + cdh_entry.feature_version = zip_cdh.version_needed_to_extract; + cdh_entry.filename = (const char*)wbuff.ptr + wbuff.pos; + cdh_entry.filename_len = zip_cdh.filename_len; + const char* check_str = __tc__zip_compare_entry(&entry, &cdh_entry); + if (check_str != NULL) return check_str; + /* Read Zip64 extra field */ + wbuff.pos = + zip64_eocdr.central_dir_offset + + GMIO_ZIP_SIZE_CENTRAL_DIRECTORY_HEADER + + zip_cdh.filename_len; + struct gmio_zip64_extrafield zip64_extra = {0}; + gmio_zip64_read_extrafield(&stream, &zip64_extra, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(fcookie.data_len, zip64_extra.uncompressed_size); + UTEST_COMPARE_UINT(fcookie.zdata_len, zip64_extra.compressed_size); + UTEST_COMPARE_UINT(0, zip64_extra.local_header_offset); + /* Read ZIP local file header */ + wbuff.pos = 0; + struct gmio_zip_local_file_header zip_lfh = {0}; + gmio_zip_read_local_file_header(&stream, &zip_lfh, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_INT(0, zip_lfh.crc32); + UTEST_COMPARE_INT(0, zip_lfh.compressed_size); + UTEST_COMPARE_INT(0, zip_lfh.uncompressed_size); + /* Read ZIP local file header extrafield */ + wbuff.pos = GMIO_ZIP_SIZE_LOCAL_FILE_HEADER + zip_lfh.filename_len; + gmio_zip64_read_extrafield(&stream, &zip64_extra, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(0, zip64_extra.uncompressed_size); + UTEST_COMPARE_UINT(0, zip64_extra.compressed_size); + UTEST_COMPARE_UINT(0, zip64_extra.local_header_offset); + /* Read Zip64 data descriptor */ + wbuff.pos += fcookie.zdata_len; + struct gmio_zip_data_descriptor zip_dd = {0}; + gmio_zip64_read_data_descriptor(&stream, &zip_dd, &error); + UTEST_COMPARE_INT(GMIO_ERROR_OK, error); + UTEST_COMPARE_UINT(fcookie.data_crc32, zip_dd.crc32); + UTEST_COMPARE_UINT(fcookie.data_len, zip_dd.uncompressed_size); + UTEST_COMPARE_UINT(fcookie.zdata_len, zip_dd.compressed_size); + } + + free(bytes); + return NULL; +}