CI: update FreeBSD, NetBSD, OpenBSD, Solaris actions
[xz.git] / tests / test_block_header.c
blobd8e6221f31b10fbe06e6fca08a65b1d991e3d39b
1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file test_block_header.c
6 /// \brief Tests Block Header coders
7 //
8 // Authors: Lasse Collin
9 // Jia Tan
11 ///////////////////////////////////////////////////////////////////////////////
13 #include "tests.h"
16 static lzma_options_lzma opt_lzma;
19 // Used in test_lzma_block_header_decode() between tests to ensure
20 // no artifacts are leftover in the block struct that could influence
21 // later tests.
22 #define RESET_BLOCK(block, buf) \
23 do { \
24 lzma_filter *filters_ = (block).filters; \
25 lzma_filters_free(filters_, NULL); \
26 memzero((buf), sizeof((buf))); \
27 memzero(&(block), sizeof(lzma_block)); \
28 (block).filters = filters_; \
29 (block).check = LZMA_CHECK_CRC32; \
30 } while (0);
33 #ifdef HAVE_ENCODERS
34 static lzma_filter filters_none[1] = {
36 .id = LZMA_VLI_UNKNOWN,
41 static lzma_filter filters_one[2] = {
43 .id = LZMA_FILTER_LZMA2,
44 .options = &opt_lzma,
45 }, {
46 .id = LZMA_VLI_UNKNOWN,
51 // These filters are only used in test_lzma_block_header_decode()
52 // which only runs if encoders and decoders are configured.
53 #ifdef HAVE_DECODERS
54 static lzma_filter filters_four[5] = {
56 .id = LZMA_FILTER_X86,
57 .options = NULL,
58 }, {
59 .id = LZMA_FILTER_X86,
60 .options = NULL,
61 }, {
62 .id = LZMA_FILTER_X86,
63 .options = NULL,
64 }, {
65 .id = LZMA_FILTER_LZMA2,
66 .options = &opt_lzma,
67 }, {
68 .id = LZMA_VLI_UNKNOWN,
71 #endif
74 static lzma_filter filters_five[6] = {
76 .id = LZMA_FILTER_X86,
77 .options = NULL,
78 }, {
79 .id = LZMA_FILTER_X86,
80 .options = NULL,
81 }, {
82 .id = LZMA_FILTER_X86,
83 .options = NULL,
84 }, {
85 .id = LZMA_FILTER_X86,
86 .options = NULL,
87 }, {
88 .id = LZMA_FILTER_LZMA2,
89 .options = &opt_lzma,
90 }, {
91 .id = LZMA_VLI_UNKNOWN,
94 #endif
97 static void
98 test_lzma_block_header_size(void)
100 #ifndef HAVE_ENCODERS
101 assert_skip("Encoder support disabled");
102 #else
103 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86))
104 assert_skip("x86 BCJ encoder is disabled");
106 lzma_block block = {
107 .version = 0,
108 .filters = filters_one,
109 .compressed_size = LZMA_VLI_UNKNOWN,
110 .uncompressed_size = LZMA_VLI_UNKNOWN,
111 .check = LZMA_CHECK_CRC32
114 // Test that all initial options are valid
115 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
116 assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
117 assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
118 assert_uint_eq(block.header_size % 4, 0);
120 // Test invalid version number
121 for (uint32_t i = 2; i < 20; i++) {
122 block.version = i;
123 assert_lzma_ret(lzma_block_header_size(&block),
124 LZMA_OPTIONS_ERROR);
127 block.version = 1;
129 // Test invalid compressed size
130 block.compressed_size = 0;
131 assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
133 block.compressed_size = LZMA_VLI_MAX + 1;
134 assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
135 block.compressed_size = LZMA_VLI_UNKNOWN;
137 // Test invalid uncompressed size
138 block.uncompressed_size = LZMA_VLI_MAX + 1;
139 assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
140 block.uncompressed_size = LZMA_VLI_MAX;
142 // Test invalid filters
143 block.filters = NULL;
144 assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
146 block.filters = filters_none;
147 assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
149 block.filters = filters_five;
150 assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
152 block.filters = filters_one;
154 // Test setting compressed_size to something valid
155 block.compressed_size = 4096;
156 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
157 assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
158 assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
159 assert_uint_eq(block.header_size % 4, 0);
161 // Test setting uncompressed_size to something valid
162 block.uncompressed_size = 4096;
163 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
164 assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
165 assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
166 assert_uint_eq(block.header_size % 4, 0);
168 // This should pass, but header_size will be an invalid value
169 // because the total block size will not be able to fit in a valid
170 // lzma_vli. This way a temporary value can be used to reserve
171 // space for the header and later the actual value can be set.
172 block.compressed_size = LZMA_VLI_MAX;
173 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
174 assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
175 assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
176 assert_uint_eq(block.header_size % 4, 0);
178 // Use an invalid value for a filter option. This should still pass
179 // because the size of the LZMA2 properties is known by liblzma
180 // without reading any of the options so it doesn't validate them.
181 lzma_options_lzma bad_ops;
182 assert_false(lzma_lzma_preset(&bad_ops, 1));
183 bad_ops.pb = 0x1000;
185 lzma_filter bad_filters[2] = {
187 .id = LZMA_FILTER_LZMA2,
188 .options = &bad_ops
191 .id = LZMA_VLI_UNKNOWN,
192 .options = NULL
196 block.filters = bad_filters;
198 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
199 assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
200 assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
201 assert_uint_eq(block.header_size % 4, 0);
203 // Use an invalid block option. The check type isn't stored in
204 // the Block Header and so _header_size ignores it.
205 block.check = INVALID_LZMA_CHECK_ID;
206 block.ignore_check = false;
208 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
209 assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
210 assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
211 assert_uint_eq(block.header_size % 4, 0);
212 #endif
216 static void
217 test_lzma_block_header_encode(void)
219 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
220 assert_skip("Encoder or decoder support disabled");
221 #else
223 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86)
224 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86))
225 assert_skip("x86 BCJ encoder and/or decoder "
226 "is disabled");
228 lzma_block block = {
229 .version = 1,
230 .filters = filters_one,
231 .compressed_size = LZMA_VLI_UNKNOWN,
232 .uncompressed_size = LZMA_VLI_UNKNOWN,
233 .check = LZMA_CHECK_CRC32,
236 // Ensure all block options are valid before changes are tested
237 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
239 uint8_t out[LZMA_BLOCK_HEADER_SIZE_MAX];
241 // Test invalid block version
242 for (uint32_t i = 2; i < 20; i++) {
243 block.version = i;
244 assert_lzma_ret(lzma_block_header_encode(&block, out),
245 LZMA_PROG_ERROR);
248 block.version = 1;
250 // Test invalid header size (< min, > max, % 4 != 0)
251 block.header_size = LZMA_BLOCK_HEADER_SIZE_MIN - 4;
252 assert_lzma_ret(lzma_block_header_encode(&block, out),
253 LZMA_PROG_ERROR);
254 block.header_size = LZMA_BLOCK_HEADER_SIZE_MIN + 2;
255 assert_lzma_ret(lzma_block_header_encode(&block, out),
256 LZMA_PROG_ERROR);
257 block.header_size = LZMA_BLOCK_HEADER_SIZE_MAX + 4;
258 assert_lzma_ret(lzma_block_header_encode(&block, out),
259 LZMA_PROG_ERROR);
260 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
262 // Test invalid compressed_size
263 block.compressed_size = 0;
264 assert_lzma_ret(lzma_block_header_encode(&block, out),
265 LZMA_PROG_ERROR);
266 block.compressed_size = LZMA_VLI_MAX + 1;
267 assert_lzma_ret(lzma_block_header_encode(&block, out),
268 LZMA_PROG_ERROR);
270 // This test passes test_lzma_block_header_size, but should
271 // fail here because there is not enough space to encode the
272 // proper block size because the total size is too big to fit
273 // in an lzma_vli
274 block.compressed_size = LZMA_VLI_MAX;
275 assert_lzma_ret(lzma_block_header_encode(&block, out),
276 LZMA_PROG_ERROR);
277 block.compressed_size = LZMA_VLI_UNKNOWN;
279 // Test invalid uncompressed size
280 block.uncompressed_size = LZMA_VLI_MAX + 1;
281 assert_lzma_ret(lzma_block_header_encode(&block, out),
282 LZMA_PROG_ERROR);
283 block.uncompressed_size = LZMA_VLI_UNKNOWN;
285 // Test invalid block check
286 block.check = INVALID_LZMA_CHECK_ID;
287 block.ignore_check = false;
288 assert_lzma_ret(lzma_block_header_encode(&block, out),
289 LZMA_PROG_ERROR);
290 block.check = LZMA_CHECK_CRC32;
292 // Test invalid filters
293 block.filters = NULL;
294 assert_lzma_ret(lzma_block_header_encode(&block, out),
295 LZMA_PROG_ERROR);
297 block.filters = filters_none;
298 assert_lzma_ret(lzma_block_header_encode(&block, out),
299 LZMA_PROG_ERROR);
301 block.filters = filters_five;
302 block.header_size = LZMA_BLOCK_HEADER_SIZE_MAX - 4;
303 assert_lzma_ret(lzma_block_header_encode(&block, out),
304 LZMA_PROG_ERROR);
306 // Test valid encoding and verify bytes of block header.
307 // More complicated tests for encoding headers are included
308 // in test_lzma_block_header_decode.
309 block.filters = filters_one;
310 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
311 assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
313 // First read block header size from out and verify
314 // that it == (encoded size + 1) * 4
315 uint32_t header_size = (out[0] + 1U) * 4;
316 assert_uint_eq(header_size, block.header_size);
318 // Next read block flags
319 uint8_t flags = out[1];
321 // Should have number of filters = 1
322 assert_uint_eq((flags & 0x3) + 1U, 1);
324 // Bits 2-7 must be empty not set
325 assert_uint_eq(flags & (0xFF - 0x3), 0);
327 // Verify filter flags
328 // Decode Filter ID
329 lzma_vli filter_id = 0;
330 size_t pos = 2;
331 assert_lzma_ret(lzma_vli_decode(&filter_id, NULL, out,
332 &pos, header_size), LZMA_OK);
333 assert_uint_eq(filter_id, filters_one[0].id);
335 // Decode Size of Properties
336 lzma_vli prop_size = 0;
337 assert_lzma_ret(lzma_vli_decode(&prop_size, NULL, out,
338 &pos, header_size), LZMA_OK);
340 // LZMA2 has 1 byte prop size
341 assert_uint_eq(prop_size, 1);
342 uint8_t expected_filter_props = 0;
343 assert_lzma_ret(lzma_properties_encode(filters_one,
344 &expected_filter_props), LZMA_OK);
345 assert_uint_eq(out[pos], expected_filter_props);
346 pos++;
348 // Check null-padding
349 for (size_t i = pos; i < header_size - 4; i++)
350 assert_uint_eq(out[i], 0);
352 // Check CRC32
353 assert_uint_eq(read32le(&out[header_size - 4]), lzma_crc32(out,
354 header_size - 4, 0));
355 #endif
359 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
360 // Helper function to compare two lzma_block structures field by field
361 static void
362 compare_blocks(lzma_block *block_expected, lzma_block *block_actual)
364 assert_uint_eq(block_actual->version, block_expected->version);
365 assert_uint_eq(block_actual->compressed_size,
366 block_expected->compressed_size);
367 assert_uint_eq(block_actual->uncompressed_size,
368 block_expected->uncompressed_size);
369 assert_uint_eq(block_actual->check, block_expected->check);
370 assert_uint_eq(block_actual->header_size, block_expected->header_size);
372 // Compare filter IDs
373 assert_true(block_expected->filters && block_actual->filters);
374 lzma_filter expected_filter = block_expected->filters[0];
375 uint32_t filter_count = 0;
376 while (expected_filter.id != LZMA_VLI_UNKNOWN) {
377 assert_uint_eq(block_actual->filters[filter_count].id,
378 expected_filter.id);
379 expected_filter = block_expected->filters[++filter_count];
382 assert_uint_eq(block_actual->filters[filter_count].id,
383 LZMA_VLI_UNKNOWN);
385 #endif
388 static void
389 test_lzma_block_header_decode(void)
391 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
392 assert_skip("Encoder or decoder support disabled");
393 #else
394 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86)
395 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86))
396 assert_skip("x86 BCJ encoder and/or decoder "
397 "is disabled");
399 lzma_block block = {
400 .filters = filters_one,
401 .compressed_size = LZMA_VLI_UNKNOWN,
402 .uncompressed_size = LZMA_VLI_UNKNOWN,
403 .check = LZMA_CHECK_CRC32,
404 .version = 0
407 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
409 // Encode block header with simple options
410 uint8_t out[LZMA_BLOCK_HEADER_SIZE_MAX];
411 assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
413 // Decode block header and check that the options match
414 lzma_filter decoded_filters[LZMA_FILTERS_MAX + 1];
415 lzma_block decoded_block = {
416 .version = 0,
417 .filters = decoded_filters,
418 .check = LZMA_CHECK_CRC32
420 decoded_block.header_size = lzma_block_header_size_decode(out[0]);
422 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
423 LZMA_OK);
424 compare_blocks(&block, &decoded_block);
426 // Reset output buffer and decoded_block
427 RESET_BLOCK(decoded_block, out);
429 // Test with compressed size set
430 block.compressed_size = 4096;
431 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
432 assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
433 decoded_block.header_size = lzma_block_header_size_decode(out[0]);
434 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
435 LZMA_OK);
436 compare_blocks(&block, &decoded_block);
438 RESET_BLOCK(decoded_block, out);
440 // Test with uncompressed size set
441 block.uncompressed_size = 4096;
442 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
443 assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
444 decoded_block.header_size = lzma_block_header_size_decode(out[0]);
445 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
446 LZMA_OK);
447 compare_blocks(&block, &decoded_block);
449 RESET_BLOCK(decoded_block, out);
451 // Test with multiple filters
452 block.filters = filters_four;
453 assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
454 assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
455 decoded_block.header_size = lzma_block_header_size_decode(out[0]);
456 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
457 LZMA_OK);
458 compare_blocks(&block, &decoded_block);
460 lzma_filters_free(decoded_filters, NULL);
462 // Test with too high version. The decoder will set it to a version
463 // that it supports.
464 decoded_block.version = 2;
465 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
466 LZMA_OK);
467 assert_uint_eq(decoded_block.version, 1);
469 // Free the filters for the last time since all other cases should
470 // result in an error.
471 lzma_filters_free(decoded_filters, NULL);
473 // Test bad check type
474 decoded_block.check = INVALID_LZMA_CHECK_ID;
475 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
476 LZMA_PROG_ERROR);
477 decoded_block.check = LZMA_CHECK_CRC32;
479 // Test bad check value
480 out[decoded_block.header_size - 1] -= 10;
481 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
482 LZMA_DATA_ERROR);
483 out[decoded_block.header_size - 1] += 10;
485 // Test non-NULL padding
486 out[decoded_block.header_size - 5] = 1;
488 // Recompute CRC32
489 write32le(&out[decoded_block.header_size - 4], lzma_crc32(out,
490 decoded_block.header_size - 4, 0));
491 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
492 LZMA_OPTIONS_ERROR);
494 // Test unsupported flags
495 out[1] = 0xFF;
497 // Recompute CRC32
498 write32le(&out[decoded_block.header_size - 4], lzma_crc32(out,
499 decoded_block.header_size - 4, 0));
500 assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
501 LZMA_OPTIONS_ERROR);
502 #endif
506 extern int
507 main(int argc, char **argv)
509 tuktest_start(argc, argv);
511 if (lzma_lzma_preset(&opt_lzma, 1))
512 tuktest_error("lzma_lzma_preset() failed");
514 tuktest_run(test_lzma_block_header_size);
515 tuktest_run(test_lzma_block_header_encode);
516 tuktest_run(test_lzma_block_header_decode);
518 return tuktest_end();