/////////////////////////////////////////////////////////////////////////////// // /// \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) { expect(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; expect(lzma_block_header_decode(&decoded_options, NULL, buf) == LZMA_OK); expect(known_options.compressed_size == decoded_options.compressed_size); expect(known_options.uncompressed_size == decoded_options.uncompressed_size); for (size_t i = 0; known_options.filters[i].id != LZMA_VLI_UNKNOWN; ++i) expect(known_options.filters[i].id == 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, }; expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR); known_options.filters = filters_none; expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR); known_options.filters = filters_five; expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR); known_options.filters = filters_one; expect(lzma_block_header_size(&known_options) == LZMA_OK); known_options.check = 999; // Some invalid value, which gets ignored. expect(lzma_block_header_size(&known_options) == LZMA_OK); known_options.compressed_size = 5; expect(lzma_block_header_size(&known_options) == LZMA_OK); known_options.compressed_size = 0; // Cannot be zero. expect(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; expect(lzma_block_header_size(&known_options) == LZMA_OK); known_options.compressed_size = LZMA_VLI_UNKNOWN; known_options.uncompressed_size = 0; expect(lzma_block_header_size(&known_options) == LZMA_OK); known_options.uncompressed_size = LZMA_VLI_MAX + 1; expect(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, }; expect(lzma_block_header_size(&known_options) == LZMA_OK); code(); known_options.compressed_size = 123456; known_options.uncompressed_size = 234567; expect(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, }; expect(lzma_block_header_size(&known_options) == LZMA_OK); known_options.header_size += 4; expect(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]; expect(lzma_block_header_decode(&decoded_options, NULL, buf) == LZMA_PROG_ERROR); --buf[0]; // Wrong CRC32 buf[known_options.header_size - 1] ^= 1; expect(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; unaligned_write32le(buf + known_options.header_size - 4, lzma_crc32(buf, known_options.header_size - 4, 0)); expect(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; unaligned_write32le(buf + known_options.header_size - 4, lzma_crc32(buf, known_options.header_size - 4, 0)); expect(lzma_block_header_decode(&decoded_options, NULL, buf) == LZMA_OPTIONS_ERROR); buf[known_options.header_size - 4 - 1] ^= 1; } int main(void) { succeed(lzma_lzma_preset(&opt_lzma, 1)); test1(); test2(); test3(); return 0; }