1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file test_block_header.c
4 /// \brief Tests Block Header coders
6 // Authors: Lasse Collin
9 // This file has been put into the public domain.
10 // You can do whatever you want with this file.
12 ///////////////////////////////////////////////////////////////////////////////
17 static lzma_options_lzma opt_lzma
;
20 // Used in test_lzma_block_header_decode() between tests to ensure
21 // no artifacts are leftover in the block struct that could influence
23 #define RESET_BLOCK(block, buf) \
25 lzma_filter *filters_ = (block).filters; \
26 lzma_filters_free(filters_, NULL); \
27 memzero((buf), sizeof((buf))); \
28 memzero(&(block), sizeof(lzma_block)); \
29 (block).filters = filters_; \
30 (block).check = LZMA_CHECK_CRC32; \
35 static lzma_filter filters_none
[1] = {
37 .id
= LZMA_VLI_UNKNOWN
,
42 static lzma_filter filters_one
[2] = {
44 .id
= LZMA_FILTER_LZMA2
,
47 .id
= LZMA_VLI_UNKNOWN
,
52 // These filters are only used in test_lzma_block_header_decode()
53 // which only runs if encoders and decoders are configured.
55 static lzma_filter filters_four
[5] = {
57 .id
= LZMA_FILTER_X86
,
60 .id
= LZMA_FILTER_X86
,
63 .id
= LZMA_FILTER_X86
,
66 .id
= LZMA_FILTER_LZMA2
,
69 .id
= LZMA_VLI_UNKNOWN
,
75 static lzma_filter filters_five
[6] = {
77 .id
= LZMA_FILTER_X86
,
80 .id
= LZMA_FILTER_X86
,
83 .id
= LZMA_FILTER_X86
,
86 .id
= LZMA_FILTER_X86
,
89 .id
= LZMA_FILTER_LZMA2
,
92 .id
= LZMA_VLI_UNKNOWN
,
99 test_lzma_block_header_size(void)
101 #ifndef HAVE_ENCODERS
102 assert_skip("Encoder support disabled");
104 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
))
105 assert_skip("x86 BCJ encoder is disabled");
109 .filters
= filters_one
,
110 .compressed_size
= LZMA_VLI_UNKNOWN
,
111 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
112 .check
= LZMA_CHECK_CRC32
115 // Test that all initial options are valid
116 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
117 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
118 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
119 assert_uint_eq(block
.header_size
% 4, 0);
121 // Test invalid version number
122 for (uint32_t i
= 2; i
< 20; i
++) {
124 assert_lzma_ret(lzma_block_header_size(&block
),
130 // Test invalid compressed size
131 block
.compressed_size
= 0;
132 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
134 block
.compressed_size
= LZMA_VLI_MAX
+ 1;
135 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
136 block
.compressed_size
= LZMA_VLI_UNKNOWN
;
138 // Test invalid uncompressed size
139 block
.uncompressed_size
= LZMA_VLI_MAX
+ 1;
140 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
141 block
.uncompressed_size
= LZMA_VLI_MAX
;
143 // Test invalid filters
144 block
.filters
= NULL
;
145 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
147 block
.filters
= filters_none
;
148 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
150 block
.filters
= filters_five
;
151 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
153 block
.filters
= filters_one
;
155 // Test setting compressed_size to something valid
156 block
.compressed_size
= 4096;
157 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
158 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
159 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
160 assert_uint_eq(block
.header_size
% 4, 0);
162 // Test setting uncompressed_size to something valid
163 block
.uncompressed_size
= 4096;
164 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
165 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
166 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
167 assert_uint_eq(block
.header_size
% 4, 0);
169 // This should pass, but header_size will be an invalid value
170 // because the total block size will not be able to fit in a valid
171 // lzma_vli. This way a temporary value can be used to reserve
172 // space for the header and later the actual value can be set.
173 block
.compressed_size
= LZMA_VLI_MAX
;
174 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
175 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
176 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
177 assert_uint_eq(block
.header_size
% 4, 0);
179 // Use an invalid value for a filter option. This should still pass
180 // because the size of the LZMA2 properties is known by liblzma
181 // without reading any of the options so it doesn't validate them.
182 lzma_options_lzma bad_ops
;
183 assert_false(lzma_lzma_preset(&bad_ops
, 1));
186 lzma_filter bad_filters
[2] = {
188 .id
= LZMA_FILTER_LZMA2
,
192 .id
= LZMA_VLI_UNKNOWN
,
197 block
.filters
= bad_filters
;
199 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
200 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
201 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
202 assert_uint_eq(block
.header_size
% 4, 0);
204 // Use an invalid block option. The check type isn't stored in
205 // the Block Header and so _header_size ignores it.
206 block
.check
= INVALID_LZMA_CHECK_ID
;
207 block
.ignore_check
= false;
209 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
210 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
211 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
212 assert_uint_eq(block
.header_size
% 4, 0);
218 test_lzma_block_header_encode(void)
220 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
221 assert_skip("Encoder or decoder support disabled");
224 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
)
225 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86
))
226 assert_skip("x86 BCJ encoder and/or decoder "
231 .filters
= filters_one
,
232 .compressed_size
= LZMA_VLI_UNKNOWN
,
233 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
234 .check
= LZMA_CHECK_CRC32
,
237 // Ensure all block options are valid before changes are tested
238 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
240 uint8_t out
[LZMA_BLOCK_HEADER_SIZE_MAX
];
242 // Test invalid block version
243 for (uint32_t i
= 2; i
< 20; i
++) {
245 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
251 // Test invalid header size (< min, > max, % 4 != 0)
252 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MIN
- 4;
253 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
255 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MIN
+ 2;
256 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
258 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MAX
+ 4;
259 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
261 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
263 // Test invalid compressed_size
264 block
.compressed_size
= 0;
265 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
267 block
.compressed_size
= LZMA_VLI_MAX
+ 1;
268 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
271 // This test passes test_lzma_block_header_size, but should
272 // fail here because there is not enough space to encode the
273 // proper block size because the total size is too big to fit
275 block
.compressed_size
= LZMA_VLI_MAX
;
276 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
278 block
.compressed_size
= LZMA_VLI_UNKNOWN
;
280 // Test invalid uncompressed size
281 block
.uncompressed_size
= LZMA_VLI_MAX
+ 1;
282 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
284 block
.uncompressed_size
= LZMA_VLI_UNKNOWN
;
286 // Test invalid block check
287 block
.check
= INVALID_LZMA_CHECK_ID
;
288 block
.ignore_check
= false;
289 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
291 block
.check
= LZMA_CHECK_CRC32
;
293 // Test invalid filters
294 block
.filters
= NULL
;
295 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
298 block
.filters
= filters_none
;
299 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
302 block
.filters
= filters_five
;
303 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MAX
- 4;
304 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
307 // Test valid encoding and verify bytes of block header.
308 // More complicated tests for encoding headers are included
309 // in test_lzma_block_header_decode.
310 block
.filters
= filters_one
;
311 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
312 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
314 // First read block header size from out and verify
315 // that it == (encoded size + 1) * 4
316 uint32_t header_size
= (out
[0] + 1U) * 4;
317 assert_uint_eq(header_size
, block
.header_size
);
319 // Next read block flags
320 uint8_t flags
= out
[1];
322 // Should have number of filters = 1
323 assert_uint_eq((flags
& 0x3) + 1, 1);
325 // Bits 2-7 must be empty not set
326 assert_uint_eq(flags
& (0xFF - 0x3), 0);
328 // Verify filter flags
330 lzma_vli filter_id
= 0;
332 assert_lzma_ret(lzma_vli_decode(&filter_id
, NULL
, out
,
333 &pos
, header_size
), LZMA_OK
);
334 assert_uint_eq(filter_id
, filters_one
[0].id
);
336 // Decode Size of Properties
337 lzma_vli prop_size
= 0;
338 assert_lzma_ret(lzma_vli_decode(&prop_size
, NULL
, out
,
339 &pos
, header_size
), LZMA_OK
);
341 // LZMA2 has 1 byte prop size
342 assert_uint_eq(prop_size
, 1);
343 uint8_t expected_filter_props
= 0;
344 assert_lzma_ret(lzma_properties_encode(filters_one
,
345 &expected_filter_props
), LZMA_OK
);
346 assert_uint_eq(out
[pos
], expected_filter_props
);
349 // Check null-padding
350 for (size_t i
= pos
; i
< header_size
- 4; i
++)
351 assert_uint_eq(out
[i
], 0);
354 assert_uint_eq(read32le(&out
[header_size
- 4]), lzma_crc32(out
,
355 header_size
- 4, 0));
360 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
361 // Helper function to compare two lzma_block structures field by field
363 compare_blocks(lzma_block
*block_expected
, lzma_block
*block_actual
)
365 assert_uint_eq(block_actual
->version
, block_expected
->version
);
366 assert_uint_eq(block_actual
->compressed_size
,
367 block_expected
->compressed_size
);
368 assert_uint_eq(block_actual
->uncompressed_size
,
369 block_expected
->uncompressed_size
);
370 assert_uint_eq(block_actual
->check
, block_expected
->check
);
371 assert_uint_eq(block_actual
->header_size
, block_expected
->header_size
);
373 // Compare filter IDs
374 assert_true(block_expected
->filters
&& block_actual
->filters
);
375 lzma_filter expected_filter
= block_expected
->filters
[0];
376 uint32_t filter_count
= 0;
377 while (expected_filter
.id
!= LZMA_VLI_UNKNOWN
) {
378 assert_uint_eq(block_actual
->filters
[filter_count
].id
,
380 expected_filter
= block_expected
->filters
[++filter_count
];
383 assert_uint_eq(block_actual
->filters
[filter_count
].id
,
390 test_lzma_block_header_decode(void)
392 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
393 assert_skip("Encoder or decoder support disabled");
395 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
)
396 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86
))
397 assert_skip("x86 BCJ encoder and/or decoder "
401 .filters
= filters_one
,
402 .compressed_size
= LZMA_VLI_UNKNOWN
,
403 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
404 .check
= LZMA_CHECK_CRC32
,
408 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
410 // Encode block header with simple options
411 uint8_t out
[LZMA_BLOCK_HEADER_SIZE_MAX
];
412 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
414 // Decode block header and check that the options match
415 lzma_filter decoded_filters
[LZMA_FILTERS_MAX
+ 1];
416 lzma_block decoded_block
= {
418 .filters
= decoded_filters
,
419 .check
= LZMA_CHECK_CRC32
421 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
423 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
425 compare_blocks(&block
, &decoded_block
);
427 // Reset output buffer and decoded_block
428 RESET_BLOCK(decoded_block
, out
);
430 // Test with compressed size set
431 block
.compressed_size
= 4096;
432 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
433 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
434 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
435 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
437 compare_blocks(&block
, &decoded_block
);
439 RESET_BLOCK(decoded_block
, out
);
441 // Test with uncompressed size set
442 block
.uncompressed_size
= 4096;
443 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
444 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
445 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
446 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
448 compare_blocks(&block
, &decoded_block
);
450 RESET_BLOCK(decoded_block
, out
);
452 // Test with multiple filters
453 block
.filters
= filters_four
;
454 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
455 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
456 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
457 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
459 compare_blocks(&block
, &decoded_block
);
461 lzma_filters_free(decoded_filters
, NULL
);
463 // Test with too high version. The decoder will set it to a version
465 decoded_block
.version
= 2;
466 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
468 assert_uint_eq(decoded_block
.version
, 1);
470 // Free the filters for the last time since all other cases should
471 // result in an error.
472 lzma_filters_free(decoded_filters
, NULL
);
474 // Test bad check type
475 decoded_block
.check
= INVALID_LZMA_CHECK_ID
;
476 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
478 decoded_block
.check
= LZMA_CHECK_CRC32
;
480 // Test bad check value
481 out
[decoded_block
.header_size
- 1] -= 10;
482 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
484 out
[decoded_block
.header_size
- 1] += 10;
486 // Test non-NULL padding
487 out
[decoded_block
.header_size
- 5] = 1;
490 write32le(&out
[decoded_block
.header_size
- 4], lzma_crc32(out
,
491 decoded_block
.header_size
- 4, 0));
492 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
495 // Test unsupported flags
499 write32le(&out
[decoded_block
.header_size
- 4], lzma_crc32(out
,
500 decoded_block
.header_size
- 4, 0));
501 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
508 main(int argc
, char **argv
)
510 tuktest_start(argc
, argv
);
512 if (lzma_lzma_preset(&opt_lzma
, 1))
513 tuktest_error("lzma_lzma_preset() failed");
515 tuktest_run(test_lzma_block_header_size
);
516 tuktest_run(test_lzma_block_header_encode
);
517 tuktest_run(test_lzma_block_header_decode
);
519 return tuktest_end();