| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| /// \file test_bcj_exact_size.c | |
| /// \brief Tests BCJ decoding when the output size is known | |
| /// | |
| /// These tests fail with XZ Utils 5.0.3 and earlier. | |
| // | |
| // Author: Lasse Collin | |
| // | |
| // This file has been put into the public domain. | |
| // You can do whatever you want with this file. | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
| #include "tests.h" | |
| /// Something to be compressed | |
| static const uint8_t in[16] = "0123456789ABCDEF"; | |
| /// in[] after compression | |
| static uint8_t compressed[1024]; | |
| static size_t compressed_size = 0; | |
| /// Output buffer for decompressing compressed[] | |
| static uint8_t out[sizeof(in)]; | |
| static void | |
| compress(void) | |
| { | |
| // Compress with PowerPC BCJ and LZMA2. PowerPC BCJ is used because | |
| // it has fixed 4-byte alignment which makes triggering the potential | |
| // bug easy. | |
| lzma_options_lzma opt_lzma2; | |
| succeed(lzma_lzma_preset(&opt_lzma2, 0)); | |
| lzma_filter filters[3] = { | |
| { .id = LZMA_FILTER_POWERPC, .options = NULL }, | |
| { .id = LZMA_FILTER_LZMA2, .options = &opt_lzma2 }, | |
| { .id = LZMA_VLI_UNKNOWN, .options = NULL }, | |
| }; | |
| expect(lzma_stream_buffer_encode(filters, LZMA_CHECK_CRC32, NULL, | |
| in, sizeof(in), | |
| compressed, &compressed_size, sizeof(compressed)) | |
| == LZMA_OK); | |
| } | |
| static void | |
| decompress(void) | |
| { | |
| lzma_stream strm = LZMA_STREAM_INIT; | |
| expect(lzma_stream_decoder(&strm, 10 << 20, 0) == LZMA_OK); | |
| strm.next_in = compressed; | |
| strm.next_out = out; | |
| while (true) { | |
| if (strm.total_in < compressed_size) | |
| strm.avail_in = 1; | |
| const lzma_ret ret = lzma_code(&strm, LZMA_RUN); | |
| if (ret == LZMA_STREAM_END) { | |
| expect(strm.total_in == compressed_size); | |
| expect(strm.total_out == sizeof(in)); | |
| return; | |
| } | |
| expect(ret == LZMA_OK); | |
| if (strm.total_out < sizeof(in)) | |
| strm.avail_out = 1; | |
| } | |
| } | |
| static void | |
| decompress_empty(void) | |
| { | |
| // An empty file with one Block using PowerPC BCJ and LZMA2. | |
| static const uint8_t empty_bcj_lzma2[] = { | |
| 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, | |
| 0x69, 0x22, 0xDE, 0x36, 0x02, 0x01, 0x05, 0x00, | |
| 0x21, 0x01, 0x00, 0x00, 0x7F, 0xE0, 0xF1, 0xC8, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x01, 0x11, 0x00, 0x3B, 0x96, 0x5F, 0x73, | |
| 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, | |
| 0x00, 0x01, 0x59, 0x5A | |
| }; | |
| // Decompress without giving any output space. | |
| uint64_t memlimit = 1 << 20; | |
| size_t in_pos = 0; | |
| size_t out_pos = 0; | |
| expect(lzma_stream_buffer_decode(&memlimit, 0, NULL, | |
| empty_bcj_lzma2, &in_pos, sizeof(empty_bcj_lzma2), | |
| out, &out_pos, 0) == LZMA_OK); | |
| expect(in_pos == sizeof(empty_bcj_lzma2)); | |
| expect(out_pos == 0); | |
| } | |
| extern int | |
| main(void) | |
| { | |
| compress(); | |
| decompress(); | |
| decompress_empty(); | |
| return 0; | |
| } |