Translations: Update the Chinese (traditional) translation.
[xz/debian.git] / tests / test_lzip_decoder.c
blob42c730ad86b9c82b5338416b2879ac00dc26496a
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) {
38 size_t file_size;
39 uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
40 uint32_t checksum = 0;
42 lzma_stream strm = LZMA_STREAM_INIT;
43 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, 0), LZMA_OK);
45 uint8_t *output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
47 strm.next_in = data;
48 strm.next_out = output_buffer;
49 strm.avail_out = DECODE_CHUNK_SIZE;
51 // Feed 1 byte at a time to the decoder to look for any bugs
52 // when switching between decoding sequences
53 lzma_ret ret = LZMA_OK;
54 while (ret == LZMA_OK) {
55 strm.avail_in = 1;
56 ret = lzma_code(&strm, LZMA_RUN);
57 if (strm.avail_out == 0) {
58 checksum = lzma_crc32(output_buffer,
59 (size_t)(strm.next_out - output_buffer),
60 checksum);
61 // No need to free output_buffer because it will
62 // automatically be freed at the end of the test by
63 // tuktest.
64 output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
65 strm.next_out = output_buffer;
66 strm.avail_out = DECODE_CHUNK_SIZE;
70 assert_lzma_ret(ret, LZMA_STREAM_END);
71 assert_uint_eq(strm.total_in, file_size);
73 checksum = lzma_crc32(output_buffer,
74 (size_t)(strm.next_out - output_buffer),
75 checksum);
76 assert_uint_eq(checksum, expected_crc);
78 lzma_end(&strm);
82 static void
83 test_options(void)
85 // Test NULL stream
86 assert_lzma_ret(lzma_lzip_decoder(NULL, MEMLIMIT, 0),
87 LZMA_PROG_ERROR);
89 // Test invalid flags
90 lzma_stream strm = LZMA_STREAM_INIT;
91 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, UINT32_MAX),
92 LZMA_OPTIONS_ERROR);
93 // Memlimit tests are done elsewhere
97 static void
98 test_v0_decode(void) {
99 // This tests if liblzma can decode lzip version 0 files.
100 // lzip 1.17 and older can decompress this, but lzip 1.18
101 // and newer can no longer decode these files.
102 basic_lzip_decode("files/good-1-v0.lz", hello_world_crc);
106 static void
107 test_v1_decode(void) {
108 // This tests decoding a basic lzip v1 file
109 basic_lzip_decode("files/good-1-v1.lz", hello_world_crc);
113 // Helper function to decode a good file with trailing bytes after
114 // the lzip stream
115 static void
116 trailing_helper(const char *src, const uint32_t expected_data_checksum,
117 const uint32_t expected_trailing_checksum) {
118 size_t file_size;
119 uint32_t checksum = 0;
120 uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
121 lzma_stream strm = LZMA_STREAM_INIT;
122 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
123 LZMA_CONCATENATED), LZMA_OK);
125 uint8_t *output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
127 strm.next_in = data;
128 strm.next_out = output_buffer;
129 strm.avail_in = file_size;
130 strm.avail_out = DECODE_CHUNK_SIZE;
132 lzma_ret ret = LZMA_OK;
133 while (ret == LZMA_OK) {
134 ret = lzma_code(&strm, LZMA_RUN);
135 if (strm.avail_out == 0) {
136 checksum = lzma_crc32(output_buffer,
137 (size_t)(strm.next_out - output_buffer),
138 checksum);
139 // No need to free output_buffer because it will
140 // automatically be freed at the end of the test by
141 // tuktest.
142 output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
143 strm.next_out = output_buffer;
144 strm.avail_out = DECODE_CHUNK_SIZE;
148 assert_lzma_ret(ret, LZMA_STREAM_END);
149 assert_uint(strm.total_in, <, file_size);
151 checksum = lzma_crc32(output_buffer,
152 (size_t)(strm.next_out - output_buffer),
153 checksum);
155 assert_uint_eq(checksum, expected_data_checksum);
157 // Trailing data should be readable from strm.next_in
158 checksum = lzma_crc32(strm.next_in, strm.avail_in, 0);
159 assert_uint_eq(checksum, expected_trailing_checksum);
161 lzma_end(&strm);
165 // Helper function to decode a bad file and compare to returned error to
166 // what the caller expects
167 static void
168 decode_expect_error(const char *src, lzma_ret expected_error)
170 lzma_stream strm = LZMA_STREAM_INIT;
171 size_t file_size;
172 uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
174 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
175 LZMA_CONCATENATED), LZMA_OK);
177 uint8_t output_buffer[DECODE_CHUNK_SIZE];
179 strm.avail_in = file_size;
180 strm.next_in = data;
181 strm.avail_out = DECODE_CHUNK_SIZE;
182 strm.next_out = output_buffer;
184 lzma_ret ret = LZMA_OK;
186 while (ret == LZMA_OK) {
187 // Discard output since we are only looking for errors
188 strm.next_out = output_buffer;
189 strm.avail_out = DECODE_CHUNK_SIZE;
190 if (strm.avail_in == 0)
191 ret = lzma_code(&strm, LZMA_FINISH);
192 else
193 ret = lzma_code(&strm, LZMA_RUN);
196 assert_lzma_ret(ret, expected_error);
197 lzma_end(&strm);
201 static void
202 test_v0_trailing(void) {
203 trailing_helper("files/good-1-v0-trailing-1.lz", hello_world_crc,
204 trailing_garbage_crc);
208 static void
209 test_v1_trailing(void) {
210 trailing_helper("files/good-1-v1-trailing-1.lz", hello_world_crc,
211 trailing_garbage_crc);
213 // The second files/good-1-v1-trailing-2.lz will have the same
214 // expected output and trailing output as
215 // files/good-1-v1-trailing-1.lz, but this tests if the prefix
216 // to the trailing data contains lzip magic bytes.
217 // When this happens, the expected behavior is to silently ignore
218 // the magic byte prefix and consume it from the input file.
219 trailing_helper("files/good-1-v1-trailing-2.lz", hello_world_crc,
220 trailing_garbage_crc);
222 // Expect LZMA_BUF error if a file ends with the lzip magic bytes
223 // but does not contain any data after
224 decode_expect_error("files/bad-1-v1-trailing-magic.lz",
225 LZMA_BUF_ERROR);
229 static void
230 test_concatentated(void)
232 // First test a file with one v0 member and one v1 member
233 // The first member should contain "Hello\n" and
234 // the second member should contain "World!\n"
236 lzma_stream strm = LZMA_STREAM_INIT;
237 size_t file_size;
238 uint8_t *v0_v1 = tuktest_file_from_srcdir("files/good-2-v0-v1.lz",
239 &file_size);
241 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
242 LZMA_CONCATENATED), LZMA_OK);
244 uint8_t output_buffer[DECODE_CHUNK_SIZE];
246 strm.avail_in = file_size;
247 strm.next_in = v0_v1;
248 strm.avail_out = DECODE_CHUNK_SIZE;
249 strm.next_out = output_buffer;
251 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
253 assert_uint_eq(strm.total_in, file_size);
255 uint32_t checksum = lzma_crc32(output_buffer, strm.total_out, 0);
256 assert_uint_eq(checksum, hello_world_crc);
258 // The second file contains one v1 member and one v2 member
259 uint8_t *v1_v0 = tuktest_file_from_srcdir("files/good-2-v1-v0.lz",
260 &file_size);
262 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
263 LZMA_CONCATENATED), LZMA_OK);
265 strm.avail_in = file_size;
266 strm.next_in = v1_v0;
267 strm.avail_out = DECODE_CHUNK_SIZE;
268 strm.next_out = output_buffer;
270 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
272 assert_uint_eq(strm.total_in, file_size);
273 checksum = lzma_crc32(output_buffer, strm.total_out, 0);
274 assert_uint_eq(checksum, hello_world_crc);
276 // The third file contains 2 v1 members
277 uint8_t *v1_v1 = tuktest_file_from_srcdir("files/good-2-v1-v1.lz",
278 &file_size);
280 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
281 LZMA_CONCATENATED), LZMA_OK);
283 strm.avail_in = file_size;
284 strm.next_in = v1_v1;
285 strm.avail_out = DECODE_CHUNK_SIZE;
286 strm.next_out = output_buffer;
288 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
290 assert_uint_eq(strm.total_in, file_size);
291 checksum = lzma_crc32(output_buffer, strm.total_out, 0);
292 assert_uint_eq(checksum, hello_world_crc);
294 lzma_end(&strm);
298 static void
299 test_crc(void) {
300 // Test invalid checksum
301 lzma_stream strm = LZMA_STREAM_INIT;
302 size_t file_size;
303 uint8_t *data = tuktest_file_from_srcdir("files/bad-1-v1-crc32.lz",
304 &file_size);
306 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
307 LZMA_CONCATENATED), LZMA_OK);
309 uint8_t output_buffer[DECODE_CHUNK_SIZE];
311 strm.avail_in = file_size;
312 strm.next_in = data;
313 strm.avail_out = DECODE_CHUNK_SIZE;
314 strm.next_out = output_buffer;
316 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR);
318 // Test ignoring the checksum value - should decode successfully
319 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
320 LZMA_CONCATENATED | LZMA_IGNORE_CHECK), LZMA_OK);
322 strm.avail_in = file_size;
323 strm.next_in = data;
324 strm.avail_out = DECODE_CHUNK_SIZE;
325 strm.next_out = output_buffer;
327 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
328 assert_uint_eq(strm.total_in, file_size);
330 // Test tell check
331 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
332 LZMA_CONCATENATED | LZMA_TELL_ANY_CHECK), LZMA_OK);
334 strm.avail_in = file_size;
335 strm.next_in = data;
336 strm.avail_out = DECODE_CHUNK_SIZE;
337 strm.next_out = output_buffer;
339 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_GET_CHECK);
340 assert_uint_eq(lzma_get_check(&strm), LZMA_CHECK_CRC32);
341 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR);
342 lzma_end(&strm);
346 static void
347 test_invalid_magic_bytes(void) {
348 uint8_t lzip_id_string[] = { 0x4C, 0x5A, 0x49, 0x50 };
349 lzma_stream strm = LZMA_STREAM_INIT;
351 for (uint32_t i = 0; i < ARRAY_SIZE(lzip_id_string); i++) {
352 // Corrupt magic bytes
353 lzip_id_string[i] ^= 1;
354 uint8_t output_buffer[DECODE_CHUNK_SIZE];
356 assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, 0),
357 LZMA_OK);
359 strm.next_in = lzip_id_string;
360 strm.avail_in = sizeof(lzip_id_string);
361 strm.next_out = output_buffer;
362 strm.avail_out = DECODE_CHUNK_SIZE;
364 assert_lzma_ret(lzma_code(&strm, LZMA_RUN),
365 LZMA_FORMAT_ERROR);
367 // Reset magic bytes
368 lzip_id_string[i] ^= 1;
371 lzma_end(&strm);
375 static void
376 test_invalid_version(void)
378 // The file contains a version number that is not 0 or 1,
379 // so it should cause an error
380 decode_expect_error("files/unsupported-1-v234.lz",
381 LZMA_OPTIONS_ERROR);
385 static void
386 test_invalid_dictionary_size(void) {
387 // First file has too small dictionary size field
388 decode_expect_error("files/bad-1-v1-dict-1.lz", LZMA_DATA_ERROR);
390 // Second file has too large dictionary size field
391 decode_expect_error("files/bad-1-v1-dict-2.lz", LZMA_DATA_ERROR);
395 static void
396 test_invalid_uncomp_size(void) {
397 // Test invalid v0 lzip file uncomp size
398 decode_expect_error("files/bad-1-v0-uncomp-size.lz",
399 LZMA_DATA_ERROR);
401 // Test invalid v1 lzip file uncomp size
402 decode_expect_error("files/bad-1-v1-uncomp-size.lz",
403 LZMA_DATA_ERROR);
407 static void
408 test_invalid_member_size(void) {
409 decode_expect_error("files/bad-1-v1-member-size.lz",
410 LZMA_DATA_ERROR);
414 static void
415 test_invalid_memlimit(void) {
416 // A very low memlimit should prevent decoding.
417 // Should be able to update the memlimit after failing
418 size_t file_size;
419 uint8_t *data = tuktest_file_from_srcdir("files/good-1-v1.lz",
420 &file_size);
422 uint8_t output_buffer[DECODE_CHUNK_SIZE];
424 lzma_stream strm = LZMA_STREAM_INIT;
426 assert_lzma_ret(lzma_lzip_decoder(&strm, 1, 0), LZMA_OK);
428 strm.next_in = data;
429 strm.avail_in = file_size;
430 strm.next_out = output_buffer;
431 strm.avail_out = DECODE_CHUNK_SIZE;
433 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEMLIMIT_ERROR);
435 // Up the memlimit so decoding can continue.
436 // First only increase by a small amount and expect an error
437 assert_lzma_ret(lzma_memlimit_set(&strm, 100), LZMA_MEMLIMIT_ERROR);
438 assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT), LZMA_OK);
440 // Finish decoding
441 assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
443 assert_uint_eq(strm.total_in, file_size);
444 uint32_t checksum = lzma_crc32(output_buffer, strm.total_out, 0);
445 assert_uint_eq(checksum, hello_world_crc);
447 lzma_end(&strm);
449 #endif
452 extern int
453 main(int argc, char **argv)
455 tuktest_start(argc, argv);
457 #ifndef HAVE_LZIP_DECODER
458 tuktest_early_skip("lzip decoder disabled");
459 #else
460 tuktest_run(test_options);
461 tuktest_run(test_v0_decode);
462 tuktest_run(test_v1_decode);
463 tuktest_run(test_v0_trailing);
464 tuktest_run(test_v1_trailing);
465 tuktest_run(test_concatentated);
466 tuktest_run(test_crc);
467 tuktest_run(test_invalid_magic_bytes);
468 tuktest_run(test_invalid_version);
469 tuktest_run(test_invalid_dictionary_size);
470 tuktest_run(test_invalid_uncomp_size);
471 tuktest_run(test_invalid_member_size);
472 tuktest_run(test_invalid_memlimit);
473 return tuktest_end();
474 #endif