lib/getopt*.c: Include <config.h> only HAVE_CONFIG_H is defined.
[xz.git] / tests / test_lzip_decoder.c
blob3743d43412177c01836907ac8ad39225f525413c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file test_lzip_decoder.c
4 /// \brief Tests decoding lzip data
5 //
6 // Author: Jia Tan
7 //
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
13 #include "tests.h"
15 #ifdef HAVE_LZIP_DECODER
17 // Memlimit large enough to pass all of the test files
18 #define MEMLIMIT (1U << 20)
19 #define DECODE_CHUNK_SIZE 1024
22 // The uncompressed data in the test files are short US-ASCII strings.
23 // The tests check if the decompressed output is what it is expected to be.
24 // Storing the strings here as text would break the tests on EBCDIC systems
25 // and storing the strings as an array of hex values is inconvenient, so
26 // store the CRC32 values of the expected data instead.
28 // CRC32 value of "Hello\nWorld\n"
29 static const uint32_t hello_world_crc = 0x15A2A343;
31 // CRC32 value of "Trailing garbage\n"
32 static const uint32_t trailing_garbage_crc = 0x87081A60;
35 // Helper function to decode a good file with no flags and plenty high memlimit
36 static void
37 basic_lzip_decode(const char *src, const uint32_t expected_crc)
39 size_t file_size;
40 uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
41 uint32_t checksum = 0;
43 lzma_stream strm = LZMA_STREAM_INIT;
44 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, 0), LZMA_OK);
46 uint8_t *output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
48 strm.next_in = data;
49 strm.next_out = output_buffer;
50 strm.avail_out = DECODE_CHUNK_SIZE;
52 // Feed 1 byte at a time to the decoder to look for any bugs
53 // when switching between decoding sequences
54 lzma_ret ret = LZMA_OK;
55 while (ret == LZMA_OK) {
56 strm.avail_in = 1;
57 ret = lzma_code(&strm, LZMA_RUN);
58 if (strm.avail_out == 0) {
59 checksum = lzma_crc32(output_buffer,
60 (size_t)(strm.next_out - output_buffer),
61 checksum);
62 // No need to free output_buffer because it will
63 // automatically be freed at the end of the test by
64 // tuktest.
65 output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
66 strm.next_out = output_buffer;
67 strm.avail_out = DECODE_CHUNK_SIZE;
71 assert_lzma_ret(ret, LZMA_STREAM_END);
72 assert_uint_eq(strm.total_in, file_size);
74 checksum = lzma_crc32(output_buffer,
75 (size_t)(strm.next_out - output_buffer),
76 checksum);
77 assert_uint_eq(checksum, expected_crc);
79 lzma_end(&strm);
83 static void
84 test_options(void)
86 // Test NULL stream
87 assert_lzma_ret(lzma_lzip_decoder(NULL, MEMLIMIT, 0),
88 LZMA_PROG_ERROR);
90 // Test invalid flags
91 lzma_stream strm = LZMA_STREAM_INIT;
92 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, UINT32_MAX),
93 LZMA_OPTIONS_ERROR);
94 // Memlimit tests are done elsewhere
98 static void
99 test_v0_decode(void)
101 // This tests if liblzma can decode lzip version 0 files.
102 // lzip 1.17 and older can decompress this, but lzip 1.18
103 // and newer can no longer decode these files.
104 basic_lzip_decode("files/good-1-v0.lz", hello_world_crc);
108 static void
109 test_v1_decode(void)
111 // This tests decoding a basic lzip v1 file
112 basic_lzip_decode("files/good-1-v1.lz", hello_world_crc);
116 // Helper function to decode a good file with trailing bytes after
117 // the lzip stream
118 static void
119 trailing_helper(const char *src, const uint32_t expected_data_checksum,
120 const uint32_t expected_trailing_checksum)
122 size_t file_size;
123 uint32_t checksum = 0;
124 uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
125 lzma_stream strm = LZMA_STREAM_INIT;
126 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
127 LZMA_CONCATENATED), LZMA_OK);
129 uint8_t *output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
131 strm.next_in = data;
132 strm.next_out = output_buffer;
133 strm.avail_in = file_size;
134 strm.avail_out = DECODE_CHUNK_SIZE;
136 lzma_ret ret = LZMA_OK;
137 while (ret == LZMA_OK) {
138 ret = lzma_code(&strm, LZMA_RUN);
139 if (strm.avail_out == 0) {
140 checksum = lzma_crc32(output_buffer,
141 (size_t)(strm.next_out - output_buffer),
142 checksum);
143 // No need to free output_buffer because it will
144 // automatically be freed at the end of the test by
145 // tuktest.
146 output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
147 strm.next_out = output_buffer;
148 strm.avail_out = DECODE_CHUNK_SIZE;
152 assert_lzma_ret(ret, LZMA_STREAM_END);
153 assert_uint(strm.total_in, <, file_size);
155 checksum = lzma_crc32(output_buffer,
156 (size_t)(strm.next_out - output_buffer),
157 checksum);
159 assert_uint_eq(checksum, expected_data_checksum);
161 // Trailing data should be readable from strm.next_in
162 checksum = lzma_crc32(strm.next_in, strm.avail_in, 0);
163 assert_uint_eq(checksum, expected_trailing_checksum);
165 lzma_end(&strm);
169 // Helper function to decode a bad file and compare to returned error to
170 // what the caller expects
171 static void
172 decode_expect_error(const char *src, lzma_ret expected_error)
174 lzma_stream strm = LZMA_STREAM_INIT;
175 size_t file_size;
176 uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
178 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
179 LZMA_CONCATENATED), LZMA_OK);
181 uint8_t output_buffer[DECODE_CHUNK_SIZE];
183 strm.avail_in = file_size;
184 strm.next_in = data;
185 strm.avail_out = DECODE_CHUNK_SIZE;
186 strm.next_out = output_buffer;
188 lzma_ret ret = LZMA_OK;
190 while (ret == LZMA_OK) {
191 // Discard output since we are only looking for errors
192 strm.next_out = output_buffer;
193 strm.avail_out = DECODE_CHUNK_SIZE;
194 if (strm.avail_in == 0)
195 ret = lzma_code(&strm, LZMA_FINISH);
196 else
197 ret = lzma_code(&strm, LZMA_RUN);
200 assert_lzma_ret(ret, expected_error);
201 lzma_end(&strm);
205 static void
206 test_v0_trailing(void)
208 trailing_helper("files/good-1-v0-trailing-1.lz", hello_world_crc,
209 trailing_garbage_crc);
213 static void
214 test_v1_trailing(void)
216 trailing_helper("files/good-1-v1-trailing-1.lz", hello_world_crc,
217 trailing_garbage_crc);
219 // The second files/good-1-v1-trailing-2.lz will have the same
220 // expected output and trailing output as
221 // files/good-1-v1-trailing-1.lz, but this tests if the prefix
222 // to the trailing data contains lzip magic bytes.
223 // When this happens, the expected behavior is to silently ignore
224 // the magic byte prefix and consume it from the input file.
225 trailing_helper("files/good-1-v1-trailing-2.lz", hello_world_crc,
226 trailing_garbage_crc);
228 // Expect LZMA_BUF error if a file ends with the lzip magic bytes
229 // but does not contain any data after
230 decode_expect_error("files/bad-1-v1-trailing-magic.lz",
231 LZMA_BUF_ERROR);
235 static void
236 test_concatentated(void)
238 // First test a file with one v0 member and one v1 member
239 // The first member should contain "Hello\n" and
240 // the second member should contain "World!\n"
242 lzma_stream strm = LZMA_STREAM_INIT;
243 size_t file_size;
244 uint8_t *v0_v1 = tuktest_file_from_srcdir("files/good-2-v0-v1.lz",
245 &file_size);
247 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
248 LZMA_CONCATENATED), LZMA_OK);
250 uint8_t output_buffer[DECODE_CHUNK_SIZE];
252 strm.avail_in = file_size;
253 strm.next_in = v0_v1;
254 strm.avail_out = DECODE_CHUNK_SIZE;
255 strm.next_out = output_buffer;
257 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
259 assert_uint_eq(strm.total_in, file_size);
261 uint32_t checksum = lzma_crc32(output_buffer, strm.total_out, 0);
262 assert_uint_eq(checksum, hello_world_crc);
264 // The second file contains one v1 member and one v2 member
265 uint8_t *v1_v0 = tuktest_file_from_srcdir("files/good-2-v1-v0.lz",
266 &file_size);
268 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
269 LZMA_CONCATENATED), LZMA_OK);
271 strm.avail_in = file_size;
272 strm.next_in = v1_v0;
273 strm.avail_out = DECODE_CHUNK_SIZE;
274 strm.next_out = output_buffer;
276 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
278 assert_uint_eq(strm.total_in, file_size);
279 checksum = lzma_crc32(output_buffer, strm.total_out, 0);
280 assert_uint_eq(checksum, hello_world_crc);
282 // The third file contains 2 v1 members
283 uint8_t *v1_v1 = tuktest_file_from_srcdir("files/good-2-v1-v1.lz",
284 &file_size);
286 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
287 LZMA_CONCATENATED), LZMA_OK);
289 strm.avail_in = file_size;
290 strm.next_in = v1_v1;
291 strm.avail_out = DECODE_CHUNK_SIZE;
292 strm.next_out = output_buffer;
294 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
296 assert_uint_eq(strm.total_in, file_size);
297 checksum = lzma_crc32(output_buffer, strm.total_out, 0);
298 assert_uint_eq(checksum, hello_world_crc);
300 lzma_end(&strm);
304 static void
305 test_crc(void)
307 // Test invalid checksum
308 lzma_stream strm = LZMA_STREAM_INIT;
309 size_t file_size;
310 uint8_t *data = tuktest_file_from_srcdir("files/bad-1-v1-crc32.lz",
311 &file_size);
313 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
314 LZMA_CONCATENATED), LZMA_OK);
316 uint8_t output_buffer[DECODE_CHUNK_SIZE];
318 strm.avail_in = file_size;
319 strm.next_in = data;
320 strm.avail_out = DECODE_CHUNK_SIZE;
321 strm.next_out = output_buffer;
323 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR);
325 // Test ignoring the checksum value - should decode successfully
326 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
327 LZMA_CONCATENATED | LZMA_IGNORE_CHECK), LZMA_OK);
329 strm.avail_in = file_size;
330 strm.next_in = data;
331 strm.avail_out = DECODE_CHUNK_SIZE;
332 strm.next_out = output_buffer;
334 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
335 assert_uint_eq(strm.total_in, file_size);
337 // Test tell check
338 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
339 LZMA_CONCATENATED | LZMA_TELL_ANY_CHECK), LZMA_OK);
341 strm.avail_in = file_size;
342 strm.next_in = data;
343 strm.avail_out = DECODE_CHUNK_SIZE;
344 strm.next_out = output_buffer;
346 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_GET_CHECK);
347 assert_uint_eq(lzma_get_check(&strm), LZMA_CHECK_CRC32);
348 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR);
349 lzma_end(&strm);
353 static void
354 test_invalid_magic_bytes(void)
356 uint8_t lzip_id_string[] = { 0x4C, 0x5A, 0x49, 0x50 };
357 lzma_stream strm = LZMA_STREAM_INIT;
359 for (uint32_t i = 0; i < ARRAY_SIZE(lzip_id_string); i++) {
360 // Corrupt magic bytes
361 lzip_id_string[i] ^= 1;
362 uint8_t output_buffer[DECODE_CHUNK_SIZE];
364 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, 0),
365 LZMA_OK);
367 strm.next_in = lzip_id_string;
368 strm.avail_in = sizeof(lzip_id_string);
369 strm.next_out = output_buffer;
370 strm.avail_out = DECODE_CHUNK_SIZE;
372 assert_lzma_ret(lzma_code(&strm, LZMA_RUN),
373 LZMA_FORMAT_ERROR);
375 // Reset magic bytes
376 lzip_id_string[i] ^= 1;
379 lzma_end(&strm);
383 static void
384 test_invalid_version(void)
386 // The file contains a version number that is not 0 or 1,
387 // so it should cause an error
388 decode_expect_error("files/unsupported-1-v234.lz",
389 LZMA_OPTIONS_ERROR);
393 static void
394 test_invalid_dictionary_size(void)
396 // First file has too small dictionary size field
397 decode_expect_error("files/bad-1-v1-dict-1.lz", LZMA_DATA_ERROR);
399 // Second file has too large dictionary size field
400 decode_expect_error("files/bad-1-v1-dict-2.lz", LZMA_DATA_ERROR);
404 static void
405 test_invalid_uncomp_size(void)
407 // Test invalid v0 lzip file uncomp size
408 decode_expect_error("files/bad-1-v0-uncomp-size.lz",
409 LZMA_DATA_ERROR);
411 // Test invalid v1 lzip file uncomp size
412 decode_expect_error("files/bad-1-v1-uncomp-size.lz",
413 LZMA_DATA_ERROR);
417 static void
418 test_invalid_member_size(void)
420 decode_expect_error("files/bad-1-v1-member-size.lz",
421 LZMA_DATA_ERROR);
425 static void
426 test_invalid_memlimit(void)
428 // A very low memlimit should prevent decoding.
429 // Should be able to update the memlimit after failing
430 size_t file_size;
431 uint8_t *data = tuktest_file_from_srcdir("files/good-1-v1.lz",
432 &file_size);
434 uint8_t output_buffer[DECODE_CHUNK_SIZE];
436 lzma_stream strm = LZMA_STREAM_INIT;
438 assert_lzma_ret(lzma_lzip_decoder(&strm, 1, 0), LZMA_OK);
440 strm.next_in = data;
441 strm.avail_in = file_size;
442 strm.next_out = output_buffer;
443 strm.avail_out = DECODE_CHUNK_SIZE;
445 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEMLIMIT_ERROR);
447 // Up the memlimit so decoding can continue.
448 // First only increase by a small amount and expect an error
449 assert_lzma_ret(lzma_memlimit_set(&strm, 100), LZMA_MEMLIMIT_ERROR);
450 assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT), LZMA_OK);
452 // Finish decoding
453 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
455 assert_uint_eq(strm.total_in, file_size);
456 uint32_t checksum = lzma_crc32(output_buffer, strm.total_out, 0);
457 assert_uint_eq(checksum, hello_world_crc);
459 lzma_end(&strm);
461 #endif
464 extern int
465 main(int argc, char **argv)
467 tuktest_start(argc, argv);
469 #ifndef HAVE_LZIP_DECODER
470 tuktest_early_skip("lzip decoder disabled");
471 #else
472 tuktest_run(test_options);
473 tuktest_run(test_v0_decode);
474 tuktest_run(test_v1_decode);
475 tuktest_run(test_v0_trailing);
476 tuktest_run(test_v1_trailing);
477 tuktest_run(test_concatentated);
478 tuktest_run(test_crc);
479 tuktest_run(test_invalid_magic_bytes);
480 tuktest_run(test_invalid_version);
481 tuktest_run(test_invalid_dictionary_size);
482 tuktest_run(test_invalid_uncomp_size);
483 tuktest_run(test_invalid_member_size);
484 tuktest_run(test_invalid_memlimit);
485 return tuktest_end();
486 #endif