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 static lzma_filter filters_four
[5] = {
40 .id
= LZMA_FILTER_X86
,
43 .id
= LZMA_FILTER_X86
,
46 .id
= LZMA_FILTER_X86
,
49 .id
= LZMA_FILTER_LZMA2
,
52 .id
= LZMA_VLI_UNKNOWN
,
57 static lzma_filter filters_five
[6] = {
59 .id
= LZMA_FILTER_X86
,
62 .id
= LZMA_FILTER_X86
,
65 .id
= LZMA_FILTER_X86
,
68 .id
= LZMA_FILTER_X86
,
71 .id
= LZMA_FILTER_LZMA2
,
74 .id
= LZMA_VLI_UNKNOWN
,
81 test_lzma_block_header_size(void)
84 assert_skip("Encoder support disabled");
86 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
))
87 assert_skip("x86 BCJ encoder is disabled");
91 .filters
= filters_one
,
92 .compressed_size
= LZMA_VLI_UNKNOWN
,
93 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
94 .check
= LZMA_CHECK_CRC32
97 // Test that all initial options are valid
98 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
99 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
100 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
101 assert_uint_eq(block
.header_size
% 4, 0);
103 // Test invalid version number
104 for (uint32_t i
= 2; i
< 20; i
++) {
106 assert_lzma_ret(lzma_block_header_size(&block
),
112 // Test invalid compressed size
113 block
.compressed_size
= 0;
114 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
116 block
.compressed_size
= LZMA_VLI_MAX
+ 1;
117 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
118 block
.compressed_size
= LZMA_VLI_UNKNOWN
;
120 // Test invalid uncompressed size
121 block
.uncompressed_size
= LZMA_VLI_MAX
+ 1;
122 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
123 block
.uncompressed_size
= LZMA_VLI_MAX
;
125 // Test invalid filters
126 block
.filters
= NULL
;
127 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
129 block
.filters
= filters_none
;
130 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
132 block
.filters
= filters_five
;
133 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_PROG_ERROR
);
135 block
.filters
= filters_one
;
137 // Test setting compressed_size to something valid
138 block
.compressed_size
= 4096;
139 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
140 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
141 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
142 assert_uint_eq(block
.header_size
% 4, 0);
144 // Test setting uncompressed_size to something valid
145 block
.uncompressed_size
= 4096;
146 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
147 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
148 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
149 assert_uint_eq(block
.header_size
% 4, 0);
151 // This should pass, but header_size will be an invalid value
152 // because the total block size will not be able to fit in a valid
153 // lzma_vli. This way a temporary value can be used to reserve
154 // space for the header and later the actual value can be set.
155 block
.compressed_size
= LZMA_VLI_MAX
;
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 // Use an invalid value for a filter option. This should still pass
162 // because the size of the LZMA2 properties is known by liblzma
163 // without reading any of the options so it doesn't validate them.
164 lzma_options_lzma bad_ops
;
165 assert_false(lzma_lzma_preset(&bad_ops
, 1));
168 lzma_filter bad_filters
[2] = {
170 .id
= LZMA_FILTER_LZMA2
,
174 .id
= LZMA_VLI_UNKNOWN
,
179 block
.filters
= bad_filters
;
181 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
182 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
183 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
184 assert_uint_eq(block
.header_size
% 4, 0);
186 // Use an invalid block option. The check type isn't stored in
187 // the Block Header and so _header_size ignores it.
188 block
.check
= 0x1000;
189 block
.ignore_check
= false;
191 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
192 assert_uint(block
.header_size
, >=, LZMA_BLOCK_HEADER_SIZE_MIN
);
193 assert_uint(block
.header_size
, <=, LZMA_BLOCK_HEADER_SIZE_MAX
);
194 assert_uint_eq(block
.header_size
% 4, 0);
200 test_lzma_block_header_encode(void)
202 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
203 assert_skip("Encoder or decoder support disabled");
206 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
)
207 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86
))
208 assert_skip("x86 BCJ encoder and/or decoder "
213 .filters
= filters_one
,
214 .compressed_size
= LZMA_VLI_UNKNOWN
,
215 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
216 .check
= LZMA_CHECK_CRC32
,
219 // Ensure all block options are valid before changes are tested
220 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
222 uint8_t out
[LZMA_BLOCK_HEADER_SIZE_MAX
];
224 // Test invalid block version
225 for (uint32_t i
= 2; i
< 20; i
++) {
227 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
233 // Test invalid header size (< min, > max, % 4 != 0)
234 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MIN
- 4;
235 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
237 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MIN
+ 2;
238 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
240 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MAX
+ 4;
241 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
243 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
245 // Test invalid compressed_size
246 block
.compressed_size
= 0;
247 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
249 block
.compressed_size
= LZMA_VLI_MAX
+ 1;
250 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
253 // This test passes test_lzma_block_header_size, but should
254 // fail here because there is not enough space to encode the
255 // proper block size because the total size is too big to fit
257 block
.compressed_size
= LZMA_VLI_MAX
;
258 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
260 block
.compressed_size
= LZMA_VLI_UNKNOWN
;
262 // Test invalid uncompressed size
263 block
.uncompressed_size
= LZMA_VLI_MAX
+ 1;
264 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
266 block
.uncompressed_size
= LZMA_VLI_UNKNOWN
;
268 // Test invalid block check
269 block
.check
= 0x1000;
270 block
.ignore_check
= false;
271 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
273 block
.check
= LZMA_CHECK_CRC32
;
275 // Test invalid filters
276 block
.filters
= NULL
;
277 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
280 block
.filters
= filters_none
;
281 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
284 block
.filters
= filters_five
;
285 block
.header_size
= LZMA_BLOCK_HEADER_SIZE_MAX
- 4;
286 assert_lzma_ret(lzma_block_header_encode(&block
, out
),
289 // Test valid encoding and verify bytes of block header.
290 // More complicated tests for encoding headers are included
291 // in test_lzma_block_header_decode.
292 block
.filters
= filters_one
;
293 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
294 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
296 // First read block header size from out and verify
297 // that it == (encoded size + 1) * 4
298 uint32_t header_size
= (out
[0] + 1U) * 4;
299 assert_uint_eq(header_size
, block
.header_size
);
301 // Next read block flags
302 uint8_t flags
= out
[1];
304 // Should have number of filters = 1
305 assert_uint_eq((flags
& 0x3) + 1, 1);
307 // Bits 2-7 must be empty not set
308 assert_uint_eq(flags
& (0xFF - 0x3), 0);
310 // Verify filter flags
312 lzma_vli filter_id
= 0;
314 assert_lzma_ret(lzma_vli_decode(&filter_id
, NULL
, out
,
315 &pos
, header_size
), LZMA_OK
);
316 assert_uint_eq(filter_id
, filters_one
[0].id
);
318 // Decode Size of Properties
319 lzma_vli prop_size
= 0;
320 assert_lzma_ret(lzma_vli_decode(&prop_size
, NULL
, out
,
321 &pos
, header_size
), LZMA_OK
);
323 // LZMA2 has 1 byte prop size
324 assert_uint_eq(prop_size
, 1);
325 uint8_t expected_filter_props
= 0;
326 assert_lzma_ret(lzma_properties_encode(filters_one
,
327 &expected_filter_props
), LZMA_OK
);
328 assert_uint_eq(out
[pos
], expected_filter_props
);
331 // Check null-padding
332 for (size_t i
= pos
; i
< header_size
- 4; i
++)
333 assert_uint_eq(out
[i
], 0);
336 assert_uint_eq(read32le(&out
[header_size
- 4]), lzma_crc32(out
,
337 header_size
- 4, 0));
342 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
343 // Helper function to compare two lzma_block structures field by field
345 compare_blocks(lzma_block
*block_expected
, lzma_block
*block_actual
)
347 assert_uint_eq(block_actual
->version
, block_expected
->version
);
348 assert_uint_eq(block_actual
->compressed_size
,
349 block_expected
->compressed_size
);
350 assert_uint_eq(block_actual
->uncompressed_size
,
351 block_expected
->uncompressed_size
);
352 assert_uint_eq(block_actual
->check
, block_expected
->check
);
353 assert_uint_eq(block_actual
->header_size
, block_expected
->header_size
);
355 // Compare filter IDs
356 assert_true(block_expected
->filters
&& block_actual
->filters
);
357 lzma_filter expected_filter
= block_expected
->filters
[0];
358 uint32_t filter_count
= 0;
359 while (expected_filter
.id
!= LZMA_VLI_UNKNOWN
) {
360 assert_uint_eq(block_actual
->filters
[filter_count
].id
,
362 expected_filter
= block_expected
->filters
[++filter_count
];
365 assert_uint_eq(block_actual
->filters
[filter_count
].id
,
372 test_lzma_block_header_decode(void)
374 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
375 assert_skip("Encoder or decoder support disabled");
377 if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86
)
378 || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86
))
379 assert_skip("x86 BCJ encoder and/or decoder "
383 .filters
= filters_one
,
384 .compressed_size
= LZMA_VLI_UNKNOWN
,
385 .uncompressed_size
= LZMA_VLI_UNKNOWN
,
386 .check
= LZMA_CHECK_CRC32
,
390 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
392 // Encode block header with simple options
393 uint8_t out
[LZMA_BLOCK_HEADER_SIZE_MAX
];
394 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
396 // Decode block header and check that the options match
397 lzma_filter decoded_filters
[LZMA_FILTERS_MAX
+ 1];
398 lzma_block decoded_block
= {
400 .filters
= decoded_filters
,
401 .check
= LZMA_CHECK_CRC32
403 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
405 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
407 compare_blocks(&block
, &decoded_block
);
409 // Reset output buffer and decoded_block
410 memzero(out
, LZMA_BLOCK_HEADER_SIZE_MAX
);
411 memzero(&decoded_block
, sizeof(lzma_block
));
412 decoded_block
.filters
= decoded_filters
;
413 decoded_block
.check
= LZMA_CHECK_CRC32
;
415 // Test with compressed size set
416 block
.compressed_size
= 4096;
417 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
418 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
419 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
420 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
422 compare_blocks(&block
, &decoded_block
);
424 memzero(out
, LZMA_BLOCK_HEADER_SIZE_MAX
);
425 memzero(&decoded_block
, sizeof(lzma_block
));
426 decoded_block
.filters
= decoded_filters
;
427 decoded_block
.check
= LZMA_CHECK_CRC32
;
429 // Test with uncompressed size set
430 block
.uncompressed_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 memzero(out
, LZMA_BLOCK_HEADER_SIZE_MAX
);
439 memzero(&decoded_block
, sizeof(lzma_block
));
440 decoded_block
.filters
= decoded_filters
;
441 decoded_block
.check
= LZMA_CHECK_CRC32
;
443 // Test with multiple filters
444 block
.filters
= filters_four
;
445 assert_lzma_ret(lzma_block_header_size(&block
), LZMA_OK
);
446 assert_lzma_ret(lzma_block_header_encode(&block
, out
), LZMA_OK
);
447 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
448 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
450 compare_blocks(&block
, &decoded_block
);
452 memzero(&decoded_block
, sizeof(lzma_block
));
453 decoded_block
.filters
= decoded_filters
;
454 decoded_block
.check
= LZMA_CHECK_CRC32
;
455 decoded_block
.header_size
= lzma_block_header_size_decode(out
[0]);
457 // Test with too high version. The decoder will set it to a version
459 decoded_block
.version
= 2;
460 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
462 assert_uint_eq(decoded_block
.version
, 1);
464 // Test bad check type
465 decoded_block
.check
= LZMA_CHECK_ID_MAX
+ 1;
466 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
468 decoded_block
.check
= LZMA_CHECK_CRC32
;
470 // Test bad check value
471 out
[decoded_block
.header_size
- 1] -= 10;
472 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
474 out
[decoded_block
.header_size
- 1] += 10;
476 // Test non-NULL padding
477 out
[decoded_block
.header_size
- 5] = 1;
480 write32le(&out
[decoded_block
.header_size
- 4], lzma_crc32(out
,
481 decoded_block
.header_size
- 4, 0));
482 assert_lzma_ret(lzma_block_header_decode(&decoded_block
, NULL
, out
),
485 // Test unsupported flags
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
),
498 main(int argc
, char **argv
)
500 tuktest_start(argc
, argv
);
502 if (lzma_lzma_preset(&opt_lzma
, 1))
503 tuktest_error("lzma_lzma_preset() failed");
505 tuktest_run(test_lzma_block_header_size
);
506 tuktest_run(test_lzma_block_header_encode
);
507 tuktest_run(test_lzma_block_header_decode
);
509 return tuktest_end();