/////////////////////////////////////////////////////////////////////////////// // /// \file test_block_header.c /// \brief Tests Block Header coders // // Author: Lasse Collin // // This file has been put into the public domain. // You can do whatever you want with this file. // /////////////////////////////////////////////////////////////////////////////// #include "tests.h" static uint8_t buf[LZMA_BLOCK_HEADER_SIZE_MAX]; static lzma_block known_options; static lzma_block decoded_options; static lzma_options_lzma opt_lzma; static lzma_filter filters_none[1] = { { .id = LZMA_VLI_UNKNOWN, }, }; static lzma_filter filters_one[2] = { { .id = LZMA_FILTER_LZMA2, .options = &opt_lzma, }, { .id = LZMA_VLI_UNKNOWN, } }; static lzma_filter filters_four[5] = { { .id = LZMA_FILTER_X86, .options = NULL, }, { .id = LZMA_FILTER_X86, .options = NULL, }, { .id = LZMA_FILTER_X86, .options = NULL, }, { .id = LZMA_FILTER_LZMA2, .options = &opt_lzma, }, { .id = LZMA_VLI_UNKNOWN, } }; static lzma_filter filters_five[6] = { { .id = LZMA_FILTER_X86, .options = NULL, }, { .id = LZMA_FILTER_X86, .options = NULL, }, { .id = LZMA_FILTER_X86, .options = NULL, }, { .id = LZMA_FILTER_X86, .options = NULL, }, { .id = LZMA_FILTER_LZMA2, .options = &opt_lzma, }, { .id = LZMA_VLI_UNKNOWN, } }; static void code(void) { assert_lzma_ret(lzma_block_header_encode(&known_options, buf), LZMA_OK); lzma_filter filters[LZMA_FILTERS_MAX + 1]; memcrap(filters, sizeof(filters)); memcrap(&decoded_options, sizeof(decoded_options)); decoded_options.header_size = known_options.header_size; decoded_options.check = known_options.check; decoded_options.filters = filters; assert_lzma_ret(lzma_block_header_decode(&decoded_options, NULL, buf), LZMA_OK); assert_uint_eq(decoded_options.compressed_size, known_options.compressed_size); assert_uint_eq(decoded_options.uncompressed_size, known_options.uncompressed_size); for (size_t i = 0; known_options.filters[i].id != LZMA_VLI_UNKNOWN; ++i) assert_uint_eq(filters[i].id, known_options.filters[i].id); for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i) free(decoded_options.filters[i].options); } static void test1(void) { known_options = (lzma_block){ .check = LZMA_CHECK_NONE, .compressed_size = LZMA_VLI_UNKNOWN, .uncompressed_size = LZMA_VLI_UNKNOWN, .filters = NULL, }; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_PROG_ERROR); known_options.filters = filters_none; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_PROG_ERROR); known_options.filters = filters_five; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_PROG_ERROR); known_options.filters = filters_one; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); // Some invalid value, which gets ignored. known_options.check = (lzma_check)(99); assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); known_options.compressed_size = 5; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); known_options.compressed_size = 0; // Cannot be zero. assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_PROG_ERROR); // LZMA_VLI_MAX is too big to keep the total size of the Block // a valid VLI, but lzma_block_header_size() is not meant // to validate it. (lzma_block_header_encode() must validate it.) known_options.compressed_size = LZMA_VLI_MAX; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); known_options.compressed_size = LZMA_VLI_UNKNOWN; known_options.uncompressed_size = 0; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); known_options.uncompressed_size = LZMA_VLI_MAX + 1; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_PROG_ERROR); } static void test2(void) { known_options = (lzma_block){ .check = LZMA_CHECK_CRC32, .compressed_size = LZMA_VLI_UNKNOWN, .uncompressed_size = LZMA_VLI_UNKNOWN, .filters = filters_four, }; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); code(); known_options.compressed_size = 123456; known_options.uncompressed_size = 234567; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); code(); // We can make the sizes smaller while keeping the header size // the same. known_options.compressed_size = 12; known_options.uncompressed_size = 23; code(); } static void test3(void) { known_options = (lzma_block){ .check = LZMA_CHECK_CRC32, .compressed_size = LZMA_VLI_UNKNOWN, .uncompressed_size = LZMA_VLI_UNKNOWN, .filters = filters_one, }; assert_lzma_ret(lzma_block_header_size(&known_options), LZMA_OK); known_options.header_size += 4; assert_lzma_ret(lzma_block_header_encode(&known_options, buf), LZMA_OK); lzma_filter filters[LZMA_FILTERS_MAX + 1]; decoded_options.header_size = known_options.header_size; decoded_options.check = known_options.check; decoded_options.filters = filters; // Wrong size ++buf[0]; assert_lzma_ret(lzma_block_header_decode(&decoded_options, NULL, buf), LZMA_PROG_ERROR); --buf[0]; // Wrong CRC32 buf[known_options.header_size - 1] ^= 1; assert_lzma_ret(lzma_block_header_decode(&decoded_options, NULL, buf), LZMA_DATA_ERROR); buf[known_options.header_size - 1] ^= 1; // Unsupported filter // NOTE: This may need updating when new IDs become supported. buf[2] ^= 0x1F; write32le(buf + known_options.header_size - 4, lzma_crc32(buf, known_options.header_size - 4, 0)); assert_lzma_ret(lzma_block_header_decode(&decoded_options, NULL, buf), LZMA_OPTIONS_ERROR); buf[2] ^= 0x1F; // Non-nul Padding buf[known_options.header_size - 4 - 1] ^= 1; write32le(buf + known_options.header_size - 4, lzma_crc32(buf, known_options.header_size - 4, 0)); assert_lzma_ret(lzma_block_header_decode(&decoded_options, NULL, buf), LZMA_OPTIONS_ERROR); buf[known_options.header_size - 4 - 1] ^= 1; } extern int main(int argc, char **argv) { tuktest_start(argc, argv); if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86) || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86)) tuktest_early_skip("x86 BCJ encoder and/or decoder " "is disabled"); if (lzma_lzma_preset(&opt_lzma, 1)) tuktest_error("lzma_lzma_preset() failed"); tuktest_run(test1); tuktest_run(test2); tuktest_run(test3); return tuktest_end(); }