1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file test_block_header.c
6 /// \brief Tests Block Header coders
8 // Authors: Lasse Collin
11 ///////////////////////////////////////////////////////////////////////////////
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
22 #define RESET_BLOCK(block, buf) \
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; \
34 static lzma_filter filters_none
[1] = {
36 .id
= LZMA_VLI_UNKNOWN
,
41 static lzma_filter filters_one
[2] = {
43 .id
= LZMA_FILTER_LZMA2
,
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.
54 static lzma_filter filters_four
[5] = {
56 .id
= LZMA_FILTER_X86
,
59 .id
= LZMA_FILTER_X86
,
62 .id
= LZMA_FILTER_X86
,
65 .id
= LZMA_FILTER_LZMA2
,
68 .id
= LZMA_VLI_UNKNOWN
,
74 static lzma_filter filters_five
[6] = {
76 .id
= LZMA_FILTER_X86
,
79 .id
= LZMA_FILTER_X86
,
82 .id
= LZMA_FILTER_X86
,
85 .id
= LZMA_FILTER_X86
,
88 .id
= LZMA_FILTER_LZMA2
,
91 .id
= LZMA_VLI_UNKNOWN
,
98 test_lzma_block_header_size(void)
100 #ifndef HAVE_ENCODERS
101 assert_skip("Encoder support disabled");
103 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
))
104 assert_skip("x86 BCJ encoder is disabled");
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
++) {
123 assert_lzma_ret(lzma_block_header_size(&block
),
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));
185 lzma_filter bad_filters
[2] = {
187 .id
= LZMA_FILTER_LZMA2
,
191 .id
= LZMA_VLI_UNKNOWN
,
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);
217 test_lzma_block_header_encode(void)
219 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
220 assert_skip("Encoder or decoder support disabled");
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 "
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
++) {
244 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
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
),
254 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MIN
+ 2;
255 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
257 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MAX
+ 4;
258 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
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
),
266 block
.compressed_size
= LZMA_VLI_MAX
+ 1;
267 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
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
274 block
.compressed_size
= LZMA_VLI_MAX
;
275 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
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
),
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
),
290 block
.check
= LZMA_CHECK_CRC32
;
292 // Test invalid filters
293 block
.filters
= NULL
;
294 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
297 block
.filters
= filters_none
;
298 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
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
),
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
329 lzma_vli filter_id
= 0;
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
);
348 // Check null-padding
349 for (size_t i
= pos
; i
< header_size
- 4; i
++)
350 assert_uint_eq(out
[i
], 0);
353 assert_uint_eq(read32le(&out
[header_size
- 4]), lzma_crc32(out
,
354 header_size
- 4, 0));
359 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
360 // Helper function to compare two lzma_block structures field by field
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
,
379 expected_filter
= block_expected
->filters
[++filter_count
];
382 assert_uint_eq(block_actual
->filters
[filter_count
].id
,
389 test_lzma_block_header_decode(void)
391 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
392 assert_skip("Encoder or decoder support disabled");
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 "
400 .filters
= filters_one
,
401 .compressed_size
= LZMA_VLI_UNKNOWN
,
402 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
403 .check
= LZMA_CHECK_CRC32
,
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
= {
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
),
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
),
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
),
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
),
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
464 decoded_block
.version
= 2;
465 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
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
),
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
),
483 out
[decoded_block
.header_size
- 1] += 10;
485 // Test non-NULL padding
486 out
[decoded_block
.header_size
- 5] = 1;
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
),
494 // Test unsupported flags
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
),
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();