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
;
21 static lzma_filter filters_none
[1] = {
23 .id
= LZMA_VLI_UNKNOWN
,
28 static lzma_filter filters_one
[2] = {
30 .id
= LZMA_FILTER_LZMA2
,
33 .id
= LZMA_VLI_UNKNOWN
,
38 // These filters are only used in test_lzma_block_header_decode()
39 // which only runs if encoders and decoders are configured.
41 static lzma_filter filters_four
[5] = {
43 .id
= LZMA_FILTER_X86
,
46 .id
= LZMA_FILTER_X86
,
49 .id
= LZMA_FILTER_X86
,
52 .id
= LZMA_FILTER_LZMA2
,
55 .id
= LZMA_VLI_UNKNOWN
,
61 static lzma_filter filters_five
[6] = {
63 .id
= LZMA_FILTER_X86
,
66 .id
= LZMA_FILTER_X86
,
69 .id
= LZMA_FILTER_X86
,
72 .id
= LZMA_FILTER_X86
,
75 .id
= LZMA_FILTER_LZMA2
,
78 .id
= LZMA_VLI_UNKNOWN
,
85 test_lzma_block_header_size(void)
88 assert_skip("Encoder support disabled");
90 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
))
91 assert_skip("x86 BCJ encoder is disabled");
95 .filters
= filters_one
,
96 .compressed_size
= LZMA_VLI_UNKNOWN
,
97 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
98 .check
= LZMA_CHECK_CRC32
101 // Test that all initial options are valid
102 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
103 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
104 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
105 assert_uint_eq(block
.header_size
% 4, 0);
107 // Test invalid version number
108 for (uint32_t i
= 2; i
< 20; i
++) {
110 assert_lzma_ret(lzma_block_header_size(&block
),
116 // Test invalid compressed size
117 block
.compressed_size
= 0;
118 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
120 block
.compressed_size
= LZMA_VLI_MAX
+ 1;
121 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
122 block
.compressed_size
= LZMA_VLI_UNKNOWN
;
124 // Test invalid uncompressed size
125 block
.uncompressed_size
= LZMA_VLI_MAX
+ 1;
126 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
127 block
.uncompressed_size
= LZMA_VLI_MAX
;
129 // Test invalid filters
130 block
.filters
= NULL
;
131 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
133 block
.filters
= filters_none
;
134 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
136 block
.filters
= filters_five
;
137 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
139 block
.filters
= filters_one
;
141 // Test setting compressed_size to something valid
142 block
.compressed_size
= 4096;
143 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
144 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
145 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
146 assert_uint_eq(block
.header_size
% 4, 0);
148 // Test setting uncompressed_size to something valid
149 block
.uncompressed_size
= 4096;
150 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
151 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
152 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
153 assert_uint_eq(block
.header_size
% 4, 0);
155 // This should pass, but header_size will be an invalid value
156 // because the total block size will not be able to fit in a valid
157 // lzma_vli. This way a temporary value can be used to reserve
158 // space for the header and later the actual value can be set.
159 block
.compressed_size
= LZMA_VLI_MAX
;
160 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
161 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
162 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
163 assert_uint_eq(block
.header_size
% 4, 0);
165 // Use an invalid value for a filter option. This should still pass
166 // because the size of the LZMA2 properties is known by liblzma
167 // without reading any of the options so it doesn't validate them.
168 lzma_options_lzma bad_ops
;
169 assert_false(lzma_lzma_preset(&bad_ops
, 1));
172 lzma_filter bad_filters
[2] = {
174 .id
= LZMA_FILTER_LZMA2
,
178 .id
= LZMA_VLI_UNKNOWN
,
183 block
.filters
= bad_filters
;
185 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
186 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
187 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
188 assert_uint_eq(block
.header_size
% 4, 0);
190 // Use an invalid block option. The check type isn't stored in
191 // the Block Header and so _header_size ignores it.
192 block
.check
= INVALID_LZMA_CHECK_ID
;
193 block
.ignore_check
= false;
195 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
196 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
197 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
198 assert_uint_eq(block
.header_size
% 4, 0);
204 test_lzma_block_header_encode(void)
206 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
207 assert_skip("Encoder or decoder support disabled");
210 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
)
211 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86
))
212 assert_skip("x86 BCJ encoder and/or decoder "
217 .filters
= filters_one
,
218 .compressed_size
= LZMA_VLI_UNKNOWN
,
219 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
220 .check
= LZMA_CHECK_CRC32
,
223 // Ensure all block options are valid before changes are tested
224 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
226 uint8_t out
[LZMA_BLOCK_HEADER_SIZE_MAX
];
228 // Test invalid block version
229 for (uint32_t i
= 2; i
< 20; i
++) {
231 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
237 // Test invalid header size (< min, > max, % 4 != 0)
238 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MIN
- 4;
239 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
241 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MIN
+ 2;
242 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
244 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MAX
+ 4;
245 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
247 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
249 // Test invalid compressed_size
250 block
.compressed_size
= 0;
251 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
253 block
.compressed_size
= LZMA_VLI_MAX
+ 1;
254 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
257 // This test passes test_lzma_block_header_size, but should
258 // fail here because there is not enough space to encode the
259 // proper block size because the total size is too big to fit
261 block
.compressed_size
= LZMA_VLI_MAX
;
262 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
264 block
.compressed_size
= LZMA_VLI_UNKNOWN
;
266 // Test invalid uncompressed size
267 block
.uncompressed_size
= LZMA_VLI_MAX
+ 1;
268 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
270 block
.uncompressed_size
= LZMA_VLI_UNKNOWN
;
272 // Test invalid block check
273 block
.check
= INVALID_LZMA_CHECK_ID
;
274 block
.ignore_check
= false;
275 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
277 block
.check
= LZMA_CHECK_CRC32
;
279 // Test invalid filters
280 block
.filters
= NULL
;
281 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
284 block
.filters
= filters_none
;
285 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
288 block
.filters
= filters_five
;
289 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MAX
- 4;
290 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
293 // Test valid encoding and verify bytes of block header.
294 // More complicated tests for encoding headers are included
295 // in test_lzma_block_header_decode.
296 block
.filters
= filters_one
;
297 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
298 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
300 // First read block header size from out and verify
301 // that it == (encoded size + 1) * 4
302 uint32_t header_size
= (out
[0] + 1U) * 4;
303 assert_uint_eq(header_size
, block
.header_size
);
305 // Next read block flags
306 uint8_t flags
= out
[1];
308 // Should have number of filters = 1
309 assert_uint_eq((flags
& 0x3) + 1, 1);
311 // Bits 2-7 must be empty not set
312 assert_uint_eq(flags
& (0xFF - 0x3), 0);
314 // Verify filter flags
316 lzma_vli filter_id
= 0;
318 assert_lzma_ret(lzma_vli_decode(&filter_id
, NULL
, out
,
319 &pos
, header_size
), LZMA_OK
);
320 assert_uint_eq(filter_id
, filters_one
[0].id
);
322 // Decode Size of Properties
323 lzma_vli prop_size
= 0;
324 assert_lzma_ret(lzma_vli_decode(&prop_size
, NULL
, out
,
325 &pos
, header_size
), LZMA_OK
);
327 // LZMA2 has 1 byte prop size
328 assert_uint_eq(prop_size
, 1);
329 uint8_t expected_filter_props
= 0;
330 assert_lzma_ret(lzma_properties_encode(filters_one
,
331 &expected_filter_props
), LZMA_OK
);
332 assert_uint_eq(out
[pos
], expected_filter_props
);
335 // Check null-padding
336 for (size_t i
= pos
; i
< header_size
- 4; i
++)
337 assert_uint_eq(out
[i
], 0);
340 assert_uint_eq(read32le(&out
[header_size
- 4]), lzma_crc32(out
,
341 header_size
- 4, 0));
346 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
347 // Helper function to compare two lzma_block structures field by field
349 compare_blocks(lzma_block
*block_expected
, lzma_block
*block_actual
)
351 assert_uint_eq(block_actual
->version
, block_expected
->version
);
352 assert_uint_eq(block_actual
->compressed_size
,
353 block_expected
->compressed_size
);
354 assert_uint_eq(block_actual
->uncompressed_size
,
355 block_expected
->uncompressed_size
);
356 assert_uint_eq(block_actual
->check
, block_expected
->check
);
357 assert_uint_eq(block_actual
->header_size
, block_expected
->header_size
);
359 // Compare filter IDs
360 assert_true(block_expected
->filters
&& block_actual
->filters
);
361 lzma_filter expected_filter
= block_expected
->filters
[0];
362 uint32_t filter_count
= 0;
363 while (expected_filter
.id
!= LZMA_VLI_UNKNOWN
) {
364 assert_uint_eq(block_actual
->filters
[filter_count
].id
,
366 expected_filter
= block_expected
->filters
[++filter_count
];
369 assert_uint_eq(block_actual
->filters
[filter_count
].id
,
376 test_lzma_block_header_decode(void)
378 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
379 assert_skip("Encoder or decoder support disabled");
381 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
)
382 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86
))
383 assert_skip("x86 BCJ encoder and/or decoder "
387 .filters
= filters_one
,
388 .compressed_size
= LZMA_VLI_UNKNOWN
,
389 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
390 .check
= LZMA_CHECK_CRC32
,
394 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
396 // Encode block header with simple options
397 uint8_t out
[LZMA_BLOCK_HEADER_SIZE_MAX
];
398 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
400 // Decode block header and check that the options match
401 lzma_filter decoded_filters
[LZMA_FILTERS_MAX
+ 1];
402 lzma_block decoded_block
= {
404 .filters
= decoded_filters
,
405 .check
= LZMA_CHECK_CRC32
407 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
409 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
411 compare_blocks(&block
, &decoded_block
);
413 // Reset output buffer and decoded_block
414 memzero(out
, LZMA_BLOCK_HEADER_SIZE_MAX
);
415 memzero(&decoded_block
, sizeof(lzma_block
));
416 decoded_block
.filters
= decoded_filters
;
417 decoded_block
.check
= LZMA_CHECK_CRC32
;
419 // Test with compressed size set
420 block
.compressed_size
= 4096;
421 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
422 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
423 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
424 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
426 compare_blocks(&block
, &decoded_block
);
428 memzero(out
, LZMA_BLOCK_HEADER_SIZE_MAX
);
429 memzero(&decoded_block
, sizeof(lzma_block
));
430 decoded_block
.filters
= decoded_filters
;
431 decoded_block
.check
= LZMA_CHECK_CRC32
;
433 // Test with uncompressed size set
434 block
.uncompressed_size
= 4096;
435 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
436 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
437 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
438 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
440 compare_blocks(&block
, &decoded_block
);
442 memzero(out
, LZMA_BLOCK_HEADER_SIZE_MAX
);
443 memzero(&decoded_block
, sizeof(lzma_block
));
444 decoded_block
.filters
= decoded_filters
;
445 decoded_block
.check
= LZMA_CHECK_CRC32
;
447 // Test with multiple filters
448 block
.filters
= filters_four
;
449 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
450 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
451 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
452 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
454 compare_blocks(&block
, &decoded_block
);
456 memzero(&decoded_block
, sizeof(lzma_block
));
457 decoded_block
.filters
= decoded_filters
;
458 decoded_block
.check
= LZMA_CHECK_CRC32
;
459 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
461 // Test with too high version. The decoder will set it to a version
463 decoded_block
.version
= 2;
464 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
466 assert_uint_eq(decoded_block
.version
, 1);
468 // Test bad check type
469 decoded_block
.check
= INVALID_LZMA_CHECK_ID
;
470 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
472 decoded_block
.check
= LZMA_CHECK_CRC32
;
474 // Test bad check value
475 out
[decoded_block
.header_size
- 1] -= 10;
476 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
478 out
[decoded_block
.header_size
- 1] += 10;
480 // Test non-NULL padding
481 out
[decoded_block
.header_size
- 5] = 1;
484 write32le(&out
[decoded_block
.header_size
- 4], lzma_crc32(out
,
485 decoded_block
.header_size
- 4, 0));
486 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
489 // Test unsupported flags
493 write32le(&out
[decoded_block
.header_size
- 4], lzma_crc32(out
,
494 decoded_block
.header_size
- 4, 0));
495 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
502 main(int argc
, char **argv
)
504 tuktest_start(argc
, argv
);
506 if (lzma_lzma_preset(&opt_lzma
, 1))
507 tuktest_error("lzma_lzma_preset() failed");
509 tuktest_run(test_lzma_block_header_size
);
510 tuktest_run(test_lzma_block_header_encode
);
511 tuktest_run(test_lzma_block_header_decode
);
513 return tuktest_end();