1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file test_stream_flags.c
6 /// \brief Tests Stream Header and Stream Footer coders
11 ///////////////////////////////////////////////////////////////////////////////
16 // Size of the Stream Flags field
17 // (taken from src/liblzma/common/stream_flags_common.h)
18 #define XZ_STREAM_FLAGS_SIZE 2
21 // Header and footer magic bytes for .xz file format
22 // (taken from src/liblzma/common/stream_flags_common.c)
23 static const uint8_t xz_header_magic
[6]
24 = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
25 static const uint8_t xz_footer_magic
[2] = { 0x59, 0x5A };
31 stream_header_encode_helper(lzma_check check
)
33 lzma_stream_flags flags
= {
38 uint8_t header
[LZMA_STREAM_HEADER_SIZE
];
40 // Encode Stream Header
41 assert_lzma_ret(lzma_stream_header_encode(&flags
, header
), LZMA_OK
);
43 // Stream Header must start with Header Magic Bytes
44 const uint32_t magic_size
= sizeof(xz_header_magic
);
45 assert_array_eq(header
, xz_header_magic
, magic_size
);
47 // Next must come Stream Flags
48 const uint8_t *encoded_stream_flags
= header
+ magic_size
;
50 // First byte is always null-byte.
51 // Second byte must have the Check ID in the lowest four bits
52 // and the highest four bits zero.
53 const uint8_t expected_stream_flags
[] = { 0, check
};
54 assert_array_eq(encoded_stream_flags
, expected_stream_flags
,
55 XZ_STREAM_FLAGS_SIZE
);
57 // Last part is the CRC32 of the Stream Flags
58 const uint8_t *crc_ptr
= encoded_stream_flags
+ XZ_STREAM_FLAGS_SIZE
;
59 const uint32_t expected_crc
= lzma_crc32(expected_stream_flags
,
60 XZ_STREAM_FLAGS_SIZE
, 0);
61 assert_uint_eq(read32le(crc_ptr
), expected_crc
);
67 test_lzma_stream_header_encode(void)
70 assert_skip("Encoder support disabled");
72 for (lzma_check i
= 0; i
< LZMA_CHECK_ID_MAX
; i
++)
73 stream_header_encode_helper(i
);
75 lzma_stream_flags flags
= {
77 .check
= LZMA_CHECK_CRC32
80 uint8_t header
[LZMA_STREAM_HEADER_SIZE
];
82 // Should fail if version > 0
84 assert_lzma_ret(lzma_stream_header_encode(&flags
, header
),
88 // Should fail if Check ID is invalid
89 flags
.check
= INVALID_LZMA_CHECK_ID
;
90 assert_lzma_ret(lzma_stream_header_encode(&flags
, header
),
92 flags
.check
= LZMA_CHECK_CRC32
;
94 // Should pass even if Backward Size is invalid
95 // because Stream Header doesn't have that field.
96 flags
.backward_size
= LZMA_VLI_MAX
+ 1;
97 assert_lzma_ret(lzma_stream_header_encode(&flags
, header
), LZMA_OK
);
102 #if defined(HAVE_ENCODERS)
104 stream_footer_encode_helper(lzma_check check
)
106 lzma_stream_flags flags
= {
109 .backward_size
= LZMA_BACKWARD_SIZE_MIN
,
112 uint8_t footer
[LZMA_STREAM_HEADER_SIZE
];
114 // Encode Stream Footer
115 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
), LZMA_OK
);
117 // Stream Footer must start with CRC32
118 const uint32_t crc
= read32le(footer
);
119 const uint32_t expected_crc
= lzma_crc32(footer
+ sizeof(uint32_t),
120 LZMA_STREAM_HEADER_SIZE
- (sizeof(uint32_t) +
121 sizeof(xz_footer_magic
)), 0);
122 assert_uint_eq(crc
, expected_crc
);
124 // Next the Backward Size
125 const uint32_t backwards_size
= read32le(footer
+ sizeof(uint32_t));
126 const uint32_t expected_backwards_size
= flags
.backward_size
/ 4 - 1;
127 assert_uint_eq(backwards_size
, expected_backwards_size
);
129 // Next the Stream Flags
130 const uint8_t *stream_flags
= footer
+ sizeof(uint32_t) * 2;
132 // First byte must be null
133 assert_uint_eq(stream_flags
[0], 0);
135 // Second byte must have the Check ID in the lowest four bits
136 // and the highest four bits zero.
137 assert_uint_eq(stream_flags
[1], check
);
139 // And ends with Footer Magic Bytes
140 const uint8_t *expected_footer_magic
= stream_flags
+
141 XZ_STREAM_FLAGS_SIZE
;
142 assert_array_eq(expected_footer_magic
, xz_footer_magic
,
143 sizeof(xz_footer_magic
));
149 test_lzma_stream_footer_encode(void)
151 #ifndef HAVE_ENCODERS
152 assert_skip("Encoder support disabled");
154 for (lzma_check i
= 0; i
< LZMA_CHECK_ID_MAX
; i
++)
155 stream_footer_encode_helper(i
);
157 lzma_stream_flags flags
= {
159 .backward_size
= LZMA_BACKWARD_SIZE_MIN
,
160 .check
= LZMA_CHECK_CRC32
163 uint8_t footer
[LZMA_STREAM_HEADER_SIZE
];
165 // Should fail if version > 0
167 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
),
171 // Should fail if Check ID is invalid
172 flags
.check
= INVALID_LZMA_CHECK_ID
;
173 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
),
176 // Should fail if Backward Size is invalid
177 flags
.backward_size
-= 1;
178 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
),
180 flags
.backward_size
+= 2;
181 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
),
183 flags
.backward_size
= LZMA_BACKWARD_SIZE_MAX
+ 4;
184 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
),
190 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
192 stream_header_decode_helper(lzma_check check
)
194 lzma_stream_flags flags
= {
199 uint8_t header
[LZMA_STREAM_HEADER_SIZE
];
201 assert_lzma_ret(lzma_stream_header_encode(&flags
, header
), LZMA_OK
);
203 lzma_stream_flags dest_flags
;
204 assert_lzma_ret(lzma_stream_header_decode(&dest_flags
, header
),
207 // Version should be 0
208 assert_uint_eq(dest_flags
.version
, 0);
210 // Backward Size should be LZMA_VLI_UNKNOWN
211 assert_uint_eq(dest_flags
.backward_size
, LZMA_VLI_UNKNOWN
);
213 // Check ID must equal the argument given to this function.
214 assert_uint_eq(dest_flags
.check
, check
);
220 test_lzma_stream_header_decode(void)
222 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
223 assert_skip("Encoder or decoder support disabled");
225 for (lzma_check i
= 0; i
< LZMA_CHECK_ID_MAX
; i
++)
226 stream_header_decode_helper(i
);
228 lzma_stream_flags flags
= {
230 .check
= LZMA_CHECK_CRC32
233 uint8_t header
[LZMA_STREAM_HEADER_SIZE
];
234 lzma_stream_flags dest
;
236 // First encode known flags to header buffer
237 assert_lzma_ret(lzma_stream_header_encode(&flags
, header
), LZMA_OK
);
239 // Should fail if magic bytes do not match
241 assert_lzma_ret(lzma_stream_header_decode(&dest
, header
),
245 // Should fail if a reserved bit is set
246 uint8_t *stream_flags
= header
+ sizeof(xz_header_magic
);
249 // Need to adjust CRC32 after making a change since the CRC32
250 // is verified before decoding the Stream Flags field.
251 uint8_t *crc32_ptr
= header
+ sizeof(xz_header_magic
)
252 + XZ_STREAM_FLAGS_SIZE
;
253 const uint32_t crc_orig
= read32le(crc32_ptr
);
254 uint32_t new_crc32
= lzma_crc32(
255 stream_flags
, XZ_STREAM_FLAGS_SIZE
, 0);
256 write32le(crc32_ptr
, new_crc32
);
257 assert_lzma_ret(lzma_stream_header_decode(&dest
, header
),
260 write32le(crc32_ptr
, crc_orig
);
262 // Should fail if upper bits of check ID are set
263 stream_flags
[1] |= 0xF0;
264 new_crc32
= lzma_crc32(stream_flags
, XZ_STREAM_FLAGS_SIZE
, 0);
265 write32le(crc32_ptr
, new_crc32
);
266 assert_lzma_ret(lzma_stream_header_decode(&dest
, header
),
268 stream_flags
[1] = flags
.check
;
269 write32le(crc32_ptr
, crc_orig
);
271 // Should fail if CRC32 does not match.
272 // First, alter a byte in the Stream Flags.
274 assert_lzma_ret(lzma_stream_header_decode(&dest
, header
),
278 // Next, change the CRC32.
280 assert_lzma_ret(lzma_stream_header_decode(&dest
, header
),
286 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
288 stream_footer_decode_helper(lzma_check check
)
290 lzma_stream_flags flags
= {
292 .backward_size
= LZMA_BACKWARD_SIZE_MIN
,
296 uint8_t footer
[LZMA_STREAM_HEADER_SIZE
];
297 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
), LZMA_OK
);
299 lzma_stream_flags dest_flags
;
300 assert_lzma_ret(lzma_stream_footer_decode(&dest_flags
, footer
),
303 // Version should be 0.
304 assert_uint_eq(dest_flags
.version
, 0);
306 // Backward Size should equal the value from the flags.
307 assert_uint_eq(dest_flags
.backward_size
, flags
.backward_size
);
309 // Check ID must equal argument given to this function.
310 assert_uint_eq(dest_flags
.check
, check
);
316 test_lzma_stream_footer_decode(void)
318 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
319 assert_skip("Encoder or decoder support disabled");
321 for (lzma_check i
= 0; i
< LZMA_CHECK_ID_MAX
; i
++)
322 stream_footer_decode_helper(i
);
324 lzma_stream_flags flags
= {
326 .check
= LZMA_CHECK_CRC32
,
327 .backward_size
= LZMA_BACKWARD_SIZE_MIN
330 uint8_t footer
[LZMA_STREAM_HEADER_SIZE
];
331 lzma_stream_flags dest
;
333 // First encode known flags to the footer buffer
334 assert_lzma_ret(lzma_stream_footer_encode(&flags
, footer
), LZMA_OK
);
336 // Should fail if magic bytes do not match
337 footer
[LZMA_STREAM_HEADER_SIZE
- 1] ^= 1;
338 assert_lzma_ret(lzma_stream_footer_decode(&dest
, footer
),
340 footer
[LZMA_STREAM_HEADER_SIZE
- 1] ^= 1;
342 // Should fail if a reserved bit is set.
343 // In the Stream Footer, the Stream Flags follow the CRC32 (4 bytes)
344 // and the Backward Size (4 bytes)
345 uint8_t *stream_flags
= footer
+ sizeof(uint32_t) * 2;
348 // Need to adjust the CRC32 so it will not fail that check instead
349 uint8_t *crc32_ptr
= footer
;
350 const uint32_t crc_orig
= read32le(crc32_ptr
);
351 uint8_t *backward_size
= footer
+ sizeof(uint32_t);
352 uint32_t new_crc32
= lzma_crc32(backward_size
, sizeof(uint32_t) +
353 XZ_STREAM_FLAGS_SIZE
, 0);
354 write32le(crc32_ptr
, new_crc32
);
355 assert_lzma_ret(lzma_stream_footer_decode(&dest
, footer
),
358 write32le(crc32_ptr
, crc_orig
);
360 // Should fail if upper bits of check ID are set
361 stream_flags
[1] |= 0xF0;
362 new_crc32
= lzma_crc32(backward_size
, sizeof(uint32_t) +
363 XZ_STREAM_FLAGS_SIZE
, 0);
364 write32le(crc32_ptr
, new_crc32
);
365 assert_lzma_ret(lzma_stream_footer_decode(&dest
, footer
),
367 stream_flags
[1] = flags
.check
;
368 write32le(crc32_ptr
, crc_orig
);
370 // Should fail if CRC32 does not match.
371 // First, alter a byte in the Stream Flags.
373 assert_lzma_ret(lzma_stream_footer_decode(&dest
, footer
),
377 // Next, change the CRC32
379 assert_lzma_ret(lzma_stream_footer_decode(&dest
, footer
),
386 test_lzma_stream_flags_compare(void)
388 lzma_stream_flags first
= {
390 .backward_size
= LZMA_BACKWARD_SIZE_MIN
,
391 .check
= LZMA_CHECK_CRC32
,
394 lzma_stream_flags second
= first
;
396 // First test should pass
397 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
), LZMA_OK
);
399 // Altering either version should cause an error
401 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
404 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
407 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
411 // Check types must be under the maximum
412 first
.check
= INVALID_LZMA_CHECK_ID
;
413 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
415 second
.check
= INVALID_LZMA_CHECK_ID
;
416 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
418 first
.check
= LZMA_CHECK_CRC32
;
419 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
421 second
.check
= LZMA_CHECK_CRC32
;
423 // Check types must be equal
424 for (lzma_check i
= 0; i
< LZMA_CHECK_ID_MAX
; i
++) {
426 if (i
== second
.check
)
427 assert_lzma_ret(lzma_stream_flags_compare(&first
,
430 assert_lzma_ret(lzma_stream_flags_compare(&first
,
431 &second
), LZMA_DATA_ERROR
);
433 first
.check
= LZMA_CHECK_CRC32
;
435 // Backward Size comparison is skipped if either are LZMA_VLI_UNKNOWN
436 first
.backward_size
= LZMA_VLI_UNKNOWN
;
437 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
), LZMA_OK
);
438 second
.backward_size
= LZMA_VLI_MAX
+ 1;
439 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
), LZMA_OK
);
440 second
.backward_size
= LZMA_BACKWARD_SIZE_MIN
;
442 // Backward Sizes need to be valid
443 first
.backward_size
= LZMA_VLI_MAX
+ 4;
444 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
446 second
.backward_size
= LZMA_VLI_MAX
+ 4;
447 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
449 first
.backward_size
= LZMA_BACKWARD_SIZE_MIN
;
450 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
452 second
.backward_size
= LZMA_BACKWARD_SIZE_MIN
;
454 // Backward Sizes must be equal
455 second
.backward_size
= first
.backward_size
+ 4;
456 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
459 // Should fail if Backward Sizes are > LZMA_BACKWARD_SIZE_MAX
460 // even though they are equal
461 first
.backward_size
= LZMA_BACKWARD_SIZE_MAX
+ 1;
462 second
.backward_size
= LZMA_BACKWARD_SIZE_MAX
+ 1;
463 assert_lzma_ret(lzma_stream_flags_compare(&first
, &second
),
469 main(int argc
, char **argv
)
471 tuktest_start(argc
, argv
);
472 tuktest_run(test_lzma_stream_header_encode
);
473 tuktest_run(test_lzma_stream_footer_encode
);
474 tuktest_run(test_lzma_stream_header_decode
);
475 tuktest_run(test_lzma_stream_footer_decode
);
476 tuktest_run(test_lzma_stream_flags_compare
);
477 return tuktest_end();