1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file test_filter_flags.c
6 /// \brief Tests Filter Flags coders
11 ///////////////////////////////////////////////////////////////////////////////
15 // FIXME: This is from src/liblzma/common/common.h but it cannot be
16 // included here. This constant is needed in only a few files, perhaps
17 // move it to some other internal header or create a new one?
18 #define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
21 #if defined(HAVE_ENCODERS)
22 // No tests are run without encoders, so init the global filters
23 // only when the encoders are enabled.
24 static lzma_filter lzma1_filter
= { LZMA_FILTER_LZMA1
, NULL
};
25 static lzma_filter lzma2_filter
= { LZMA_FILTER_LZMA2
, NULL
};
26 static lzma_filter delta_filter
= { LZMA_FILTER_DELTA
, NULL
};
28 static lzma_filter bcj_filters_encoders
[] = {
29 #ifdef HAVE_ENCODER_X86
30 { LZMA_FILTER_X86
, NULL
},
32 #ifdef HAVE_ENCODER_POWERPC
33 { LZMA_FILTER_POWERPC
, NULL
},
35 #ifdef HAVE_ENCODER_IA64
36 { LZMA_FILTER_IA64
, NULL
},
38 #ifdef HAVE_ENCODER_ARM
39 { LZMA_FILTER_ARM
, NULL
},
41 #ifdef HAVE_ENCODER_ARM64
42 { LZMA_FILTER_ARM64
, NULL
},
44 #ifdef HAVE_ENCODER_ARMTHUMB
45 { LZMA_FILTER_ARMTHUMB
, NULL
},
47 #ifdef HAVE_ENCODER_SPARC
48 { LZMA_FILTER_SPARC
, NULL
},
50 #ifdef HAVE_ENCODER_RISCV
51 { LZMA_FILTER_RISCV
, NULL
},
53 { LZMA_VLI_UNKNOWN
, NULL
}
56 // HAVE_ENCODERS ifdef not terminated here because decoders are
57 // only used if encoders are, but encoders can still be used
58 // even if decoders are not.
61 static lzma_filter bcj_filters_decoders
[] = {
62 #ifdef HAVE_DECODER_X86
63 { LZMA_FILTER_X86
, NULL
},
65 #ifdef HAVE_DECODER_POWERPC
66 { LZMA_FILTER_POWERPC
, NULL
},
68 #ifdef HAVE_DECODER_IA64
69 { LZMA_FILTER_IA64
, NULL
},
71 #ifdef HAVE_DECODER_ARM
72 { LZMA_FILTER_ARM
, NULL
},
74 #ifdef HAVE_DECODER_ARM64
75 { LZMA_FILTER_ARM64
, NULL
},
77 #ifdef HAVE_DECODER_ARMTHUMB
78 { LZMA_FILTER_ARMTHUMB
, NULL
},
80 #ifdef HAVE_DECODER_SPARC
81 { LZMA_FILTER_SPARC
, NULL
},
83 #ifdef HAVE_DECODER_RISCV
84 { LZMA_FILTER_RISCV
, NULL
},
86 { LZMA_VLI_UNKNOWN
, NULL
}
93 test_lzma_filter_flags_size(void)
96 assert_skip("Encoder support disabled");
98 // For each supported filter, test that the size can be calculated
99 // and that the size calculated is reasonable. A reasonable size
100 // must be greater than 0, but less than the maximum size for the
103 if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA1
)) {
104 // LZMA1 isn't supported in .xz so we get LZMA_PROG_ERROR.
105 assert_lzma_ret(lzma_filter_flags_size(&size
,
106 &lzma1_filter
), LZMA_PROG_ERROR
);
109 if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2
)) {
110 assert_lzma_ret(lzma_filter_flags_size(&size
,
111 &lzma2_filter
), LZMA_OK
);
112 assert_true(size
!= 0 && size
< LZMA_BLOCK_HEADER_SIZE_MAX
);
115 for (size_t i
= 0; bcj_filters_encoders
[i
].id
!= LZMA_VLI_UNKNOWN
;
117 assert_lzma_ret(lzma_filter_flags_size(&size
,
118 &bcj_filters_encoders
[i
]), LZMA_OK
);
119 assert_true(size
!= 0 && size
< LZMA_BLOCK_HEADER_SIZE_MAX
);
122 if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA
)) {
123 assert_lzma_ret(lzma_filter_flags_size(&size
,
124 &delta_filter
), LZMA_OK
);
125 assert_true(size
!= 0 && size
< LZMA_BLOCK_HEADER_SIZE_MAX
);
128 // Test invalid Filter IDs
129 lzma_filter bad_filter
= { 2, NULL
};
131 assert_lzma_ret(lzma_filter_flags_size(&size
, &bad_filter
),
133 bad_filter
.id
= LZMA_VLI_MAX
;
134 assert_lzma_ret(lzma_filter_flags_size(&size
, &bad_filter
),
136 bad_filter
.id
= LZMA_FILTER_RESERVED_START
;
137 assert_lzma_ret(lzma_filter_flags_size(&size
, &bad_filter
),
143 // Helper function for test_lzma_filter_flags_encode.
144 // The should_encode parameter represents if the encoding operation
145 // is expected to fail.
146 // Avoid data -> encode -> decode -> compare to data.
147 // Instead create expected encoding and compare to result from
148 // lzma_filter_flags_encode.
149 // Filter Flags in .xz are encoded as:
150 // |Filter ID (VLI)|Size of Properties (VLI)|Filter Properties|
151 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
153 verify_filter_flags_encode(lzma_filter
*filter
, bool should_encode
)
157 // First calculate the size of Filter Flags to know how much
158 // memory to allocate to hold the encoded Filter Flags
159 assert_lzma_ret(lzma_filter_flags_size(&size
, filter
), LZMA_OK
);
160 uint8_t *encoded_out
= tuktest_malloc(size
);
162 if (!should_encode
) {
163 assert_false(lzma_filter_flags_encode(filter
, encoded_out
,
164 &out_pos
, size
) == LZMA_OK
);
168 // Next encode the Filter Flags for the provided filter
169 assert_lzma_ret(lzma_filter_flags_encode(filter
, encoded_out
,
170 &out_pos
, size
), LZMA_OK
);
171 assert_uint_eq(size
, out_pos
);
173 // Next decode the VLI for the Filter ID and verify it matches
174 // the expected Filter ID
175 size_t filter_id_vli_size
= 0;
176 lzma_vli filter_id
= 0;
177 assert_lzma_ret(lzma_vli_decode(&filter_id
, NULL
, encoded_out
,
178 &filter_id_vli_size
, size
), LZMA_OK
);
179 assert_uint_eq(filter
->id
, filter_id
);
181 // Next decode the Size of Properties and ensure it equals
182 // the expected size.
183 // Expected size should be:
184 // total filter flag length - size of filter id VLI + size of
186 // Not verifying the contents of Filter Properties since
187 // that belongs in a different test
188 size_t size_of_properties_vli_size
= 0;
189 lzma_vli size_of_properties
= 0;
190 assert_lzma_ret(lzma_vli_decode(&size_of_properties
, NULL
,
191 encoded_out
+ filter_id_vli_size
,
192 &size_of_properties_vli_size
, size
), LZMA_OK
);
193 assert_uint_eq(size
- (size_of_properties_vli_size
+
194 filter_id_vli_size
), size_of_properties
);
200 test_lzma_filter_flags_encode(void)
202 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
203 assert_skip("Encoder or decoder support disabled");
205 // No test for LZMA1 since the .xz format does not support LZMA1
206 // and so the flags cannot be encoded for that filter
207 if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2
)) {
208 // Test with NULL options that should fail
209 lzma_options_lzma
*options
= lzma2_filter
.options
;
210 lzma2_filter
.options
= NULL
;
211 verify_filter_flags_encode(&lzma2_filter
, false);
213 // Place options back in the filter, and test should pass
214 lzma2_filter
.options
= options
;
215 verify_filter_flags_encode(&lzma2_filter
, true);
218 // NOTE: Many BCJ filters require that start_offset is a multiple
219 // of some power of two. The Filter Flags encoder and decoder don't
220 // completely validate the options and thus 257 passes the tests
221 // with all BCJ filters. It would be caught when initializing
222 // a filter chain encoder or decoder.
223 lzma_options_bcj bcj_options
= {
227 for (size_t i
= 0; bcj_filters_encoders
[i
].id
!= LZMA_VLI_UNKNOWN
;
229 // NULL options should pass for bcj filters
230 verify_filter_flags_encode(&bcj_filters_encoders
[i
], true);
231 lzma_filter bcj_with_options
= {
232 bcj_filters_encoders
[i
].id
, &bcj_options
};
233 verify_filter_flags_encode(&bcj_with_options
, true);
236 if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA
)) {
237 lzma_options_delta delta_opts_below_min
= {
238 .type
= LZMA_DELTA_TYPE_BYTE
,
239 .dist
= LZMA_DELTA_DIST_MIN
- 1
242 lzma_options_delta delta_opts_above_max
= {
243 .type
= LZMA_DELTA_TYPE_BYTE
,
244 .dist
= LZMA_DELTA_DIST_MAX
+ 1
247 verify_filter_flags_encode(&delta_filter
, true);
249 lzma_filter delta_filter_bad_options
= {
250 LZMA_FILTER_DELTA
, &delta_opts_below_min
};
252 // Next test error case using minimum - 1 delta distance
253 verify_filter_flags_encode(&delta_filter_bad_options
, false);
255 // Next test error case using maximum + 1 delta distance
256 delta_filter_bad_options
.options
= &delta_opts_above_max
;
257 verify_filter_flags_encode(&delta_filter_bad_options
, false);
259 // Next test NULL case
260 delta_filter_bad_options
.options
= NULL
;
261 verify_filter_flags_encode(&delta_filter_bad_options
, false);
264 // Test expected failing cases
265 lzma_filter bad_filter
= { LZMA_FILTER_RESERVED_START
, NULL
};
267 size_t out_size
= LZMA_BLOCK_HEADER_SIZE_MAX
;
268 uint8_t out
[LZMA_BLOCK_HEADER_SIZE_MAX
];
270 // Filter ID outside of valid range
271 assert_lzma_ret(lzma_filter_flags_encode(&bad_filter
, out
, &out_pos
,
272 out_size
), LZMA_PROG_ERROR
);
274 bad_filter
.id
= LZMA_VLI_MAX
+ 1;
275 assert_lzma_ret(lzma_filter_flags_encode(&bad_filter
, out
, &out_pos
,
276 out_size
), LZMA_PROG_ERROR
);
281 assert_lzma_ret(lzma_filter_flags_encode(&bad_filter
, out
, &out_pos
,
282 out_size
), LZMA_OPTIONS_ERROR
);
285 // Out size too small
286 if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2
)) {
287 uint32_t bad_size
= 0;
289 // First test with 0 output size
290 assert_lzma_ret(lzma_filter_flags_encode(
291 &lzma2_filter
, out
, &out_pos
, 0),
294 // Next calculate the size needed to encode and
295 // use less than that
296 assert_lzma_ret(lzma_filter_flags_size(&bad_size
,
297 &lzma2_filter
), LZMA_OK
);
299 assert_lzma_ret(lzma_filter_flags_encode(
300 &lzma2_filter
, out
, &out_pos
,
301 bad_size
- 1), LZMA_PROG_ERROR
);
306 if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA
)) {
307 bad_filter
.id
= LZMA_FILTER_DELTA
;
309 // First test with NULL options
310 assert_lzma_ret(lzma_filter_flags_encode(&bad_filter
, out
,
311 &out_pos
, out_size
), LZMA_PROG_ERROR
);
314 // Next test with invalid options
315 lzma_options_delta bad_options
= {
316 .dist
= LZMA_DELTA_DIST_MAX
+ 1,
317 .type
= LZMA_DELTA_TYPE_BYTE
319 bad_filter
.options
= &bad_options
;
321 assert_lzma_ret(lzma_filter_flags_encode(&bad_filter
, out
,
322 &out_pos
, out_size
), LZMA_PROG_ERROR
);
328 // Helper function for test_lzma_filter_flags_decode.
329 // Encodes the filter_in without using lzma_filter_flags_encode.
330 // Leaves the specific assertions of filter_out options to the caller
331 // because it is agnostic to the type of options used in the call
332 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
334 verify_filter_flags_decode(const lzma_filter
*filter_in
,
335 lzma_filter
*filter_out
)
337 uint32_t total_size
= 0;
339 assert_lzma_ret(lzma_filter_flags_size(&total_size
, filter_in
),
341 assert_uint(total_size
, >, 0);
342 uint8_t *filter_flag_buffer
= tuktest_malloc(total_size
);
344 uint32_t properties_size
= 0;
347 assert_lzma_ret(lzma_properties_size(&properties_size
, filter_in
),
349 assert_lzma_ret(lzma_vli_encode(filter_in
->id
, NULL
,
350 filter_flag_buffer
, &out_pos
, total_size
), LZMA_OK
);
351 assert_lzma_ret(lzma_vli_encode(properties_size
, NULL
,
352 filter_flag_buffer
, &out_pos
, total_size
),
354 assert_lzma_ret(lzma_properties_encode(filter_in
,
355 filter_flag_buffer
+ out_pos
), LZMA_OK
);
356 assert_lzma_ret(lzma_filter_flags_decode(filter_out
, NULL
,
357 filter_flag_buffer
, &in_pos
, total_size
),
359 assert_uint_eq(filter_in
->id
, filter_out
->id
);
365 test_lzma_filter_flags_decode(void)
367 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
368 assert_skip("Encoder or decoder support disabled");
370 // For each filter, only run the decoder test if both the encoder
371 // and decoder are enabled. This is because verify_filter_flags_decode
372 // uses lzma_filter_flags_size which requires the encoder.
373 if (lzma_filter_decoder_is_supported(LZMA_FILTER_LZMA2
) &&
374 lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2
)) {
375 lzma_filter lzma2_decoded
= { LZMA_FILTER_LZMA2
, NULL
};
377 verify_filter_flags_decode(&lzma2_filter
, &lzma2_decoded
);
379 lzma_options_lzma
*expected
= lzma2_filter
.options
;
380 lzma_options_lzma
*decoded
= lzma2_decoded
.options
;
382 // Only the dictionary size is encoded and decoded
383 // so only compare those
384 assert_uint_eq(decoded
->dict_size
, expected
->dict_size
);
386 // The decoded options must be freed by the caller
390 for (size_t i
= 0; bcj_filters_decoders
[i
].id
!= LZMA_VLI_UNKNOWN
;
392 if (lzma_filter_encoder_is_supported(
393 bcj_filters_decoders
[i
].id
)) {
394 lzma_filter bcj_decoded
= {
395 bcj_filters_decoders
[i
].id
, NULL
};
397 lzma_filter bcj_encoded
= {
398 bcj_filters_decoders
[i
].id
, NULL
};
400 // First test without options
401 verify_filter_flags_decode(&bcj_encoded
,
403 assert_true(bcj_decoded
.options
== NULL
);
405 // Next test with start_offset.
407 // NOTE: The encoder and decoder don't verify if
408 // the start_offset is valid for the filter. Only
409 // the encoder or decoder initialization does.
410 lzma_options_bcj options
= {
414 bcj_encoded
.options
= &options
;
415 verify_filter_flags_decode(&bcj_encoded
,
417 lzma_options_bcj
*decoded_opts
= bcj_decoded
.options
;
418 assert_uint_eq(decoded_opts
->start_offset
,
419 options
.start_offset
);
424 if (lzma_filter_decoder_is_supported(LZMA_FILTER_DELTA
) &&
425 lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA
)) {
426 lzma_filter delta_decoded
= { LZMA_FILTER_DELTA
, NULL
};
428 verify_filter_flags_decode(&delta_filter
, &delta_decoded
);
429 lzma_options_delta
*expected
= delta_filter
.options
;
430 lzma_options_delta
*decoded
= delta_decoded
.options
;
431 assert_uint_eq(expected
->dist
, decoded
->dist
);
432 assert_uint_eq(expected
->type
, decoded
->type
);
437 // Test expected failing cases
438 uint8_t bad_encoded_filter
[LZMA_BLOCK_HEADER_SIZE_MAX
];
439 lzma_filter bad_filter
;
441 // Filter ID outside of valid range
442 lzma_vli bad_filter_id
= LZMA_FILTER_RESERVED_START
;
443 size_t bad_encoded_out_pos
= 0;
446 assert_lzma_ret(lzma_vli_encode(bad_filter_id
, NULL
,
447 bad_encoded_filter
, &bad_encoded_out_pos
,
448 LZMA_BLOCK_HEADER_SIZE_MAX
), LZMA_OK
);
450 assert_lzma_ret(lzma_filter_flags_decode(&bad_filter
, NULL
,
451 bad_encoded_filter
, &in_pos
,
452 LZMA_BLOCK_HEADER_SIZE_MAX
), LZMA_DATA_ERROR
);
454 bad_encoded_out_pos
= 0;
459 bad_encoded_out_pos
= 0;
462 assert_lzma_ret(lzma_vli_encode(bad_filter_id
, NULL
,
463 bad_encoded_filter
, &bad_encoded_out_pos
,
464 LZMA_BLOCK_HEADER_SIZE_MAX
), LZMA_OK
);
466 // Next encode Size of Properties with the value of 0
467 assert_lzma_ret(lzma_vli_encode(0, NULL
,
468 bad_encoded_filter
, &bad_encoded_out_pos
,
469 LZMA_BLOCK_HEADER_SIZE_MAX
), LZMA_OK
);
471 // Decode should fail on bad Filter ID
472 assert_lzma_ret(lzma_filter_flags_decode(&bad_filter
, NULL
,
473 bad_encoded_filter
, &in_pos
,
474 LZMA_BLOCK_HEADER_SIZE_MAX
), LZMA_OPTIONS_ERROR
);
475 bad_encoded_out_pos
= 0;
479 // Encode the LZMA2 filter normally, but then set
480 // the out size when decoding as too small
481 if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2
) &&
482 lzma_filter_decoder_is_supported(LZMA_FILTER_LZMA2
)) {
483 uint32_t filter_flag_size
= 0;
484 assert_lzma_ret(lzma_filter_flags_size(&filter_flag_size
,
485 &lzma2_filter
), LZMA_OK
);
487 assert_lzma_ret(lzma_filter_flags_encode(&lzma2_filter
,
488 bad_encoded_filter
, &bad_encoded_out_pos
,
489 LZMA_BLOCK_HEADER_SIZE_MAX
), LZMA_OK
);
491 assert_lzma_ret(lzma_filter_flags_decode(&bad_filter
, NULL
,
492 bad_encoded_filter
, &in_pos
,
493 filter_flag_size
- 1), LZMA_DATA_ERROR
);
500 main(int argc
, char **argv
)
502 tuktest_start(argc
, argv
);
505 // Only init filter options if encoder is supported because decoder
506 // tests requires encoder support, so the decoder tests will only
507 // run if for a given filter both the encoder and decoder are enabled.
508 if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA1
)) {
509 lzma_options_lzma
*options
= tuktest_malloc(
510 sizeof(lzma_options_lzma
));
511 lzma_lzma_preset(options
, LZMA_PRESET_DEFAULT
);
512 lzma1_filter
.options
= options
;
515 if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2
)) {
516 lzma_options_lzma
*options
= tuktest_malloc(
517 sizeof(lzma_options_lzma
));
518 lzma_lzma_preset(options
, LZMA_PRESET_DEFAULT
);
519 lzma2_filter
.options
= options
;
522 if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA
)) {
523 lzma_options_delta
*options
= tuktest_malloc(
524 sizeof(lzma_options_delta
));
525 options
->dist
= LZMA_DELTA_DIST_MIN
;
526 options
->type
= LZMA_DELTA_TYPE_BYTE
;
527 delta_filter
.options
= options
;
531 tuktest_run(test_lzma_filter_flags_size
);
532 tuktest_run(test_lzma_filter_flags_encode
);
533 tuktest_run(test_lzma_filter_flags_decode
);
534 return tuktest_end();